diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e3a2ee1..cac4962 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,12 +11,11 @@ jobs: with: fetch-depth: 0 - name: Docker Layer Caching - uses: jpribyl/action-docker-layer-caching@v0.1.1 + uses: ScribeMD/docker-cache@0.5.0 continue-on-error: true + id: cache with: - key: savemii-docker-cache-{hash} - restore-keys: | - savemii-docker-cache- + key: savemii-docker-cache-${{ hashFiles('DockerFile')}} - name: Build artifacts run: | docker build . --file Dockerfile --tag builder @@ -25,11 +24,11 @@ jobs: uses: actions/upload-artifact@v4 with: name: SaveMiiModWUTPort-Aroma - path: SaveMiiModWUTPort-Aroma.zip + path: build/Aroma/* if-no-files-found: warn - name: Upload HBL version uses: actions/upload-artifact@v4 with: name: SaveMiiModWUTPort-HBL - path: SaveMiiModWUTPort-HBL.zip + path: build/HBL/* if-no-files-found: warn diff --git a/Makefile b/Makefile index a263acb..560134d 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ CONTENT := ICON := meta/wuhb/icon.png TV_SPLASH := meta/wuhb/tv-splash.png DRC_SPLASH := meta/wuhb/drc-splash.png -ROMFS := languages +ROMFS := romfs #------------------------------------------------------------------------------- # options for code generation @@ -156,13 +156,16 @@ clean: #------------------------------------------------------------------------------- release: $(BUILD) - @mkdir -p SaveMiiModWUTPort - @cp savemii.rpx SaveMiiModWUTPort - @cp meta/hbl/icon.png SaveMiiModWUTPort - @cp meta/hbl/meta.xml SaveMiiModWUTPort - @zip -9 -r SaveMiiModWUTPort-HBL.zip SaveMiiModWUTPort - @zip -9 SaveMiiModWUTPort-Aroma.zip savemii.wuhb - @rm -rf SaveMiiModWUTPort + @mkdir -p build/Aroma/wiiu/apps/SaveMiiModWUTPort + @mkdir -p build/HBL/wiiu/apps/SaveMiiModWUTPort + @rm -rf build/Aroma/wiiu/apps/SaveMiiModWUTPort/* + @rm -rf build/HBL/wiiu/apps/SaveMiiModWUTPort/* + @cp savemii.rpx build/HBL/wiiu/apps/SaveMiiModWUTPort + @cp meta/hbl/icon.png build/HBL/wiiu/apps/SaveMiiModWUTPort + @cp meta/hbl/meta.xml build/HBL/wiiu/apps/SaveMiiModWUTPort + @cp savemii.wuhb build/Aroma/wiiu/apps/SaveMiiModWUTPort + @zip -9 -r SaveMiiModWUTPort-HBL.zip build/HBL + @zip -9 -r SaveMiiModWUTPort-Aroma.zip build/Aroma #------------------------------------------------------------------------------- else .PHONY: all diff --git a/README.md b/README.md index b17d921..fea5e6a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,109 @@ For sorting Titles press R to change sorting method and press L to change betwee Use it at your own risk and please report any issues that may occur. +## Quick Notes + +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. + +### Wii U Title Management / vWii Title Management + +Allows you to backup/restore/wipe individual titles. + +1. First select the title you want to manage. + 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. + 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. +2. Select the task you want to do: + 1. Backup: Copy savedata from USB/NAND to SD + 2. Restore: Copy savedata from SD to USB/NAND + 3. Wipe: Delete savedata from USB/NAND + 4. Export / Import to Loadiine: Legacy options to manage Loadiine savedata + 5. Copy to other Device: If savedata for a title is present in USB and NAND, copy it from one storage to the other + +#### Backup +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. +2. For Wii U titles, select which data to save: + 1. All users: Recommended option. Will backup all game data. + 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. +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. + +*Wii U titles savedata layout:* +``` +sd:/wiiu/backups/ + xxxxxxxxyyyyyyyy/ # Title Id + 0/ + saveMiiMeta.json + 80000001/ # one folder for each profile + ... # savedata + 80000002/ + ... + ... + common/ + ... + 1/ # one folder for each slot + ... +``` +For vWii titles, savedata is directly under the slot folder. + +#### Restore +1. Select a slot to get the data from. By default, data from the "root" backupSet (the one where the manual backups are stored) is used. But you can also use slots from batch backupSets, by pressing "X" button in this menu and selecting the backupSet you want to use. BackupSets can be tagged by pressing "+" button in the BackupSet List Menu, or from the BackupSet Management in Main menu. + 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. +2. For Wii U titles, select witch data to restore: + 1. `From: All users / To: Same user than Source` + 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. + 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. + 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` + 3. Press "A" to initiate the restore. + +#### Wipe +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. + +#### Copy to other device +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. + +### Batch Backup + +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. +BackupSets can be tagged by pressing "+" button in the BackupSet List menu or by entering in the menu Backupset Management from the Main menu. + +``` +sd:/wiiu/backups/batch/ + ${timestamp}/ + saveMiiMeta.json + xxxxxxxxyyyyyyyy/ # one folder for each title + 0/ # slot containing USB or NAND savedata for the title + saveMiiMeta.json + 80000001/ + ... + 80000002/ + ... + ... one folder for each profile + common/ + ... + 1/ # slot containing NAND savedata for titles simultaneously installed in USB and NAND + ... + xxxxxxxxxyyyyyyyy/ + 0/ + ... +``` + +### Batch Restore + +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, +1. Select wether you want to restore Wii U titles or vWii titles +2. Select the backupSet you want to restore from +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. +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. +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. +6. Once the restore is completed, a summary screen will show the number of sucess/failed/skipped titles. +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. + +### Backupset management +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"). + + +---- + + Reasons to use this over original mod: - Faster copy speeds diff --git a/include/ApplicationState.h b/include/ApplicationState.h index 73140a8..af93602 100644 --- a/include/ApplicationState.h +++ b/include/ApplicationState.h @@ -21,6 +21,11 @@ class ApplicationState { SUBSTATE_RETURN, }; + enum eSubstateCalled { + NONE + }; + virtual void render() = 0; virtual eSubState update(Input *input) = 0; + }; \ No newline at end of file diff --git a/include/BackupSetList.h b/include/BackupSetList.h index 0e5beaa..5bfb2f3 100644 --- a/include/BackupSetList.h +++ b/include/BackupSetList.h @@ -3,37 +3,127 @@ #include #include #include +#include + +class BSMetadataValues { + friend class BSMetadata; + friend class BackupSetList; + public: + + template + class attr { + public: + std::set range; + std::set::iterator iterator; + }; + attr> year; + attr> month; + attr> serialId; + attr> tag; + + template + static void Right (T & metadataAttrValues); + + template + static void Left (T & metadataAttrValues); + + void resetFilter(); + +}; + +class BSMetadata { + public: + friend class BackupSetItem; + friend class BackupSetList; + BSMetadata(std::string year = "*", std::string month = "*", + std::string serialId = "*", std::string tag = "*") : + year(year),month(month),serialId(serialId),tag(tag) {}; + BSMetadata(BSMetadataValues & bsMetadataValues) : + year(*(bsMetadataValues.year.iterator)),month(*(bsMetadataValues.month.iterator)), + serialId(*(bsMetadataValues.serialId.iterator)),tag(*(bsMetadataValues.tag.iterator)) {}; + private: + std::string year; + std::string month; + std::string serialId; + std::string tag; +}; + +class BackupSetItem { + public: + friend class BackupSetList; + BackupSetItem(std::string entryPath,BSMetadata bsItemMetadata) : + entryPath(entryPath),bsItemMetadata(bsItemMetadata) {}; + private: + std::string entryPath; + BSMetadata bsItemMetadata; +}; + +struct BackupSetItemView { + std::string entryPath; + std::string serialId; + std::string tag; +}; + class BackupSetList { public: friend class BackupSetListState; - + friend class BackupSetListFilterState; BackupSetList() {}; BackupSetList(const char *backupSetListRoot); static std::unique_ptr currentBackupSetList; void sort(bool sortAscending = false); + static bool getSortAscending() { return sortAscending;}; std::string at(int i); - void add(std::string backupSet); + std::string getSerialIdAt(int i); + std::string getStretchedSerialIdAt(int i); + std::string getTagAt(int i); + void setTagBSVAt(int i, const std::string & tag); + void setTagBSAt(int i, const std::string & tag); + void add(std::string entryPath,std::string serialId,std::string tag); + + int getSizeView() { return this->entriesView;}; + int getSize() { return this->entries;}; + + void filter(); + void filter(BSMetadata filterDef); + void resetTagRange(); + BSMetadataValues *getBSMetadataValues() {return &bsMetadataValues; }; static const std::string ROOT_BS; - static std::string getBackupSetSubPath() { return backupSetSubPath; } - static std::string getBackupSetEntry() { return backupSetEntry; } + static std::string getBackupSetSubPath() { return backupSetSubPath; }; + static std::string getBackupSetPath() { return currentBackupSetList->backupSetListRoot+backupSetSubPath; }; + static std::string getBackupSetEntry() { return backupSetEntry; }; + static std::string getBackupSetSubPath(int i); static void setBackupSetEntry(int i); static void setBackupSetSubPath(); static void initBackupSetList(); static void setBackupSetSubPathToRoot() { backupSetSubPath = "/"; } + static void setBackupSetToRoot() { setBackupSetEntry(0); setBackupSetSubPathToRoot();} static void saveBackupSetSubPath() { savedBackupSetSubPath = backupSetSubPath; } static void restoreBackupSetSubPath() { backupSetSubPath = savedBackupSetSubPath; } - + static bool getIsInitializationRequired() { return isInitializationRequired; } + static void setIsInitializationRequired(bool isInitializationRequired_) { + BackupSetList::isInitializationRequired = isInitializationRequired_; + } + private: static bool sortAscending; - std::vector backupSets; + std::vector backupSetsView; + std::vector backupSets; + std::vector serialIds; + std::vector tags; + std::vector v2b; + BSMetadataValues bsMetadataValues; + int entriesView; int entries; std::string backupSetListRoot; static std::string backupSetSubPath; static std::string backupSetEntry; static std::string savedBackupSetSubPath; + inline static bool isInitializationRequired = false; }; + diff --git a/include/Metadata.h b/include/Metadata.h index 20ed622..73fecaf 100644 --- a/include/Metadata.h +++ b/include/Metadata.h @@ -1,30 +1,71 @@ #pragma once +#include #include -#include +//#include #include +#include class Metadata { public: Metadata(uint32_t high, uint32_t low, uint8_t s) : highID(high), lowID(low), slot(s), - path (getDynamicBackupPath(highID, lowID, slot).append("/savemiiMeta.json")) { - } + path (getDynamicBackupPath(highID, lowID, slot).append("/savemiiMeta.json")), + Date({}), + storage({}), + serialId(this->unknownSerialId), + tag({}) { } Metadata(uint32_t high, uint32_t low, uint8_t s, std::string datetime) : highID(high), lowID(low), slot(s), - path (getBatchBackupPath(highID, lowID, slot, datetime).append("/savemiiMeta.json")) { - } + path (getBatchBackupPath(highID, lowID, slot, datetime).append("/savemiiMeta.json")), + Date({}), + storage({}), + serialId(this->unknownSerialId), + tag({}) { } +// guess date from batchBackupRoot, to infer a savemiiMeta.json for <1.6.4 batchBackups + Metadata(const std::string & path) : storage({}), + serialId(this->unknownSerialId), + tag({}) { + Date = path.substr(path.length()-17,17); + if (Date.substr(0,2) != "20") + Date=""; + this->path = path + ("/savemiiMeta.json"); + } + + Metadata(const std::string & datetime, const std::string & storage, const std::string & serialId,const std::string & tag ) : + Date(datetime), + storage(storage), + serialId(serialId), + tag(tag) { + path = getBatchBackupPathRoot(datetime)+"/savemiiMeta.json"; + } + + + bool read(); + bool write(); + std::string simpleFormat(); std::string get(); bool set(const std::string &date,bool isUSB); - static std::string serialId; + static std::string thisConsoleSerialId; + static std::string unknownSerialId; + std::string getDate() { return Date;}; + std::string getTag() { return tag;}; + void setTag(std::string tag_) { this->tag = tag_;}; + std::string getSerialId() { return serialId;}; private: uint32_t highID; uint32_t lowID; uint8_t slot; std::string path; -}; \ No newline at end of file + + std::string Date; + std::string storage; + std::string serialId; + std::string tag; +}; + diff --git a/include/menu/BRTitleSelectState.h b/include/menu/BRTitleSelectState.h new file mode 100644 index 0000000..39d363b --- /dev/null +++ b/include/menu/BRTitleSelectState.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class BRTitleSelectState : public ApplicationState { +public: + BRTitleSelectState(int sduser, int wiiuuser, bool common, bool wipeBeforeRestore, bool fullBackup,Title *titles, int titlesCount, bool isWiiUBatchRestore); + + enum eState { + STATE_BATCH_RESTORE_TITLE_SELECT, + STATE_DO_SUBSTATE, + }; + + void render() override; + ApplicationState::eSubState update(Input *input) override; + +private: + std::unique_ptr subState{}; + eState state = STATE_BATCH_RESTORE_TITLE_SELECT; + + + int sduser; + int wiiuuser; + bool common; + bool wipeBeforeRestore; + bool fullBackup; + Title *titles; + int titlesCount; + bool isWiiUBatchRestore; + + + std::vector sortNames = {LanguageUtils::gettext("None"), + LanguageUtils::gettext("Name"), + LanguageUtils::gettext("Storage"), + LanguageUtils::gettext("Strg+Nm")}; + + int titleSort = 1; + int scroll = 0; + int cursorPos = 0; + bool sortAscending = true; + int targ = 0; + + bool noTitles = false; + + std::vector c2t; + int candidatesCount; + + void updateC2t(); + + std::vector titleStateAfterBR = { + " ", + " > Aborted", + " > OK", + " > WR", + " > KO" + }; +}; \ No newline at end of file diff --git a/include/menu/BackupSetListFilterState.h b/include/menu/BackupSetListFilterState.h new file mode 100644 index 0000000..77375ae --- /dev/null +++ b/include/menu/BackupSetListFilterState.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include +#include + + + + +class BackupSetListFilterState : public ApplicationState { +public: + BackupSetListFilterState(std::unique_ptr & backupSetList) : + backupSetList(backupSetList) {}; + enum eState { + STATE_BACKUPSET_FILTER, + STATE_DO_SUBSTATE, + }; + + void render() override; + ApplicationState::eSubState update(Input *input) override; + +private: + std::unique_ptr subState{}; + eState state = STATE_BACKUPSET_FILTER; + + std::unique_ptr & backupSetList; + int entrycount = 4; + int cursorPos = 0; +}; \ No newline at end of file diff --git a/include/menu/BackupSetListState.h b/include/menu/BackupSetListState.h index 8aea7cc..cd3f582 100644 --- a/include/menu/BackupSetListState.h +++ b/include/menu/BackupSetListState.h @@ -2,19 +2,25 @@ #include #include +#include #include - - - class BackupSetListState : public ApplicationState { public: BackupSetListState(); + BackupSetListState(Title *titles, int titlesCount, bool isWiiUBatchRestore); + static void resetCursorPosition(); + static void resetCursorAndScroll(); enum eState { STATE_BACKUPSET_MENU, STATE_DO_SUBSTATE, }; + enum eSubstateCalled { + NONE, + STATE_BACKUPSET_FILTER, + STATE_KEYBOARD + }; void render() override; ApplicationState::eSubState update(Input *input) override; @@ -22,8 +28,21 @@ class BackupSetListState : public ApplicationState { private: std::unique_ptr subState{}; eState state = STATE_BACKUPSET_MENU; - + eSubstateCalled substateCalled = NONE; + bool finalScreen; + bool sortAscending; + + static int cursorPos; + static int scroll; std::string backupSetListRoot; + + std::string tag; + std::string newTag; + + Title *titles; + int titlesCount; + + bool isWiiUBatchRestore; }; \ No newline at end of file diff --git a/include/menu/BatchRestoreOptions.h b/include/menu/BatchRestoreOptions.h new file mode 100644 index 0000000..29bfe8b --- /dev/null +++ b/include/menu/BatchRestoreOptions.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +class BatchRestoreOptions : public ApplicationState { +public: + BatchRestoreOptions(Title *titles, int titlesCount, bool isWiiUBatchRestore); + + enum eState { + STATE_BATCH_RESTORE_OPTIONS_MENU, + STATE_DO_SUBSTATE, + }; + + void render() override; + ApplicationState::eSubState update(Input *input) override; + std::string tag; + +private: + std::unique_ptr subState{}; + eState state = STATE_BATCH_RESTORE_OPTIONS_MENU; + + int8_t wiiuuser = -1; + int8_t sduser = -1; + bool common = false; + + bool wipeBeforeRestore = true; + bool fullBackup = true; + std::set> batchSDUsers; + + Title *titles; + int titlesCount = 0; + + int cursorPos; + int minCursorPos; + + bool isWiiUBatchRestore; + + +}; \ No newline at end of file diff --git a/include/menu/BatchRestoreState.h b/include/menu/BatchRestoreState.h new file mode 100644 index 0000000..b27bfd6 --- /dev/null +++ b/include/menu/BatchRestoreState.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +class BatchRestoreState : public ApplicationState { +public: + BatchRestoreState(Title *wiiutitles, Title *wiititles, int wiiuTitlesCount, int vWiiTitlesCount) : wiiutitles(wiiutitles), + wiititles(wiititles), + wiiuTitlesCount(wiiuTitlesCount), + vWiiTitlesCount(vWiiTitlesCount) {} + enum eState { + STATE_BATCH_RESTORE_MENU, + STATE_DO_SUBSTATE, + }; + + void render() override; + ApplicationState::eSubState update(Input *input) override; + std::string tag; + +private: + std::unique_ptr subState{}; + eState state = STATE_BATCH_RESTORE_MENU; + + Title *wiiutitles; + Title *wiititles; + + int wiiuTitlesCount; + int vWiiTitlesCount; +}; \ No newline at end of file diff --git a/include/menu/KeyboardState.h b/include/menu/KeyboardState.h new file mode 100644 index 0000000..9c6be7a --- /dev/null +++ b/include/menu/KeyboardState.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +class KeyboardState : public ApplicationState { +public: + KeyboardState(std::string & input) : input(input) { + this->keyboard = std::make_unique(); + this->cursorPosX = this->keyboard->column; + this->cursorPosY = this->keyboard->row; + } + enum eState { + STATE_KEYBOARD, + STATE_DO_SUBSTATE, + }; + + void render() override; + ApplicationState::eSubState update(Input *input) override; + +private: + std::unique_ptr subState{}; + eState state = STATE_KEYBOARD; + + std::unique_ptr keyboard; + + int entrycount = 4; + int cursorPosX = 0; + int cursorPosY = 0; + std::string & input; +}; \ No newline at end of file diff --git a/include/menu/MainMenuState.h b/include/menu/MainMenuState.h index 8c1e273..84e24ca 100644 --- a/include/menu/MainMenuState.h +++ b/include/menu/MainMenuState.h @@ -16,6 +16,11 @@ class MainMenuState : public ApplicationState { STATE_DO_SUBSTATE, }; + enum eSubstateCalled { + NONE, + STATE_BACKUPSET_MENU, + }; + void render() override; ApplicationState::eSubState update(Input *input) override; @@ -23,6 +28,8 @@ class MainMenuState : public ApplicationState { std::unique_ptr subState{}; eState state = STATE_MAIN_MENU; + eSubstateCalled substateCalled = NONE; + Title *wiiutitles; Title *wiititles; diff --git a/include/menu/TitleOptionsState.h b/include/menu/TitleOptionsState.h index 29b3edc..07bcd93 100644 --- a/include/menu/TitleOptionsState.h +++ b/include/menu/TitleOptionsState.h @@ -22,6 +22,12 @@ class TitleOptionsState : public ApplicationState { STATE_DO_SUBSTATE, }; + enum eSubstateCalled { + NONE, + STATE_BACKUPSET_MENU, + STATE_KEYBOARD + }; + void render() override; ApplicationState::eSubState update(Input *input) override; @@ -29,6 +35,8 @@ class TitleOptionsState : public ApplicationState { std::unique_ptr subState{}; eState state = STATE_TITLE_OPTIONS; + eSubstateCalled substateCalled = NONE; + Title title; Task task; @@ -47,4 +55,7 @@ class TitleOptionsState : public ApplicationState { uint8_t slot = 0; int cursorPos = 0; int entrycount; + + std::string tag; + std::string newTag; }; \ No newline at end of file diff --git a/include/menu/WiiUTitleListState.h b/include/menu/WiiUTitleListState.h index 3dec7fe..e3b847d 100644 --- a/include/menu/WiiUTitleListState.h +++ b/include/menu/WiiUTitleListState.h @@ -33,7 +33,8 @@ class WiiUTitleListState : public ApplicationState { LanguageUtils::gettext("Storage+Name")}; int titleSort = 1; - int scroll = 0; + static int scroll; + static int cursorPos; bool sortAscending = true; int targ = 0; diff --git a/include/menu/vWiiTitleListState.h b/include/menu/vWiiTitleListState.h index f5767ed..140b69a 100644 --- a/include/menu/vWiiTitleListState.h +++ b/include/menu/vWiiTitleListState.h @@ -33,7 +33,8 @@ class vWiiTitleListState : public ApplicationState { LanguageUtils::gettext("Storage+Name")}; int titleSort = 1; - int scroll = 0; + static int scroll; + static int cursorPos; bool sortAscending = true; int targ = 0; diff --git a/include/savemng.h b/include/savemng.h index ffb1392..9353d20 100644 --- a/include/savemng.h +++ b/include/savemng.h @@ -23,6 +23,24 @@ #define M_OFF 1 #define Y_OFF 1 +enum eBatchRestoreState { + NOT_TRIED = 0, + ABORTED = 1, + OK = 2, + WR = 3, + KO = 4 +}; + +struct backupInfo { + bool hasBatchBackup; + bool candidateToBeRestored; + bool selected; + bool hasUserSavedata; + bool hasCommonSavedata; + eBatchRestoreState batchRestoreState; + int lastErrCode; +}; + struct Title { uint32_t highID; uint32_t lowID; @@ -33,10 +51,13 @@ struct Title { bool saveInit; bool isTitleOnUSB; bool isTitleDupe; + bool is_Wii; + bool noFwImg; uint16_t dupeID; uint8_t *iconBuf; uint64_t accountSaveSize; uint32_t groupID; + backupInfo currentBackup; }; struct Saves { @@ -58,7 +79,8 @@ enum Style { ST_CONFIRM_CANCEL = 2, ST_MULTILINE = 16, ST_WARNING = 32, - ST_ERROR = 64 + ST_ERROR = 64, + ST_WIPE = 128 }; template @@ -108,8 +130,10 @@ std::string getUSB(); void consolePrintPos(int x, int y, const char *format, ...) __attribute__((hot)); bool promptConfirm(Style st, const std::string &question); void promptError(const char *message, ...); +void promptMessage(Color bgcolor,const char *message, ...); std::string getDynamicBackupPath(uint32_t highID, uint32_t lowID, uint8_t slot); std::string getBatchBackupPath(uint32_t highID, uint32_t lowID, uint8_t slot, std::string datetime); +std::string getBatchBackupPathRoot(std::string datetime); void getAccountsWiiU(); void getAccountsSD(Title *title, uint8_t slot); bool hasAccountSave(Title *title, bool inSD, bool iine, uint32_t user, uint8_t slot, int version); @@ -117,16 +141,19 @@ bool getLoadiineGameSaveDir(char *out, const char *productCode, const char *long bool getLoadiineSaveVersionList(int *out, const char *gamePath); bool isSlotEmpty(uint32_t highID, uint32_t lowID, uint8_t slot); bool isSlotEmpty(uint32_t highID, uint32_t lowID, uint8_t slot, const std::string &batchDatetime); +bool folderEmpty(const char *fPath); bool hasCommonSave(Title *title, bool inSD, bool iine, uint8_t slot, int version); void copySavedata(Title *title, Title *titled, int8_t wiiuuser, int8_t wiiuuser_d, bool common) __attribute__((hot)); std::string getNowDateForFolder() __attribute__((hot)); std::string getNowDate() __attribute__((hot)); void writeMetadata(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB) __attribute__((hot)); void writeMetadata(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB,const std::string &batchDatetime) __attribute__((hot)); -void backupAllSave(Title *titles, int count, const std::string &batchDatetime) __attribute__((hot)); -void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common) __attribute__((hot)); -void restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, bool common) __attribute__((hot)); -void wipeSavedata(Title *title, int8_t wiiuuser, bool common) __attribute__((hot)); +void writeMetadataWithTag(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB,const std::string &tag) __attribute__((hot)); +void writeBackupAllMetadata(const std::string & Date, const std::string & tag); +void backupAllSave(Title *titles, int count, const std::string &batchDatetime, bool onlySelectedTitles = false) __attribute__((hot)); +void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common, const std::string &tag = "") __attribute__((hot)); +int restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, bool common, bool interactive = true) __attribute__((hot)); +int wipeSavedata(Title *title, int8_t wiiuuser, bool common, bool interactive = true) __attribute__((hot)); void importFromLoadiine(Title *title, bool common, int version); void exportToLoadiine(Title *title, bool common, int version); int checkEntry(const char *fPath); @@ -134,7 +161,10 @@ int32_t loadFile(const char *fPath, uint8_t **buf) __attribute__((hot)); int32_t loadTitleIcon(Title *title) __attribute__((hot)); void consolePrintPosMultiline(int x, int y, const char *format, ...) __attribute__((hot)); void consolePrintPosAligned(int y, uint16_t offset, uint8_t align, const char *format, ...) __attribute__((hot)); +void kConsolePrintPos(int x, int y, int x_offset, const char *format, ...) __attribute__((hot)); uint8_t getSDaccn(); uint8_t getWiiUaccn(); Account *getWiiUacc(); -Account *getSDacc(); \ No newline at end of file +Account *getSDacc(); +void deleteSlot(Title *title, uint8_t slot); +bool wipeBackupSet(const std::string &subPath); \ No newline at end of file diff --git a/include/utils/Colors.h b/include/utils/Colors.h index 8279c86..8c10251 100644 --- a/include/utils/Colors.h +++ b/include/utils/Colors.h @@ -4,6 +4,26 @@ #define COLOR_BLACK Color(0, 0, 0, 255) #define COLOR_BACKGROUND Color(0x00006F00) #define COLOR_TEXT COLOR_WHITE -#define COLOR_LIST_HIGH Color(0x40D050FF) +#define COLOR_TEXT_AT_CURSOR Color(0xBBBBEEFF) +#define COLOR_LIST_HIGH Color(0x40D070FF) +#define COLOR_LIST_HIGH_AT_CURSOR Color(0x40D0BBFF) #define COLOR_LIST Color(0x00FF00FF) -#define COLOR_INFO Color(0x88CC88FF) \ No newline at end of file +#define COLOR_LIST_AT_CURSOR Color(0x00FFAAFF) +#define COLOR_LIST_SKIPPED Color(0x888800FF) +#define COLOR_LIST_SKIPPED_AT_CURSOR Color(0x8888AAFF) +#define COLOR_LIST_SELECTED_NOSAVE Color(0xFFFF00FF) +#define COLOR_LIST_SELECTED_NOSAVE_AT_CURSOR Color(0xCCCC60FF) +#define COLOR_LIST_NOSAVE Color(0xFFFF00FF) +#define COLOR_LIST_NOSAVE_AT_CURSOR Color(0xFFFFBBFF) +#define COLOR_LIST_DANGER Color(0xFF0000FF) +#define COLOR_LIST_DANGER_AT_CURSOR Color(0xFF0060FF) +#define COLOR_LIST_RESTORE_SUCCESS Color(0xFFFFFFFF) +#define COLOR_LIST_RESTORE_SUCCESS_AT_CURSOR Color(0xBBBBEEFF) +#define COLOR_INFO Color(0x88CC88FF) +#define COLOR_INFO_AT_CURSOR Color(0x88CCCCFF) +#define COLOR_CURRENT_BS Color(0xFFBB33FF) +#define COLOR_CURRENT_BS_AT_CURSOR Color(0xFFFF99FF) +#define COLOR_KEY Color(0xFF3333FF) +#define COLOR_KEY_S Color(0xFF666600) +#define COLOR_KEY_C Color(0xFF0000FF) +#define COLOR_BG_SUCCESS Color(0x00DD55FF) diff --git a/include/utils/DrawUtils.h b/include/utils/DrawUtils.h index 725eb76..ab7f198 100644 --- a/include/utils/DrawUtils.h +++ b/include/utils/DrawUtils.h @@ -51,13 +51,16 @@ class DrawUtils { static void drawRect(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, uint8_t b, uint8_t a); - static bool initFont(); + static bool initFont(OSSharedDataType fontType); + //static bool initKFont(); - static bool setFont(OSSharedDataType fontType); + static bool setFont(); + //static bool setKFont(); static void deinitFont(); static void setFontColor(Color col); + static void setFontColorByCursor(Color col, Color colAtCursor,int cursorPos, int line); static void print(uint32_t x, uint32_t y, const char *string, bool alignRight = false); @@ -79,6 +82,7 @@ class DrawUtils { static uint32_t deinitScreen(); + static void drawKey(int x,int y,int x_off,Color color); diff --git a/include/utils/InputUtils.h b/include/utils/InputUtils.h index 1a5f50b..7df9af4 100644 --- a/include/utils/InputUtils.h +++ b/include/utils/InputUtils.h @@ -8,12 +8,15 @@ typedef enum Button { PAD_BUTTON_A, PAD_BUTTON_B, PAD_BUTTON_X, + PAD_BUTTON_Y, PAD_BUTTON_UP, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT, PAD_BUTTON_L, PAD_BUTTON_R, + PAD_BUTTON_PLUS, + PAD_BUTTON_MINUS, PAD_BUTTON_ANY } Button; diff --git a/include/utils/KeyboardUtils.h b/include/utils/KeyboardUtils.h new file mode 100644 index 0000000..27d1eea --- /dev/null +++ b/include/utils/KeyboardUtils.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include + +class Keyboard { + public: + friend class KeyboardState; + void render(); + int kbLeft(); + int kbRight(); + int kbUp(); + int kbDown(); + void kbKeyPressed(); + void shiftPressed(); + void delPressed(); + void setCurrentKey(); + std::string getKey(int row_,int column_); + std::string getCurrentKey(); + int getKeyboardRowSize(int row_); + std::string ucs4ToUtf8(const std::u32string& in); + std::u32string utf8ToUcs4(const std::string& in); + std::string input; + Keyboard() : row(2),column(5) { + /* + keysNormal = {"1234567890-= ", + "qwertyuiop[]|", + "asdfghjkl;' ", + "zxcvbnm ,./ "}; + keysShift = { "!@#$%^&*()_+~", + "QWERTYUIOP{}\\", + "ASDFGHJKL:\" ", + "ZXCVBNM <> "}; + */ + std::vector keyboardNormal = { + "KB_N_0", + "KB_N_1", + "KB_N_2", + "KB_N_3" + }; + std::vector keyboardShift = { + "KB_S_0", + "KB_S_1", + "KB_S_2", + "KB_S_3" + + }; + for (unsigned int i=0;i keysNormal; + std::vector keysShift; + std::vector currentKeyboard; + std::u32string currentKey; + int row; + int column; + +}; \ No newline at end of file diff --git a/include/version.h b/include/version.h index 18c9efd..c7c646a 100644 --- a/include/version.h +++ b/include/version.h @@ -2,4 +2,4 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 6 -#define VERSION_MICRO 3 +#define VERSION_MICRO 4 diff --git a/languages/SChinese.json b/languages/SChinese.json deleted file mode 100644 index 3eff18b..0000000 --- a/languages/SChinese.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "Disclaimer:": "注意:", - "There is always the potential for a brick.": "请尽量小心使用此程序,它可能会导致砖机。", - "Everything you do with this software is your own responsibility": "你所使用此程序做的一切都是你自己的责任", - "Out of memory.": "内存不足", - "Loaded %i Wii U titles.": "已加载 %i 个Wii U软件。", - "%s%s (No banner.bin)": "%s%s(没有banner.bin数据)", - "Loaded %i Wii titles.": "已加载 %i 个Wii软件", - "None": "无", - "Name": "名称", - "Storage": "存储设备", - "Storage+Name": "存储设备+名称", - "initFS failed. Please make sure your MochaPayload is up-to-date": "初始化文件系统失败。\n确保你的MochaPayload是最新", - " Wii U Save Management (%u Title%s)": " Wii U保存数据管理(%u 软件)", - " vWii Save Management (%u Title%s)": " vWii保存数据管理(%u 软件)", - " Batch Backup": " 批量备份", - "\uE002: Options \ue000: Select Mode": "\uE002:选项 \ue000:选择模式", - " Backup All (%u Title%s)": " 备份所有保存数据(%u 软件)", - " Backup Wii U (%u Title%s)": " 备份Wii U软件的保存数据(%u 软件)", - " Backup vWii (%u Title%s)": " 备份vWii软件的保存数据(%u 软件)", - "\ue000: Backup \ue001: Back": "\ue000:备份 \ue001:返回", - "%s Sort: %s \ue084": "%s 排序方式: %s \ue084", - " [Not Init]": "[未初始化]", - "\ue000: Select Game \ue001: Back": "\ue000:选择游戏 \ue001:返回", - " Backup savedata": " 备份保存数据", - " Restore savedata": " 还原保存数据", - " Wipe savedata": " 清除保存数据", - " Import from loadiine": " 从loadiine导入", - " Export to loadiine": " 导出到loadiine", - " Copy Savedata to Title in %s": "将Savedata复制到 %s 软件中", - "\ue000: Select Task \ue001: Back": "\ue000:选择进程 \ue001:返回", - "Destination:": "目标位置:", - "Select %s:": "选择%s:", - "version": "Ver", - "Delete from:": "删除中:", - "slot": "保存数据槽位", - "Empty": "无数据", - "Used": "已使用", - "Select SD user to copy from:": "选择从SD复制数据的用户:", - "all users": "所有用户", - "Has Save": "该用户有保存数据", - "Select Wii U user to delete from:": "选择从SD删除数据的用户:", - "Select Wii U user%s:": "选择Wii U的用户:", - " to copy from": " ", - " to copy to": " ", - "Date: %s": "保存日期:%s", - "Include 'common' save?": "连带'common'保存数据一起吗?", - "yes": "是", - "no ": "不", - "No 'common' save found.": "没有发现'common'保存数据", - "\ue000: Restore \ue001: Back": "\ue000:还原 \ue001:返回", - "\ue000: Wipe \ue001: Back": "\ue000:清除 \ue001:返回", - "\ue000: Import \ue001: Back": "\ue000:导入 \ue001:返回", - "\ue000: Export \ue001: Back": "\ue000:导出 \ue001:返回", - "\ue000: Copy \ue001: Back": "\ue000:复制 \ue001:返回", - "Press \ue044 to exit.": "按下 \ue044 退出程序。", - "No Wii U titles found.": "未发现Wii U软件", - "No vWii saves found.": "未发现vWii保存数据", - "CBHC save. Could be dangerous to modify. Continue?": "这是CBHC的保存数据。修改它可能会导致一些问题,继续吗?", - "Are you REALLY sure?": "你真的要这样做吗?", - "vWii saves are in the vWii section. Continue?": "vWii的保存数据在vWii的存储中。继续?", - "Recommended to run Game at least one time. Continue?": "请至少也得运行一次软件。继续?", - "No save to Backup.": "没有可备份的保存数据", - "No save to Wipe.": "没有可删除的保存数据", - "No save to Export.": "没有可导出的保存数据", - "No save to Copy.": "没有可以复制的保存数据", - "Copying file: %s": "正在复制文件 %s", - "From: %s": "从 %s", - "To: %s": "到 %s", - "\ue000 Yes - \ue001 No": "\ue000 是 - \ue001 否", - "\ue000 Confirm - \ue001 Cancel": "\ue000 确认 - \ue001 取消", - "Filesize: %d bytes": "文件大小:%d 字节", - "Deleting folder %s": "正在删除 %s 文件夹", - "From: \n%s": "从:\n%s", - "Failed to delete folder %s: %s": "删除文件夹失败 %s: %s", - "Deleting file %s": "正在删除文件 %s", - "Failed to delete file %s: %s": "删除文件失败 %s: %s", - "Loadiine game folder not found.": "Loadiine游戏文件夹没有发现。", - "Failed to open Loadiine game save directory.": "Loadiine游戏文件夹无法打开。", - "Are you sure?": "你确定吗?", - "Backup current savedata first to next empty slot?": "是否在下一个槽位中备份一个现在可用的保存数据?", - "Backup done. Now copying Savedata.": "备份完成。现在复制Savedata。", - "Common save not found.": "没有发现common保存数据", - "Copy failed.": "复制保存数据失败。", - "Backup failed.": "备份保存数据失败。", - "Backup found on this slot. Overwrite it?": "在这个槽位有保存数据,覆盖吗?", - "No save found for this user.": "这个用户没有保存数据。", - "Backup failed. DO NOT restore from this slot.": "备份保存数据失败。此槽位的保存数据不要还原!", - "No backup found on selected slot.": "没有在选择的槽位发现保存数据。", - "Restore failed.": "还原保存数据失败。", - "Hm, are you REALLY sure?": "嘶,你真的真的要这样做?", - "Backup current savedata first?": "要不要先备份现在的保存数据?", - "Failed to delete common folder: %s": "删除common文件夹失败: %s", - "Failed to delete savefile.": "删除保存数据失败。", - "Failed to delete user folder: %s": "删除user文件夹失败: %s", - "Failed to import savedata from loadiine.": "导入loadiine保存数据失败。", - "Failed to export savedata to loadiine.": "导出保存数据到loadiine失败。" -} diff --git a/languages/english.json b/languages/english.json deleted file mode 100644 index 030d62e..0000000 --- a/languages/english.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "Disclaimer:": "Disclaimer:", - "There is always the potential for a brick.": "There is always the potential for a brick.", - "Everything you do with this software is your own responsibility": "Everything you do with this software is your own responsibility", - "Out of memory.": "Out of memory.", - "Loaded %i Wii U titles.": "Loaded %i Wii U titles.", - "%s%s (No banner.bin)": "%s%s (No banner.bin)", - "Loaded %i Wii titles.": "Loaded %i Wii titles.", - "None": "None", - "Name": "Name", - "Storage": "Storage", - "Storage+Name": "Storage+Name", - "initFS failed. Please make sure your MochaPayload is up-to-date": "initFS failed. Please make sure your MochaPayload is up-to-date", - " Wii U Save Management (%u Title%s)": " Wii U Save Management (%u Title%s)", - " vWii Save Management (%u Title%s)": " vWii Save Management (%u Title%s)", - " Batch Backup": " Batch Backup", - "\uE002: Options \ue000: Select Mode": "\uE002: Options \ue000: Select Mode", - " Backup All (%u Title%s)": " Backup All (%u Title%s)", - " Backup Wii U (%u Title%s)": " Backup Wii U (%u Title%s)", - " Backup vWii (%u Title%s)": " Backup vWii (%u Title%s)", - "\ue000: Backup \ue001: Back": "\ue000: Backup \ue001: Back", - "%s Sort: %s \ue084": "%s Sort: %s \ue084", - " [Not Init]": " [Not Init]", - "\ue000: Select Game \ue001: Back": "\ue000: Select Game \ue001: Back", - " Backup savedata": " Backup savedata", - " Restore savedata": " Restore savedata", - " Wipe savedata": " Wipe savedata", - " Import from loadiine": " Import from loadiine", - " Export to loadiine": " Export to loadiine", - " Copy Savedata to Title in %s": " Copy Savedata to Title in %s", - "\ue000: Select Task \ue001: Back": "\ue000: Select Task \ue001: Back", - "Destination:": "Destination:", - "Select %s:": "Select %s:", - "version": "version", - "Delete from:": "Delete from:", - "slot": "slot", - "Empty": "Empty", - "Used": "Used", - "Select SD user to copy from:": "Select SD user to copy from:", - "all users": "all users", - "Has Save": "Has Save", - "Select Wii U user to delete from:": "Select Wii U user to delete from:", - "Select Wii U user%s:": "Select Wii U user%s:", - " to copy from": " to copy from", - " to copy to": " to copy to", - "Date: %s": "Date: %s", - "Include 'common' save?": "Include 'common' save?", - "yes": "yes", - "no ": "no ", - "No 'common' save found.": "No 'common' save found.", - "\ue000: Wipe \ue001: Back": "\ue000: Wipe \ue001: Back", - "\ue000: Import \ue001: Back": "\ue000: Import \ue001: Back", - "\ue000: Export \ue001: Back": "\ue000: Export \ue001: Back", - "\ue000: Copy \ue001: Back": "\ue000: Copy \ue001: Back", - "Press \ue044 to exit.": "Press \ue044 to exit.", - "No Wii U titles found.": "No Wii U titles found.", - "No vWii saves found.": "No vWii saves found.", - "CBHC save. Could be dangerous to modify. Continue?": "CBHC save. Could be dangerous to modify. Continue?", - "Are you REALLY sure?": "Are you REALLY sure?", - "vWii saves are in the vWii section. Continue?": "vWii saves are in the vWii section. Continue?", - "Recommended to run Game at least one time. Continue?": "Recommended to run Game at least one time. Continue?", - "No save to Backup.": "No save to Backup.", - "No save to Wipe.": "No save to Wipe.", - "No save to Export.": "No save to Export.", - "No save to Copy.": "No save to Copy.", - "Copying file: %s": "Copying file: %s", - "From: %s": "From: %s", - "To: %s": "To: %s", - "\ue000 Yes - \ue001 No": "\ue000 Yes - \ue001 No", - "\ue000 Confirm - \ue001 Cancel": "\ue000 Confirm - \ue001 Cancel", - "Filesize: %d bytes": "Filesize: %d bytes", - "Deleting folder %s": "Deleting folder %s", - "From: \n%s": "From: \n%s", - "Failed to delete folder %s: %s": "Failed to delete folder %s: %s", - "Deleting file %s": "Deleting file %s", - "Failed to delete file %s: %s": "Failed to delete file %s: %s", - "Loadiine game folder not found.": "Loadiine game folder not found.", - "Failed to open Loadiine game save directory.": "Failed to open Loadiine game save directory.", - "Are you sure?": "Are you sure?", - "Backup current savedata first to next empty slot?": "Backup current savedata first to next empty slot?", - "Backup done. Now copying Savedata.": "Backup done. Now copying Savedata.", - "Common save not found.": "Common save not found.", - "Copy failed.": "Copy failed.", - "Backup failed.": "Backup failed.", - "Backup found on this slot. Overwrite it?": "Backup found on this slot. Overwrite it?", - "No save found for this user.": "No save found for this user.", - "Backup failed. DO NOT restore from this slot.": "Backup failed. DO NOT restore from this slot.", - "No backup found on selected slot.": "No backup found on selected slot.", - "Restore failed.": "Restore failed.", - "Hm, are you REALLY sure?": "Hm, are you REALLY sure?", - "Backup current savedata first?": "Backup current savedata first?", - "Failed to delete common folder: %s": "Failed to delete common folder: %s", - "Failed to delete savefile.": "Failed to delete savefile.", - "Failed to delete user folder: %s": "Failed to delete user folder: %s", - "Failed to import savedata from loadiine.": "Failed to import savedata from loadiine.", - "Failed to export savedata to loadiine.": "Failed to export savedata to loadiine.", - "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", - "\ue000: Select BackupSet \ue001: Back": "\ue000: Select BackupSet \ue001: Back", - "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", - "WiiU USB Savedata >> slot 0": "WiiU USB Savedata >> slot 0", - "WiiU NAND Savedata >> slot 1": "WiiU NAND Savedata >> slot 1", - "vWii Savedata >> slot 0": "vWii Savedata >> slot 0", - "BackupSet: %s": "BackupSet: %s", - ", from ": ", from ", - "Common save not restored.": "Common save not restored.", - "\ue001: Back": "\ue001: Back" -} \ No newline at end of file diff --git a/languages/russian.json b/languages/russian.json deleted file mode 100644 index 5a5771b..0000000 --- a/languages/russian.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "Disclaimer:": "Отказ от ответственности:", - "There is always the potential for a brick.": "Всегда есть шанс брикнуть консоль.", - "Everything you do with this software is your own responsibility": "Всё что вы делаете в программе вы делаете на свой страх и риск", - "Out of memory.": "Недостаточно памяти.", - "Loaded %i Wii U titles.": "Загружено %i тайтлов Wii U.", - "%s%s (No banner.bin)": "%s%s (No banner.bin)", - "Loaded %i Wii titles.": "Загружено %i тайтлов Wii.", - "None": "Ничего не найдено", - "Name": "Имя", - "Storage": "Хранилище", - "Storage+Name": "Хранилище+Имя", - "initFS failed. Please make sure your MochaPayload is up-to-date": "Ошибка инициализации файловой системы (initFS). Убедитесь, что пейлоад Mocha свежей версии", - " Wii U Save Management (%u Title%s)": " Управление сохранениями Wii U (%u Имя%s)", - " vWii Save Management (%u Title%s)": " Управление сохранениями vWii (%u Имя%s)", - " Batch Backup": " Пакетный бекап", - "\uE002: Options \ue000: Select Mode": "\uE002: Опции \ue000: Выбор режима", - " Backup All (%u Title%s)": " Сделать бекап для всех (%u Имя%s)", - " Backup Wii U (%u Title%s)": " Бекап только для Wii U (%u Имя%s)", - " Backup vWii (%u Title%s)": " Бекап только для vWii (%u Имя%s)", - ": Backup : Back": ": Бекап: Назад", - "%s Sort: %s ": "%s Сортировать: %s ", - " [Not Init]": " [Not Init]", - ": Select Game : Back": ": Выбрать игру : Назад", - " Backup savedata": " Бекап сохранений", - " Restore savedata": " Восстановить сохранения", - " Wipe savedata": " Стереть сохранения", - " Import from loadiine": " Импортировать из loadiine", - " Export to loadiine": " Экспорт в loadiine", - " Copy Savedata to Title in %s": " Скопировать сохранения в Имя в %s", - ": Select Task : Back": ": Выбрать задачу : Назад", - "Destination:": "Назначение:", - "Select %s:": "Выбрать %s:", - "version": "версия", - "Delete from:": "Удалить из:", - "slot": "слот", - "Empty": "Пусто", - "Used": "Использовано", - "Select SD user to copy from:": "Выбрать пользователя для копирования:", - "all users": "все пользователи", - "Has Save": "Есть сохранение", - "Select Wii U user to delete from:": "Выберите пользователя Wii U для удаления из:", - "Select Wii U user%s:": "Выберите пользователя Wii U%s:", - " to copy from": " копировать из", - " to copy to": " копировать в", - "Date: %s": "Дата: %s", - "Include 'common' save?": "Включить 'common' сохранения?", - "yes": "да", - "no ": "нет ", - "No 'common' save found.": "Не найдено ни одного 'common' сохранения.", - ": Restore : Back": ": Восстановить : Назад", - ": Wipe : Back": ": Стереть : Назад", - ": Import : Back": ": Импорт : Назад", - ": Export : Back": ": Экспорт : Назад", - ": Copy : Back": ": Копирование : Назад", - "Press  to exit.": "Нажмите  для выхода.", - "No Wii U titles found.": "Не найдено тайтлов Wii U.", - "No vWii saves found.": "Сохранения vWii не найдены.", - "CBHC save. Could be dangerous to modify. Continue?": "Сохранение CBHC. Может быть опасным для изменения. Продолжить?", - "Are you REALLY sure?": "Ты ТОЧНО уверен?", - "vWii saves are in the vWii section. Continue?": "сохранение vWii находится в разделе vWii. Продолжить?", - "Recommended to run Game at least one time. Continue?": "Рекомендуется запустить игру по крайней мере один раз. Продолжить?", - "No save to Backup.": "Нет сохранений для бекапа.", - "No save to Wipe.": "Нет сохранений для стирания.", - "No save to Export.": "Нет сохранений для экспорта.", - "No save to Copy.": "Нет сохранений для копирования.", - "Copying file: %s": "Копируемый файл: %s", - "From: %s": "Из %s", - "To: %s": "В %s", - " Yes -  No": " Да -  Нет", - " Confirm -  Cancel": " Подтвердить -  Отменить", - "Filesize: %d bytes": "Размер: %d байт", - "Deleting folder %s": "Удаление папки %s", - "From: \n%s": "Из %s", - "Failed to delete folder %s: %s": "Не удалось удалить папку %s: %s", - "Deleting file %s": "Удаление файла %s", - "Failed to delete file %s: %s": "Не удалось удалить файл %s: %s", - "Loadiine game folder not found.": "Папка Loadiine не найдена.", - "Failed to open Loadiine game save directory.": "Не удалось открыть каталог сохранения Loadiine.", - "Are you sure?": "Вы уверены?", - "Backup current savedata first to next empty slot?": "Сохранить текущее сохранение в следующий пустой слот?", - "Backup done. Now copying Savedata.": "Бекап завершен. Копирование сохранений.", - "Common save not found.": "'Common' сохранение не найдено.", - "Copy failed.": "Копирование не удалось.", - "Backup failed.": "Бекап не удался.", - "Backup found on this slot. Overwrite it?": "Слот не пустой. Перезаписать?", - "No save found for this user.": "Не найдено сохранений для этого пользователя.", - "Backup failed. DO NOT restore from this slot.": "Бекап не удался. НЕ восстанавливайте из этого слота.", - "No backup found on selected slot.": "В выбранном слоте бекап не найден.", - "Restore failed.": "Ошибка восстановления.", - "Hm, are you REALLY sure?": "Вы ТОЧНО уверены?", - "Backup current savedata first?": "Сделать сперва бекап сохранения?", - "Failed to delete common folder: %s": "Не удалось удалить папку: %s", - "Failed to delete savefile.": "Не удалось удалить сохранение.", - "Failed to delete user folder: %s": "Не удалось удалить пользовательскую папку: %s", - "Failed to import savedata from loadiine.": "Не удалось импортировать сохранения из loadiine.", - "Failed to export savedata to loadiine.": "Не удалось экспортировать сохранения из loadiine." -} \ No newline at end of file diff --git a/languages/spanish.json b/languages/spanish.json deleted file mode 100644 index f40efde..0000000 --- a/languages/spanish.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "Disclaimer:": "Atención:", - "There is always the potential for a brick.": "Siempre existe la posibilidad de un brick.", - "Everything you do with this software is your own responsibility": "Todo lo que hagas con este software es tu responsabilidad", - "Out of memory.": "Sin memoria.", - "Loaded %i Wii U titles.": "Cargados %i títulos de Wii U.", - "%s%s (No banner.bin)": "%s%s (Sin banner.bin)", - "Loaded %i Wii titles.": "Cargados %i títulos de Wii.", - "None": "Ninguno", - "Name": "Nombre", - "Storage": "Dispositivo", - "Storage+Name": "Dispositivo+Nombre", - "initFS failed. Please make sure your MochaPayload is up-to-date": "Error en initFS. Verifica que MochaPayload está actualizado", - " Wii U Save Management (%u Title%s)": " Gestión de saves de Wii U (%u Título%s)", - " vWii Save Management (%u Title%s)": " Gestión de saves de vWii (%u Título%s)", - " Batch Backup": " Copia de seguridad en masa", - "\uE002: Options \ue000: Select Mode": "\uE002: Opciones \ue000: Seleccionar", - " Backup All (%u Title%s)": " Copiar Todo (%u Título%s)", - " Backup Wii U (%u Title%s)": " Copiar Wii U (%u Título%s)", - " Backup vWii (%u Title%s)": " Copiar vWii (%u Título%s)", - "\ue000: Backup \ue001: Back": "\ue000: Copiar \ue001: Atrás", - "%s Sort: %s \ue084": "%s Orden: %s \ue084", - " [Not Init]": " [No Inic.]", - "\ue000: Select Game \ue001: Back": "\ue000: Seleccionar Juego \ue001: Atrás", - " Backup savedata": " Copiar savedata", - " Restore savedata": " Restaurar savedata", - " Wipe savedata": " Borrar savedata", - " Import from loadiine": " Importar desde loadiine", - " Export to loadiine": " Exportar a loadiine", - " Copy Savedata to Title in %s": " Copiar Savedata al Título en %s", - "\ue000: Select Task \ue001: Back": "\ue000: Seleccionar Tarea \ue001: Atrás", - "Destination:": "Destino:", - "Select %s:": "Seleccionar %s:", - "version": "versión", - "Delete from:": "Borrar de:", - "slot": "slot", - "Empty": "Libre", - "Used": "Usado", - "Select SD user to copy from:": "Selecciona el usuario de SD del que copiar:", - "all users": "todos los usuarios", - "Has Save": "Existe Save", - "Select Wii U user to delete from:": "Selecciona el usuario de Wii U del que copiar:", - "Select Wii U user%s:": "Selecciona el usuario de Wii U%s:", - " to copy from": " del que copiar", - " to copy to": " al que copiar", - "Date: %s": "Fecha: %s", - "Include 'common' save?": "¿Incluír 'common' save?", - "yes": "sí", - "no ": "no ", - "No 'common' save found.": "No se ha encontrado 'common' save.", - "\ue000: Restore \ue001: Back": "\ue000: Restaurar \ue001: Atrás", - "\ue000: Wipe \ue001: Back": "\ue000: Eliminar \ue001: Atrás", - "\ue000: Import \ue001: Back": "\ue000: Importar \ue001: Atrás", - "\ue000: Export \ue001: Back": "\ue000: Exportar \ue001: Atrás", - "\ue000: Copy \ue001: Back": "\ue000: Copiar \ue001: Atrás", - "Press \ue044 to exit.": "Presiona \ue044 para salir.", - "No Wii U titles found.": "No se han encontrado títulos de Wii U.", - "No vWii saves found.": "No se han encontrado saves de vWii.", - "CBHC save. Could be dangerous to modify. Continue?": "Save de CBHC. Puede ser peligroso modificarlo. ¿Continuar?", - "Are you REALLY sure?": "¿Estás COMPLETAMENTE seguro?", - "vWii saves are in the vWii section. Continue?": "Los saves de vWii están en su propia sección. ¿Continuar?", - "Recommended to run Game at least one time. Continue?": "Se recomienda correr el juego al menos una vez. ¿Continuar?", - "No save to Backup.": "No hay save que copiar.", - "No save to Wipe.": "No hay save que eliminar.", - "No save to Export.": "No hay save que exportar.", - "No save to Copy.": "No hay save que copiar.", - "Copying file: %s": "Copiando archivo: %s", - "From: %s": "Desde: %s", - "To: %s": "A: %s", - "\ue000 Yes - \ue001 No": "\ue000 Sí - \ue001 No", - "\ue000 Confirm - \ue001 Cancel": "\ue000 Confirmar - \ue001 Cancelar", - "Filesize: %d bytes": "Tamaño: %d bytes", - "Deleting folder %s": "Eliminando carpeta %s", - "From: \n%s": "Desde:\n%s", - "Failed to delete folder %s: %s": "Error al eliminar la carpeta %s: %s", - "Deleting file %s": "Eliminando archivo %s", - "Failed to delete file %s: %s": "Error al eliminar el archivo %s: %s", - "Loadiine game folder not found.": "Carpeta del juego de Loadiine no encontrada.", - "Failed to open Loadiine game save directory.": "Error al abrir la carpeta de saves del juego de Loadiine.", - "Are you sure?": "¿Estás seguro?", - "Backup current savedata first to next empty slot?": "¿Copiar el save actual al siguiente slot libre?", - "Backup done. Now copying Savedata.": "Copia hecha. Haciendo copia del save.", - "Common save not found.": "No se ha podido encontrar el common save.", - "Copy failed.": "Error al realizar la copia.", - "Backup failed.": "Error al realizar la copia.", - "Backup found on this slot. Overwrite it?": "Se ha encontrado una copia en este slot. ¿Sobreescribirlo?", - "No save found for this user.": "No se han encontrado saves de este usuario.", - "Backup failed. DO NOT restore from this slot.": "Error al realizar la copia. NO restaures este slot.", - "No backup found on selected slot.": "No se ha encontrado una copia en el slot seleccionado.", - "Restore failed.": "Error al restaurar.", - "Hm, are you REALLY sure?": "¿Hm, estás COMPLETAMENTE seguro?", - "Backup current savedata first?": "¿Hacer copia antes del save?", - "Failed to delete common folder: %s": "Error al eliminar la carpeta common: %s", - "Failed to delete savefile.": "Error al eliminar el save.", - "Failed to delete user folder: %s": "Error al eliminar la carpeta user: %s", - "Failed to import savedata from loadiine.": "Error al importar el save de loadiine.", - "Failed to export savedata to loadiine.": "Error al exportar el save a loadiine.", - "\ue083 Sort: %s \ue084": "\ue083 Ordenar: %s \ue084", - "\ue000: Select BackupSet \ue001: Back": "\ue000: Seleccionar BackupSet \ue001: Atrás", - "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Cambiar BackupSet \ue000: Restaurar \ue001: Atrás", - "WiiU USB Savedata >> slot 0": "WiiU USB Savedata >> slot 0", - "WiiU NAND Savedata >> slot 1": "WiiU NAND Savedata >> slot 1", - "vWii Savedata >> slot 0": "vWii Savedata >> slot 0", - "BackupSet: %s": "BackupSet: %s", - ", from ": ", de ", - "Common save not restored.": "No se ha podido restaurar el common save", - "\ue001: Back": "\ue001: Atrás" -} \ No newline at end of file diff --git a/meta/hbl/meta.xml b/meta/hbl/meta.xml index cdb49fa..9decf02 100644 --- a/meta/hbl/meta.xml +++ b/meta/hbl/meta.xml @@ -2,7 +2,7 @@ SaveMii WUT DaThinkingChair,w3irDv - 1.6.3 + 1.6.4 202408240000 WiiU/vWii Save Manager WiiU/vWii Save Manager diff --git a/romfs/languages/SChinese.json b/romfs/languages/SChinese.json new file mode 100644 index 0000000..cb7c53b --- /dev/null +++ b/romfs/languages/SChinese.json @@ -0,0 +1,192 @@ +{ + "Disclaimer:": "注意:", + "There is always the potential for a brick.": "请尽量小心使用此程序,它可能会导致砖机。", + "Everything you do with this software is your own responsibility": "你所使用此程序做的一切都是你自己的责任", + "Out of memory.": "内存不足", + "Loaded %i Wii U titles.": "已加载 %i 个Wii U软件。", + "%s%s (No banner.bin)": "%s%s(没有banner.bin数据)", + "Loaded %i Wii titles.": "已加载 %i 个Wii软件", + "None": "无", + "Name": "名称", + "Storage": "存储设备", + "Storage+Name": "存储设备+名称", + "initFS failed. Please make sure your MochaPayload is up-to-date": "初始化文件系统失败。\n确保你的MochaPayload是最新", + " Wii U Save Management (%u Title%s)": " Wii U保存数据管理(%u 软件)", + " vWii Save Management (%u Title%s)": " vWii保存数据管理(%u 软件)", + " Batch Backup": " 批量备份", + "\uE002: Options \ue000: Select Mode": "\uE002:选项 \ue000:选择模式", + " Backup All (%u Title%s)": " 备份所有保存数据(%u 软件)", + " Backup Wii U (%u Title%s)": " 备份Wii U软件的保存数据(%u 软件)", + " Backup vWii (%u Title%s)": " 备份vWii软件的保存数据(%u 软件)", + "\ue000: Backup \ue001: Back": "\ue000:备份 \ue001:返回", + "%s Sort: %s \ue084": "%s 排序方式: %s \ue084", + " [Not Init]": "[未初始化]", + "\ue000: Select Game \ue001: Back": "\ue000:选择游戏 \ue001:返回", + " Backup savedata": " 备份保存数据", + " Restore savedata": " 还原保存数据", + " Wipe savedata": " 清除保存数据", + " Import from loadiine": " 从loadiine导入", + " Export to loadiine": " 导出到loadiine", + " Copy Savedata to Title in %s": "将Savedata复制到 %s 软件中", + "\ue000: Select Task \ue001: Back": "\ue000:选择进程 \ue001:返回", + "Destination:": "目标位置:", + "Select %s:": "选择%s:", + "version": "Ver", + "Delete from:": "删除中:", + "slot": "保存数据槽位", + "Empty": "无数据", + "Used": "已使用", + "Select SD user to copy from:": "选择从SD复制数据的用户:", + "all users": "所有用户", + "Has Save": "该用户有保存数据", + "Select Wii U user to delete from:": "选择从SD删除数据的用户:", + "Select Wii U user%s:": "选择Wii U的用户%s:", + " to copy from": " ", + " to copy to": " ", + "Date: %s": "保存日期:%s", + "Include 'common' save?": "连带'common'保存数据一起吗?", + "yes": "是", + "no ": "不", + "No 'common' save found.": "没有发现'common'保存数据", + "\ue000: Wipe \ue001: Back": "\ue000:清除 \ue001:返回", + "\ue000: Import \ue001: Back": "\ue000:导入 \ue001:返回", + "\ue000: Export \ue001: Back": "\ue000:导出 \ue001:返回", + "\ue000: Copy \ue001: Back": "\ue000:复制 \ue001:返回", + "Press \ue044 to exit.": "按下 \ue044 退出程序。", + "No Wii U titles found.": "未发现Wii U软件", + "No vWii saves found.": "未发现vWii保存数据", + "CBHC save. Could be dangerous to modify. Continue?": "这是CBHC的保存数据。修改它可能会导致一些问题,继续吗?", + "Are you REALLY sure?": "你真的要这样做吗?", + "vWii saves are in the vWii section. Continue?": "vWii的保存数据在vWii的存储中。继续?", + "Recommended to run Game at least one time. Continue?": "请至少也得运行一次软件。继续?", + "No save to Backup.": "没有可备份的保存数据", + "No save to Wipe.": "没有可删除的保存数据", + "No save to Export.": "没有可导出的保存数据", + "No save to Copy.": "没有可以复制的保存数据", + "Copying file: %s": "正在复制文件 %s", + "From: %s": "从 %s", + "To: %s": "到 %s", + "\ue000 Yes - \ue001 No": "\ue000 是 - \ue001 否", + "\ue000 Confirm - \ue001 Cancel": "\ue000 确认 - \ue001 取消", + "Filesize: %d bytes": "文件大小:%d 字节", + "Deleting folder %s": "正在删除 %s 文件夹", + "From: \n%s": "从:\n%s", + "Failed to delete folder %s: %s": "删除文件夹失败 %s: %s", + "Deleting file %s": "正在删除文件 %s", + "Failed to delete file %s: %s": "删除文件失败 %s: %s", + "Loadiine game folder not found.": "Loadiine游戏文件夹没有发现。", + "Failed to open Loadiine game save directory.": "Loadiine游戏文件夹无法打开。", + "Are you sure?": "你确定吗?", + "Backup current savedata first to next empty slot?": "是否在下一个槽位中备份一个现在可用的保存数据?", + "Backup done. Now copying Savedata.": "备份完成。现在复制Savedata。", + "Common save not found.": "没有发现common保存数据", + "Copy failed.": "复制保存数据失败。", + "Backup failed.": "备份保存数据失败。", + "Backup found on this slot. Overwrite it?": "在这个槽位有保存数据,覆盖吗?", + "No save found for this user.": "这个用户没有保存数据。", + "Backup failed. DO NOT restore from this slot.": "备份保存数据失败。此槽位的保存数据不要还原!", + "No backup found on selected slot.": "没有在选择的槽位发现保存数据。", + "Restore failed.": "还原保存数据失败。", + "Hm, are you REALLY sure?": "嘶,你真的真的要这样做?", + "Backup current savedata first?": "要不要先备份现在的保存数据?", + "Failed to delete common folder: %s": "删除common文件夹失败: %s", + "Failed to delete savefile.": "删除保存数据失败。", + "Failed to delete user folder: %s": "删除user文件夹失败: %s", + "Failed to import savedata from loadiine.": "导入loadiine保存数据失败。", + "Failed to export savedata to loadiine.": "导出保存数据到loadiine失败。", + "\ue083 Sort: %s \ue084": "\ue083 排序: %s \ue084", + "\ue000: Select BackupSet \ue001: Back": "\ue000: 选择备份设置 \ue001: 备份", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: 更改备份设置 \ue000: 恢复 \ue001: 备份", + "WiiU USB Savedata >> slot 0": "WiiU USB 存档数据 >> slot 0", + "WiiU NAND Savedata >> slot 1": "WiiU NAND 存档数据 >> slot 1", + "vWii Savedata >> slot 0": "vWii 存档数据 >> slot 0", + "BackupSet: %s": "备份设置: %s", + ", from ": ", 来自 ", + "Common save not restored.": "普通存档未恢复。", + "\ue001: Back": "\ue001: 备份", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" +} \ No newline at end of file diff --git a/languages/TChinese.json b/romfs/languages/TChinese.json similarity index 50% rename from languages/TChinese.json rename to romfs/languages/TChinese.json index a9a56ef..4067a08 100644 --- a/languages/TChinese.json +++ b/romfs/languages/TChinese.json @@ -94,5 +94,94 @@ "Failed to delete savefile.": "無法刪除保存資料。", "Failed to delete user folder: %s": "無法刪除使用者資料夾: %s", "Failed to import savedata from loadiine.": "無法從loadiine導入保存數據。", - "Failed to export savedata to loadiine.": "無法導出保存數據到Loadiine。" + "Failed to export savedata to loadiine.": "無法導出保存數據到Loadiine。", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSet: %s": "BackupSet: %s", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue001: Back": "\ue001: Back", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } diff --git a/romfs/languages/english.json b/romfs/languages/english.json new file mode 100644 index 0000000..f4f2181 --- /dev/null +++ b/romfs/languages/english.json @@ -0,0 +1,221 @@ +{ + "Disclaimer:": "Disclaimer:", + "There is always the potential for a brick.": "There is always the potential for a brick.", + "Everything you do with this software is your own responsibility": "Everything you do with this software is your own responsibility", + "Out of memory.": "Out of memory.", + "Loaded %i Wii U titles.": "Loaded %i Wii U titles.", + "%s%s (No banner.bin)": "%s%s (No banner.bin)", + "Loaded %i Wii titles.": "Loaded %i Wii titles.", + "None": "None", + "Name": "Name", + "Storage": "Storage", + "Storage+Name": "Storage+Name", + "initFS failed. Please make sure your MochaPayload is up-to-date": "initFS failed. Please make sure your MochaPayload is up-to-date", + " Wii U Save Management (%u Title%s)": " Wii U Save Management (%u Title%s)", + " vWii Save Management (%u Title%s)": " vWii Save Management (%u Title%s)", + " Batch Backup": " Batch Backup", + "\uE002: Options \ue000: Select Mode": "\uE002: Options \ue000: Select Mode", + " Backup All (%u Title%s)": " Backup All (%u Title%s)", + " Backup Wii U (%u Title%s)": " Backup Wii U (%u Title%s)", + " Backup vWii (%u Title%s)": " Backup vWii (%u Title%s)", + "\ue000: Backup \ue001: Back": "\ue000: Backup \ue001: Back", + "%s Sort: %s \ue084": "%s Sort: %s \ue084", + " [Not Init]": " [Not Init]", + "\ue000: Select Game \ue001: Back": "\ue000: Select Game \ue001: Back", + " Backup savedata": " Backup savedata", + " Restore savedata": " Restore savedata", + " Wipe savedata": " Wipe savedata", + " Import from loadiine": " Import from loadiine", + " Export to loadiine": " Export to loadiine", + " Copy Savedata to Title in %s": " Copy Savedata to Title in %s", + "\ue000: Select Task \ue001: Back": "\ue000: Select Task \ue001: Back", + "Destination:": "Destination:", + "Select %s:": "Select %s:", + "version": "version", + "Delete from:": "Delete from:", + "slot": "slot", + "Empty": "Empty", + "Used": "Used", + "Select SD user to copy from:": "Select SD user to copy from:", + "all users": "all users", + "Has Save": "Has Save", + "Select Wii U user to delete from:": "Select Wii U user to delete from:", + "Select Wii U user%s:": "Select Wii U user%s:", + " to copy from": " to copy from", + " to copy to": " to copy to", + "Date: %s": "Date: %s", + "Include 'common' save?": "Include 'common' save?", + "yes": "yes", + "no ": "no ", + "No 'common' save found.": "No 'common' save found.", + "\ue000: Wipe \ue001: Back": "\ue000: Wipe \ue001: Back", + "\ue000: Import \ue001: Back": "\ue000: Import \ue001: Back", + "\ue000: Export \ue001: Back": "\ue000: Export \ue001: Back", + "\ue000: Copy \ue001: Back": "\ue000: Copy \ue001: Back", + "Press \ue044 to exit.": "\ue044 Exit", + "No Wii U titles found.": "No Wii U titles found.", + "No vWii saves found.": "No vWii saves found.", + "CBHC save. Could be dangerous to modify. Continue?": "CBHC save. Could be dangerous to modify. Continue?", + "Are you REALLY sure?": "Are you REALLY sure?", + "vWii saves are in the vWii section. Continue?": "vWii saves are in the vWii section. Continue?", + "Recommended to run Game at least one time. Continue?": "Recommended to run Game at least one time. Continue?", + "No save to Backup.": "No save to Backup.", + "No save to Wipe.": "No save to Wipe.", + "No save to Export.": "No save to Export.", + "No save to Copy.": "No save to Copy.", + "Copying file: %s": "Copying file: %s", + "From: %s": "From: %s", + "To: %s": "To: %s", + "\ue000 Yes - \ue001 No": "\ue000 Yes - \ue001 No", + "\ue000 Confirm - \ue001 Cancel": "\ue000 Confirm - \ue001 Cancel", + "Filesize: %d bytes": "Filesize: %d bytes", + "Deleting folder %s": "Deleting folder %s", + "From: \n%s": "From: \n%s", + "Failed to delete folder %s: %s": "Failed to delete folder %s: %s", + "Deleting file %s": "Deleting file %s", + "Failed to delete file %s: %s": "Failed to delete file %s: %s", + "Loadiine game folder not found.": "Loadiine game folder not found.", + "Failed to open Loadiine game save directory.": "Failed to open Loadiine game save directory.", + "Are you sure?": "Are you sure?", + "Backup current savedata first to next empty slot?": "Backup current savedata first to next empty slot?", + "Backup done. Now copying Savedata.": "Backup done. Now copying Savedata.", + "Common save not found.": "Common save not found.", + "Copy failed.": "Copy failed.", + "Backup failed.": "Backup failed.", + "Backup found on this slot. Overwrite it?": "Backup found on this slot. Overwrite it?", + "No save found for this user.": "No save found for this user.", + "Backup failed. DO NOT restore from this slot.": "Backup failed. DO NOT restore from this slot.", + "No backup found on selected slot.": "No backup found on selected slot.", + "Restore failed.": "Restore failed.", + "Hm, are you REALLY sure?": "Hm, are you REALLY sure?", + "Backup current savedata first?": "Backup current savedata first?", + "Failed to delete common folder: %s": "Failed to delete common folder: %s", + "Failed to delete savefile.": "Failed to delete savefile.", + "Failed to delete user folder: %s": "Failed to delete user folder: %s", + "Failed to import savedata from loadiine.": "Failed to import savedata from loadiine.", + "Failed to export savedata to loadiine.": "Failed to export savedata to loadiine.", + "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", + "\ue000: Select BackupSet \ue001: Back": "\ue000: Select BackupSet \ue001: Back", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", + "WiiU USB Savedata >> slot 0": "WiiU USB Savedata >> slot 0", + "WiiU NAND Savedata >> slot 1": "WiiU NAND Savedata >> slot 1", + "vWii Savedata >> slot 0": "vWii Savedata >> slot 0", + "BackupSet: %s": "BackupSet: %s", + ", from ": ", from ", + "Common save not restored.": "Common save not restored.", + "\ue001: Back": "\ue001: Back", + "Failed to delete slot %u.": "Failed to delete slot %u.", + "Error setting path. Aborting.": "Error setting path. Aborting.", + "Failed to delete backupSet %s.": "Failed to delete backupSet %s.", + "\ue000: Backup \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue046 Delete Slot \ue001: Back", + "\ue003 Confirm - \ue001 Cancel": "\ue003 Confirm - \ue001 Cancel", + "Wipe BackupSet - Are you sure?": "Wipe BackupSet - Are you sure?", + "Wipe BackupSet - Hm, are you REALLY sure?": "Wipe BackupSet - Hm, are you REALLY sure?", + "Initializing BackupSets metadata.": "Initializing BackupSets metadata.", + "Please wait. First write to SD may be slow.": "Initializing BackupSets metadata.", + "Filter BackupSets": "Filter BackupSets", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Console: %s": "Console: %s", + "Tag: %s": "Tag: %s", + "Month: %s": "Month: %s", + "Year: %s": "Year: %s", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "BackupSets": "BackupSets", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "\ue000: Select BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "Batch Backup": "Batch Backup", + "Backup": "Backup", + "Restore": "Restore", + "Wipe": "Wipe", + "Import Loadiine": "Import Loadiine", + "Export Loadiine": "Export Loadiine", + "Copy to Other Device": "Copy to Other Device", + "Tasks": "Tasks", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "%s \n Common save not found.": "%s \n Common save not found.", + "%s \n Failed to delete common folder:\n %s": "%s \n Failed to delete common folder:\n %s", + "%s \n Failed to delete savefile.": "%s \n Failed to delete savefile.", + "%s \n Failed to delete user folder:\n %s": "%s \n Failed to delete user folder:\n %s", + "%s\nCommon save not restored.": "%s\nCommon save not restored.", + "%s\nNo backup found on selected slot.": "%s\nNo backup found on selected slot.", + "%s\nNo save found for this user.": "%s\nNo save found for this user.", + "%s\nRestore failed.": "%s\nRestore failed.", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "English": "English", + "Folder does not exist.": "Folder does not exist.", + "German": "German", + "Getting Serial ID": "Getting Serial ID", + "Initializing ROMFS": "Initializing ROMFS", + "Initializing WPAD and KAPD": "Initializing WPAD and KAPD", + "Initializing loadWiiU Titles": "Initializing loadWiiU Titles", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Press \ue000 to continue": "Press \ue000 to continue", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" +} \ No newline at end of file diff --git a/languages/german.json b/romfs/languages/german.json similarity index 55% rename from languages/german.json rename to romfs/languages/german.json index c05b974..f3345cb 100644 --- a/languages/german.json +++ b/romfs/languages/german.json @@ -103,5 +103,90 @@ "BackupSet: %s": "BackupSet: %s", ", from ": ", aus ", "Common save not restored.": "'Gemeinsame' Sicherung nicht wiederhergestellt", - "\ue001: Back": "\ue001: Zurück" + "\ue001: Back": "\ue001: Zurück", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } diff --git a/languages/italian.json b/romfs/languages/italian.json similarity index 54% rename from languages/italian.json rename to romfs/languages/italian.json index 8cdd6a2..542a154 100644 --- a/languages/italian.json +++ b/romfs/languages/italian.json @@ -103,5 +103,90 @@ "BackupSet: %s": "BackupSet: %s", ", from ": ", da ", "Common save not restored.": "Salvataggio comune non ripristinato", - "\ue001: Back": "\ue001: Indietro" + "\ue001: Back": "\ue001: Indietro", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } \ No newline at end of file diff --git a/languages/japanese.json b/romfs/languages/japanese.json similarity index 55% rename from languages/japanese.json rename to romfs/languages/japanese.json index ffcf765..0956be6 100644 --- a/languages/japanese.json +++ b/romfs/languages/japanese.json @@ -94,5 +94,94 @@ "Failed to delete savefile.": "保存ファイルの削除に失敗しました。", "Failed to delete user folder: %s": "ユーザー フォルダの削除に失敗しました: %s", "Failed to import savedata from loadiine.": "loadiine からセーブデータをインポートできませんでした。", - "Failed to export savedata to loadiine.": "セーブデータを loadiine にエクスポートできませんでした。" + "Failed to export savedata to loadiine.": "セーブデータを loadiine にエクスポートできませんでした。", + "\ue001: Back": "\ue001: 戻る", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSet: %s": "BackupSet: %s", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } \ No newline at end of file diff --git a/languages/korean.json b/romfs/languages/korean.json similarity index 52% rename from languages/korean.json rename to romfs/languages/korean.json index db16479..bf1e796 100644 --- a/languages/korean.json +++ b/romfs/languages/korean.json @@ -94,5 +94,94 @@ "Failed to delete savefile.": "저장파일을 삭제하지 못했습니다.", "Failed to delete user folder: %s": "사용자 폴더를 삭제하지 못했습니다: %s", "Failed to import savedata from loadiine.": "loadiine에서 저장 데이터를 가져오지 못했습니다.", - "Failed to export savedata to loadiine.": "저장 데이터를 loadiine으로 내보내지 못했습니다." + "Failed to export savedata to loadiine.": "저장 데이터를 loadiine으로 내보내지 못했습니다.", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSet: %s": "BackupSet: %s", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Portuguese": "Portuguese", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue001: Back": "\ue001: Back", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } \ No newline at end of file diff --git a/languages/portuguese.json b/romfs/languages/portuguese.json similarity index 53% rename from languages/portuguese.json rename to romfs/languages/portuguese.json index 18c3603..45fd47f 100644 --- a/languages/portuguese.json +++ b/romfs/languages/portuguese.json @@ -104,5 +104,89 @@ "BackupSet: %s": "BackupSet: %s", ", from ": ", de ", "Common save not restored.": "Save 'Common' não restauradoi", - "\ue001: Back": "\ue001: Voltar" + "\ue001: Back": "\ue001: Voltar", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Export Loadiine": "Export Loadiine", + "German": "German", + "Import Loadiine": "Import Loadiine", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" } \ No newline at end of file diff --git a/romfs/languages/russian.json b/romfs/languages/russian.json new file mode 100644 index 0000000..ab06d66 --- /dev/null +++ b/romfs/languages/russian.json @@ -0,0 +1,220 @@ +{ + "Disclaimer:": "Отказ от ответственности:", + "There is always the potential for a brick.": "Всегда есть шанс брикнуть консоль.", + "Everything you do with this software is your own responsibility": "Всё что вы делаете в программе вы делаете на свой страх и риск", + "Out of memory.": "Недостаточно памяти.", + "Loaded %i Wii U titles.": "Загружено %i тайтлов Wii U.", + "%s%s (No banner.bin)": "%s%s (No banner.bin)", + "Loaded %i Wii titles.": "Загружено %i тайтлов Wii.", + "None": "Ничего не найдено", + "Name": "Имя", + "Storage": "Хранилище", + "Storage+Name": "Хранилище+Имя", + "initFS failed. Please make sure your MochaPayload is up-to-date": "Ошибка инициализации файловой системы (initFS). Убедитесь, что пейлоад Mocha свежей версии", + " Wii U Save Management (%u Title%s)": " Управление сохранениями Wii U (%u Имя%s)", + " vWii Save Management (%u Title%s)": " Управление сохранениями vWii (%u Имя%s)", + " Batch Backup": " Пакетный бекап", + "\uE002: Options \ue000: Select Mode": "\uE002: Опции \ue000: Выбор режима", + " Backup All (%u Title%s)": " Сделать бекап для всех (%u Имя%s)", + " Backup Wii U (%u Title%s)": " Бекап только для Wii U (%u Имя%s)", + " Backup vWii (%u Title%s)": " Бекап только для vWii (%u Имя%s)", + ": Backup : Back": ": Бекап: Назад", + "%s Sort: %s ": "%s Сортировать: %s ", + " [Not Init]": " [Not Init]", + ": Select Game : Back": ": Выбрать игру : Назад", + " Backup savedata": " Бекап сохранений", + " Restore savedata": " Восстановить сохранения", + " Wipe savedata": " Стереть сохранения", + " Import from loadiine": " Импортировать из loadiine", + " Export to loadiine": " Экспорт в loadiine", + " Copy Savedata to Title in %s": " Скопировать сохранения в Имя в %s", + ": Select Task : Back": ": Выбрать задачу : Назад", + "Destination:": "Назначение:", + "Select %s:": "Выбрать %s:", + "version": "версия", + "Delete from:": "Удалить из:", + "slot": "слот", + "Empty": "Пусто", + "Used": "Использовано", + "Select SD user to copy from:": "Выбрать пользователя для копирования:", + "all users": "все пользователи", + "Has Save": "Есть сохранение", + "Select Wii U user to delete from:": "Выберите пользователя Wii U для удаления из:", + "Select Wii U user%s:": "Выберите пользователя Wii U%s:", + " to copy from": " копировать из", + " to copy to": " копировать в", + "Date: %s": "Дата: %s", + "Include 'common' save?": "Включить 'common' сохранения?", + "yes": "да", + "no ": "нет ", + "No 'common' save found.": "Не найдено ни одного 'common' сохранения.", + ": Restore : Back": ": Восстановить : Назад", + ": Wipe : Back": ": Стереть : Назад", + ": Import : Back": ": Импорт : Назад", + ": Export : Back": ": Экспорт : Назад", + ": Copy : Back": ": Копирование : Назад", + "Press  to exit.": "Нажмите  для выхода.", + "No Wii U titles found.": "Не найдено тайтлов Wii U.", + "No vWii saves found.": "Сохранения vWii не найдены.", + "CBHC save. Could be dangerous to modify. Continue?": "Сохранение CBHC. Может быть опасным для изменения. Продолжить?", + "Are you REALLY sure?": "Ты ТОЧНО уверен?", + "vWii saves are in the vWii section. Continue?": "сохранение vWii находится в разделе vWii. Продолжить?", + "Recommended to run Game at least one time. Continue?": "Рекомендуется запустить игру по крайней мере один раз. Продолжить?", + "No save to Backup.": "Нет сохранений для бекапа.", + "No save to Wipe.": "Нет сохранений для стирания.", + "No save to Export.": "Нет сохранений для экспорта.", + "No save to Copy.": "Нет сохранений для копирования.", + "Copying file: %s": "Копируемый файл: %s", + "From: %s": "Из %s", + "To: %s": "В %s", + " Yes -  No": " Да -  Нет", + " Confirm -  Cancel": " Подтвердить -  Отменить", + "Filesize: %d bytes": "Размер: %d байт", + "Deleting folder %s": "Удаление папки %s", + "From: \n%s": "Из %s", + "Failed to delete folder %s: %s": "Не удалось удалить папку %s: %s", + "Deleting file %s": "Удаление файла %s", + "Failed to delete file %s: %s": "Не удалось удалить файл %s: %s", + "Loadiine game folder not found.": "Папка Loadiine не найдена.", + "Failed to open Loadiine game save directory.": "Не удалось открыть каталог сохранения Loadiine.", + "Are you sure?": "Вы уверены?", + "Backup current savedata first to next empty slot?": "Сохранить текущее сохранение в следующий пустой слот?", + "Backup done. Now copying Savedata.": "Бекап завершен. Копирование сохранений.", + "Common save not found.": "'Common' сохранение не найдено.", + "Copy failed.": "Копирование не удалось.", + "Backup failed.": "Бекап не удался.", + "Backup found on this slot. Overwrite it?": "Слот не пустой. Перезаписать?", + "No save found for this user.": "Не найдено сохранений для этого пользователя.", + "Backup failed. DO NOT restore from this slot.": "Бекап не удался. НЕ восстанавливайте из этого слота.", + "No backup found on selected slot.": "В выбранном слоте бекап не найден.", + "Restore failed.": "Ошибка восстановления.", + "Hm, are you REALLY sure?": "Вы ТОЧНО уверены?", + "Backup current savedata first?": "Сделать сперва бекап сохранения?", + "Failed to delete common folder: %s": "Не удалось удалить папку: %s", + "Failed to delete savefile.": "Не удалось удалить сохранение.", + "Failed to delete user folder: %s": "Не удалось удалить пользовательскую папку: %s", + "Failed to import savedata from loadiine.": "Не удалось импортировать сохранения из loadiine.", + "Failed to export savedata to loadiine.": "Не удалось экспортировать сохранения из loadiine.", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "%s Sort: %s \ue084": "%s Sort: %s \ue084", + "%s \n Common save not found.": "%s \n Common save not found.", + "%s \n Failed to delete common folder:\n %s": "%s \n Failed to delete common folder:\n %s", + "%s \n Failed to delete savefile.": "%s \n Failed to delete savefile.", + "%s \n Failed to delete user folder:\n %s": "%s \n Failed to delete user folder:\n %s", + "%s\nCommon save not restored.": "%s\nCommon save not restored.", + "%s\nNo backup found on selected slot.": "%s\nNo backup found on selected slot.", + "%s\nNo save found for this user.": "%s\nNo save found for this user.", + "%s\nRestore failed.": "%s\nRestore failed.", + ", from ": ", from ", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSet: %s": "BackupSet: %s", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Error setting path. Aborting.": "Error setting path. Aborting.", + "Export Loadiine": "Export Loadiine", + "Failed to delete backupSet %s.": "Failed to delete backupSet %s.", + "Failed to delete slot %u.": "Failed to delete slot %u.", + "Folder does not exist.": "Folder does not exist.", + "German": "German", + "Getting Serial ID": "Getting Serial ID", + "Import Loadiine": "Import Loadiine", + "Initializing BackupSets metadata.": "Initializing BackupSets metadata.", + "Initializing ROMFS": "Initializing ROMFS", + "Initializing WPAD and KAPD": "Initializing WPAD and KAPD", + "Initializing loadWiiU Titles": "Initializing loadWiiU Titles", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Please wait. First write to SD may be slow.": "Please wait. First write to SD may be slow.", + "Portuguese": "Portuguese", + "Press \ue000 to continue": "Press \ue000 to continue", + "Press \ue044 to exit.": "Press \ue044 to exit.", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe BackupSet - Hm, are you REALLY sure?": "Wipe BackupSet - Hm, are you REALLY sure?", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000 Confirm - \ue001 Cancel": "\ue000 Confirm - \ue001 Cancel", + "\ue000 Yes - \ue001 No": "\ue000 Yes - \ue001 No", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue001: Back": "\ue000: Backup \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Copy \ue001: Back": "\ue000: Copy \ue001: Back", + "\ue000: Export \ue001: Back": "\ue000: Export \ue001: Back", + "\ue000: Import \ue001: Back": "\ue000: Import \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue000: Select Game \ue001: Back": "\ue000: Select Game \ue001: Back", + "\ue000: Select Task \ue001: Back": "\ue000: Select Task \ue001: Back", + "\ue000: Wipe \ue001: Back": "\ue000: Wipe \ue001: Back", + "\ue001: Back": "\ue001: Back", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Change BackupSet \ue000: Restore \ue001: Back", + "\ue003 Confirm - \ue001 Cancel": "\ue003 Confirm - \ue001 Cancel", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "\ue083 Sort: %s \ue084": "\ue083 Sort: %s \ue084", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" +} \ No newline at end of file diff --git a/romfs/languages/spanish.json b/romfs/languages/spanish.json new file mode 100644 index 0000000..88c8df0 --- /dev/null +++ b/romfs/languages/spanish.json @@ -0,0 +1,214 @@ +{ + "Disclaimer:": "Atención:", + "There is always the potential for a brick.": "Siempre existe la posibilidad de un brick.", + "Everything you do with this software is your own responsibility": "Todo lo que hagas con este software es tu responsabilidad", + "Out of memory.": "Sin memoria.", + "Loaded %i Wii U titles.": "Cargados %i títulos de Wii U.", + "%s%s (No banner.bin)": "%s%s (Sin banner.bin)", + "Loaded %i Wii titles.": "Cargados %i títulos de Wii.", + "None": "Ninguno", + "Name": "Nombre", + "Storage": "Dispositivo", + "Storage+Name": "Dispositivo+Nombre", + "initFS failed. Please make sure your MochaPayload is up-to-date": "Error en initFS. Verifica que MochaPayload está actualizado", + " Wii U Save Management (%u Title%s)": " Gestión de saves de Wii U (%u Título%s)", + " vWii Save Management (%u Title%s)": " Gestión de saves de vWii (%u Título%s)", + " Batch Backup": " Copia de seguridad en masa", + "\uE002: Options \ue000: Select Mode": "\uE002: Opciones \ue000: Seleccionar", + " Backup All (%u Title%s)": " Copiar Todo (%u Título%s)", + " Backup Wii U (%u Title%s)": " Copiar Wii U (%u Título%s)", + " Backup vWii (%u Title%s)": " Copiar vWii (%u Título%s)", + "\ue000: Backup \ue001: Back": "\ue000: Copiar \ue001: Atrás", + "%s Sort: %s \ue084": "%s Orden: %s \ue084", + " [Not Init]": " [No Inic.]", + "\ue000: Select Game \ue001: Back": "\ue000: Seleccionar Juego \ue001: Atrás", + " Backup savedata": " Copiar savedata", + " Restore savedata": " Restaurar savedata", + " Wipe savedata": " Borrar savedata", + " Import from loadiine": " Importar desde loadiine", + " Export to loadiine": " Exportar a loadiine", + " Copy Savedata to Title in %s": " Copiar Savedata al Título en %s", + "\ue000: Select Task \ue001: Back": "\ue000: Seleccionar Tarea \ue001: Atrás", + "Destination:": "Destino:", + "Select %s:": "Seleccionar %s:", + "version": "versión", + "Delete from:": "Borrar de:", + "slot": "slot", + "Empty": "Libre", + "Used": "Usado", + "Select SD user to copy from:": "Selecciona el usuario de SD del que copiar:", + "all users": "todos los usuarios", + "Has Save": "Existe Save", + "Select Wii U user to delete from:": "Selecciona el usuario de Wii U del que copiar:", + "Select Wii U user%s:": "Selecciona el usuario de Wii U%s:", + " to copy from": " del que copiar", + " to copy to": " al que copiar", + "Date: %s": "Fecha: %s", + "Include 'common' save?": "¿Incluír 'common' save?", + "yes": "sí", + "no ": "no ", + "No 'common' save found.": "No se ha encontrado 'common' save.", + "\ue000: Restore \ue001: Back": "\ue000: Restaurar \ue001: Atrás", + "\ue000: Wipe \ue001: Back": "\ue000: Eliminar \ue001: Atrás", + "\ue000: Import \ue001: Back": "\ue000: Importar \ue001: Atrás", + "\ue000: Export \ue001: Back": "\ue000: Exportar \ue001: Atrás", + "\ue000: Copy \ue001: Back": "\ue000: Copiar \ue001: Atrás", + "Press \ue044 to exit.": "Presiona \ue044 para salir.", + "No Wii U titles found.": "No se han encontrado títulos de Wii U.", + "No vWii saves found.": "No se han encontrado saves de vWii.", + "CBHC save. Could be dangerous to modify. Continue?": "Save de CBHC. Puede ser peligroso modificarlo. ¿Continuar?", + "Are you REALLY sure?": "¿Estás COMPLETAMENTE seguro?", + "vWii saves are in the vWii section. Continue?": "Los saves de vWii están en su propia sección. ¿Continuar?", + "Recommended to run Game at least one time. Continue?": "Se recomienda correr el juego al menos una vez. ¿Continuar?", + "No save to Backup.": "No hay save que copiar.", + "No save to Wipe.": "No hay save que eliminar.", + "No save to Export.": "No hay save que exportar.", + "No save to Copy.": "No hay save que copiar.", + "Copying file: %s": "Copiando archivo: %s", + "From: %s": "Desde: %s", + "To: %s": "A: %s", + "\ue000 Yes - \ue001 No": "\ue000 Sí - \ue001 No", + "\ue000 Confirm - \ue001 Cancel": "\ue000 Confirmar - \ue001 Cancelar", + "Filesize: %d bytes": "Tamaño: %d bytes", + "Deleting folder %s": "Eliminando carpeta %s", + "From: \n%s": "Desde:\n%s", + "Failed to delete folder %s: %s": "Error al eliminar la carpeta %s: %s", + "Deleting file %s": "Eliminando archivo %s", + "Failed to delete file %s: %s": "Error al eliminar el archivo %s: %s", + "Loadiine game folder not found.": "Carpeta del juego de Loadiine no encontrada.", + "Failed to open Loadiine game save directory.": "Error al abrir la carpeta de saves del juego de Loadiine.", + "Are you sure?": "¿Estás seguro?", + "Backup current savedata first to next empty slot?": "¿Copiar el save actual al siguiente slot libre?", + "Backup done. Now copying Savedata.": "Copia hecha. Haciendo copia del save.", + "Common save not found.": "No se ha podido encontrar el common save.", + "Copy failed.": "Error al realizar la copia.", + "Backup failed.": "Error al realizar la copia.", + "Backup found on this slot. Overwrite it?": "Se ha encontrado una copia en este slot. ¿Sobreescribirlo?", + "No save found for this user.": "No se han encontrado saves de este usuario.", + "Backup failed. DO NOT restore from this slot.": "Error al realizar la copia. NO restaures este slot.", + "No backup found on selected slot.": "No se ha encontrado una copia en el slot seleccionado.", + "Restore failed.": "Error al restaurar.", + "Hm, are you REALLY sure?": "¿Hm, estás COMPLETAMENTE seguro?", + "Backup current savedata first?": "¿Hacer copia antes del save?", + "Failed to delete common folder: %s": "Error al eliminar la carpeta common: %s", + "Failed to delete savefile.": "Error al eliminar el save.", + "Failed to delete user folder: %s": "Error al eliminar la carpeta user: %s", + "Failed to import savedata from loadiine.": "Error al importar el save de loadiine.", + "Failed to export savedata to loadiine.": "Error al exportar el save a loadiine.", + "\ue083 Sort: %s \ue084": "\ue083 Ordenar: %s \ue084", + "\ue000: Select BackupSet \ue001: Back": "\ue000: Seleccionar BackupSet \ue001: Atrás", + "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: Cambiar BackupSet \ue000: Restaurar \ue001: Atrás", + "WiiU USB Savedata >> slot 0": "WiiU USB Savedata >> slot 0", + "WiiU NAND Savedata >> slot 1": "WiiU NAND Savedata >> slot 1", + "vWii Savedata >> slot 0": "vWii Savedata >> slot 0", + "BackupSet: %s": "BackupSet: %s", + ", from ": ", de ", + "Common save not restored.": "No se ha podido restaurar el common save", + "\ue001: Back": "\ue001: Atrás", + " Batch Restore": " Batch Restore", + " Language: %s": " Language: %s", + " Restore Wii U (%u Title%s)": " Restore Wii U (%u Title%s)", + " Restore vWii (%u Title%s)": " Restore vWii (%u Title%s)", + " [vWiiInject]": " [vWiiInject]", + "%s \n Common save not found.": "%s \n Common save not found.", + "%s \n Failed to delete common folder:\n %s": "%s \n Failed to delete common folder:\n %s", + "%s \n Failed to delete savefile.": "%s \n Failed to delete savefile.", + "%s \n Failed to delete user folder:\n %s": "%s \n Failed to delete user folder:\n %s", + "%s\nCommon save not restored.": "%s\nCommon save not restored.", + "%s\nNo backup found on selected slot.": "%s\nNo backup found on selected slot.", + "%s\nNo save found for this user.": "%s\nNo save found for this user.", + "%s\nRestore failed.": "%s\nRestore failed.", + "- Include common savedata: N": "- Include common savedata: N", + "- Perform full backup: N": "- Perform full backup: N", + "- Restore allusers": "- Restore allusers", + "- Restore from %s to < %s (%s) >": "- Restore from %s to < %s (%s) >", + "- Wipe data: N": "- Wipe data: N", + ">> Skip": ">> Skip", + "Any Button: Back": "Any Button: Back", + "Backup": "Backup", + "BackupSets (filter applied)": "BackupSets (filter applied)", + "BackupSets": "BackupSets", + "Batch Backup": "Batch Backup", + "Batch Restore - Select & Go": "Batch Restore - Select & Go", + "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.": "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.", + "Batch Restore": "Batch Restore", + "BatchRestore - Options": "BatchRestore - Options", + "Configuration Options": "Configuration Options", + "Copy to Other Device": "Copy to Other Device", + "English": "English", + "Error setting path. Aborting.": "Error setting path. Aborting.", + "Export Loadiine": "Export Loadiine", + "Failed to delete backupSet %s.": "Failed to delete backupSet %s.", + "Failed to delete slot %u.": "Failed to delete slot %u.", + "Folder does not exist.": "Folder does not exist.", + "German": "German", + "Getting Serial ID": "Getting Serial ID", + "Import Loadiine": "Import Loadiine", + "Initializing BackupSets metadata.": "Initializing BackupSets metadata.", + "Initializing ROMFS": "Initializing ROMFS", + "Initializing WPAD and KAPD": "Initializing WPAD and KAPD", + "Initializing loadWiiU Titles": "Initializing loadWiiU Titles", + "Italian": "Italian", + "Japanese": "Japanese", + "Keyboard": "Keyboard", + "Korean": "Korean", + "Main menu": "Main menu", + "No Wii U titles found": "No Wii U titles found", + "No titles found": "No titles found", + "No vWii titles found.": "No vWii titles found.", + "No": "No", + "Please wait. First write to SD may be slow.": "Please wait. First write to SD may be slow.", + "Portuguese": "Portuguese", + "Press \ue000 to continue": "Press \ue000 to continue", + "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n", + "Restore": "Restore", + "Root BackupSet cannot be selected for batchRestore": "Root BackupSet cannot be selected for batchRestore", + "Russian": "Russian", + "Select Wii U user to copy to": "Select Wii U user to copy to", + "Show only BackupSets satisfying all these conditions:": "Show only BackupSets satisfying all these conditions:", + "Simplified Chinese": "Simplified Chinese", + "Spanish": "Spanish", + "Strg+Nm": "Strg+Nm", + "Tasks": "Tasks", + "There are no titles matching selected filters.": "There are no titles matching selected filters.", + "Traditional Chinese": "Traditional Chinese", + "Wii U Titles": "Wii U Titles", + "WiiU Serial Id: %s": "WiiU Serial Id: %s", + "Wipe BackupSet - Hm, are you REALLY sure?": "Wipe BackupSet - Hm, are you REALLY sure?", + "Wipe": "Wipe", + "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s.\nContinue?\n\n", + "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n", + "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "You have selected uninitialized titles (not recommended). Are you 100%% sure?", + "[AB]": "[AB]", + "[KO]": "[KO]", + "[OK]": "[OK]", + "[WR]": "[WR]", + "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back", + "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back", + "\ue000: Continue to batch restore \ue001: Back": "\ue000: Continue to batch restore \ue001: Back", + "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000: Ok! Go to Title selection \ue001: Back", + "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back", + "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back", + "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", + "\ue003 Confirm - \ue001 Cancel": "\ue003 Confirm - \ue001 Cancel", + "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back", + "same user than in source": "same user than in source", + "vWii Titles": "vWii Titles", + "|Restored|": "|Restored|", + " BackupSet Management": " BackupSet Management", + "BS: %s": "BS: %s", + "pre-BatchRestore Backup (WiiU)": "pre-BatchRestore Backup (WiiU)", + "pre-BatchRestore Backup (vWii)": "pre-BatchRestore Backup (vWii)", + "pre-Restore backup": "pre-Restore backup", + "pre-Wipe backup": "pre-Wipe backup", + "pre-copyToOtherDev backup": "pre-copyToOtherDev backup", + "UNUSABLE SLOT - BACKUP FAILED": "UNUSABLE SLOT - BACKUP FAILED", + "KB_N_0": "1234567890-=", + "KB_N_1": "qwertyuiop[]|", + "KB_N_2": "asdfghjkl;'", + "KB_N_3": "zxcvbnm ,./", + "KB_S_0": "!@#$%^&*()_+~", + "KB_S_1": "QWERTYUIOP{}\\", + "KB_S_2": "ASDFGHJKL:\"", + "KB_S_3": "ZXCVBNM <>" +} \ No newline at end of file diff --git a/src/BackupSetList.cpp b/src/BackupSetList.cpp index bdfc1ef..6cc6e5e 100644 --- a/src/BackupSetList.cpp +++ b/src/BackupSetList.cpp @@ -1,11 +1,13 @@ #include +#include +#include #include #include -#include #include #include #include +#include bool BackupSetList::sortAscending = false; const std::string BackupSetList::ROOT_BS = ">> Root <<"; @@ -22,7 +24,14 @@ BackupSetList::BackupSetList(const char *backupSetListRoot) this->backupSetListRoot = backupSetListRoot; - backupSets.push_back(ROOT_BS); + BSMetadata bsm; + + backupSets.push_back(BackupSetItem(ROOT_BS,bsm)); + bsMetadataValues.year.range.insert("*"); + bsMetadataValues.month.range.insert("*"); + bsMetadataValues.serialId.range.insert("*"); + bsMetadataValues.tag.range.insert("*"); + v2b.push_back(0); DIR *dir = opendir(backupSetListRoot); if (dir != nullptr) { @@ -30,37 +39,81 @@ BackupSetList::BackupSetList(const char *backupSetListRoot) while ((data = readdir(dir)) != nullptr) { if(strcmp(data->d_name,".") == 0 || strcmp(data->d_name,"..") == 0 || ! (data->d_type & DT_DIR)) continue; - backupSets.push_back(data->d_name); + + std::string metadataPath = data->d_name; + Metadata metadata(std::string(batchBackupPath)+"/"+metadataPath); + if(!metadata.read()) { + metadata.write(); + } + bsm = BSMetadata(metadata.getDate().substr(0,4),metadata.getDate().size()>6 ? metadata.getDate().substr(5,2) : "", + metadata.getSerialId(),metadata.getTag()); + backupSets.push_back(BackupSetItem(data->d_name,bsm)); + if (bsm.year != "") + bsMetadataValues.year.range.insert(bsm.year); + if (bsm.month != "") + bsMetadataValues.month.range.insert(bsm.month); + bsMetadataValues.serialId.range.insert(bsm.serialId); + if (bsm.tag != "") + bsMetadataValues.tag.range.insert(bsm.tag); } } closedir(dir); - this->entries = backupSets.size(); + this->entries = this->backupSets.size(); + + BackupSetItemView bsiv; + for (int i=0;i < this->entries;i++) { + bsiv.entryPath = backupSets[i].entryPath; + bsiv.serialId = backupSets[i].bsItemMetadata.serialId; + bsiv.tag = backupSets[i].bsItemMetadata.tag; + this->backupSetsView.push_back(bsiv); + this->v2b.push_back(i); + } + + this->entriesView = backupSetsView.size(); this->sort(sortAscending); + bsMetadataValues.year.iterator = --bsMetadataValues.year.range.end(); + bsMetadataValues.month.iterator = --bsMetadataValues.month.range.end(); + bsMetadataValues.serialId.iterator = bsMetadataValues.serialId.range.begin(); + bsMetadataValues.tag.iterator = bsMetadataValues.tag.range.begin(); } void BackupSetList::sort(bool sortAscending_) { if (sortAscending_) { - std::ranges::sort(backupSets.begin()+1,backupSets.end(),std::ranges::less{}); + std::ranges::sort(backupSetsView.begin()+1,backupSetsView.end(),std::ranges::less{},&BackupSetItemView::entryPath); } else { - std::ranges::sort(backupSets.begin()+1,backupSets.end(),std::ranges::greater{}); + std::ranges::sort(backupSetsView.begin()+1,backupSetsView.end(),std::ranges::greater{},&BackupSetItemView::entryPath); } sortAscending = sortAscending_; } -std::string BackupSetList::at(int i) -{ - - return backupSets.at(i); +std::string BackupSetList::at(int i) { + return backupSetsView.at(i).entryPath; +} +std::string BackupSetList::getSerialIdAt(int i) { + return backupSetsView.at(i).serialId; } -void BackupSetList::add(std::string backupSet) +std::string BackupSetList::getStretchedSerialIdAt(int i) { + int serialIdSize = getSerialIdAt(i).size(); + return serialIdSize > 8 ? getSerialIdAt(i).substr(0,4)+".."+getSerialIdAt(i).substr(serialIdSize-4,4) : getSerialIdAt(i); +} + +std::string BackupSetList::getTagAt(int i) { + return backupSetsView.at(i).tag; +} + +void BackupSetList::add(std::string entryPath,std::string serialId,std::string tag) { - backupSets.push_back(backupSet); - this->entries++; + BackupSetItemView bsiv; + bsiv.entryPath = entryPath; + bsiv.serialId = serialId; + bsiv.tag = tag; + backupSetsView.push_back(bsiv); + this->entriesView++; if (!sortAscending) this->sort(false); } @@ -81,3 +134,93 @@ void BackupSetList::setBackupSetSubPath() { else backupSetSubPath = "/batch/"+backupSetEntry+"/"; } + +std::string BackupSetList::getBackupSetSubPath(int i) { + if (i == 0) + return "/"; + else + return "/batch/"+currentBackupSetList->at(i)+"/"; +} + +void BackupSetList::filter(BSMetadata filterDef) { + + backupSetsView.erase(backupSetsView.begin()+1,backupSetsView.end()); + v2b.erase(v2b.begin()+1,v2b.end()); + BackupSetItemView bsiv; + for (unsigned int i=1; i < this->backupSets.size(); i++) { + if (filterDef.year == "*" || filterDef.year == this->backupSets[i].bsItemMetadata.year) + if (filterDef.month == "*" || filterDef.month == this->backupSets[i].bsItemMetadata.month) + if (filterDef.serialId == "*" || filterDef.serialId == this->backupSets[i].bsItemMetadata.serialId) + if (filterDef.tag == "*" || filterDef.tag == this->backupSets[i].bsItemMetadata.tag) { + bsiv.entryPath = backupSets[i].entryPath; + bsiv.serialId = backupSets[i].bsItemMetadata.serialId; + bsiv.tag = backupSets[i].bsItemMetadata.tag; + this->backupSetsView.push_back(bsiv); + this->v2b.push_back(i); + } + } + this->entriesView = this->backupSetsView.size(); +} + +void BackupSetList::filter() { + backupSetsView.erase(backupSetsView.begin()+1,backupSetsView.end()); + BackupSetItemView bsiv; + for (unsigned int i=1; i < this->backupSets.size(); i++) { + if (*bsMetadataValues.year.iterator == "*" || *bsMetadataValues.year.iterator == this->backupSets[i].bsItemMetadata.year) + if (*bsMetadataValues.month.iterator == "*" || *bsMetadataValues.month.iterator == this->backupSets[i].bsItemMetadata.month) + if (*bsMetadataValues.serialId.iterator == "*" || *bsMetadataValues.serialId.iterator == this->backupSets[i].bsItemMetadata.serialId) + if (*bsMetadataValues.tag.iterator == "*" || *bsMetadataValues.tag.iterator == this->backupSets[i].bsItemMetadata.tag) { + bsiv.entryPath = backupSets[i].entryPath; + bsiv.serialId = backupSets[i].bsItemMetadata.serialId; + bsiv.tag = backupSets[i].bsItemMetadata.tag; + this->backupSetsView.push_back(bsiv); + } + } + this->entriesView = this->backupSetsView.size(); +} + +void BackupSetList::resetTagRange() { + bsMetadataValues.tag.range.erase(bsMetadataValues.tag.range.begin(),bsMetadataValues.tag.range.end()); + for (unsigned int i=0;i < this->backupSets.size();i++) { + if (backupSets[i].bsItemMetadata.tag != "") + bsMetadataValues.tag.range.insert(backupSets[i].bsItemMetadata.tag); + } + bsMetadataValues.tag.iterator = bsMetadataValues.tag.range.begin(); +} + +void BSMetadataValues::resetFilter() { + this->year.iterator = --this->year.range.end(); + this->month.iterator = --this->month.range.end(); + this->serialId.iterator = this->serialId.range.begin(); + this->tag.iterator = this->tag.range.begin(); +} + +void BackupSetList::setTagBSVAt(int i, const std::string & tag) { + this->backupSetsView[i].tag = tag; +} + +void BackupSetList::setTagBSAt(int i, const std::string & tag_) { + this->backupSets[i].bsItemMetadata.tag = tag_; +} + +template < typename T > +void BSMetadataValues::Right( T & metadataAttr ) { + metadataAttr.iterator++; + if (metadataAttr.iterator == metadataAttr.range.end()) + metadataAttr.iterator = metadataAttr.range.begin(); +} + +template < typename T > +void BSMetadataValues::Left(T & metadataAttr ) { + if (metadataAttr.iterator == metadataAttr.range.begin()) + metadataAttr.iterator = --metadataAttr.range.end(); + else + metadataAttr.iterator--; +} + +template void BSMetadataValues::Right(attr> &); +template void BSMetadataValues::Right(attr> &); +template void BSMetadataValues::Left(attr> &); +template void BSMetadataValues::Left(attr> &); + + diff --git a/src/Metadata.cpp b/src/Metadata.cpp index f1adb73..ee70a02 100644 --- a/src/Metadata.cpp +++ b/src/Metadata.cpp @@ -1,13 +1,15 @@ #include #include +#include #define FS_ALIGN(x) ((x + 0x3F) & ~(0x3F)) -std::string Metadata::serialId { "_WIIU_" }; +std::string Metadata::unknownSerialId { "_WIIU_" }; +std::string Metadata::thisConsoleSerialId = Metadata::unknownSerialId; -std::string Metadata::get() { - if (checkEntry(path.c_str()) != 0) { - FILE *f = fopen(path.c_str(), "rb"); +bool Metadata::read() { + if (checkEntry(this->path.c_str()) != 0) { + FILE *f = fopen(this->path.c_str(), "rb"); fseek(f, 0, SEEK_END); long len = ftell(f); fseek(f, 0, SEEK_SET); @@ -23,35 +25,72 @@ std::string Metadata::get() { if (root) { std::string metadata {}; - const char* date_ = json_string_value(json_object_get(root, "Date")); - if (date_ != nullptr) { - metadata.append(json_string_value(json_object_get(root, "Date"))); + const char* Date = json_string_value(json_object_get(root, "Date")); + if (Date != nullptr) { + this->Date.assign(Date); + } + const char* storage = json_string_value(json_object_get(root, "storage")); + if (storage != nullptr) { + this->storage.assign(storage); } - const char* storage_ = json_string_value(json_object_get(root, "storage")); - if (storage_ != nullptr) { - metadata.append(LanguageUtils::gettext(", from ")).append(storage_); + const char* serialId = json_string_value(json_object_get(root, "serialId")); + if (serialId != nullptr) { + this->serialId.assign(serialId); } - const char* serialId_ = json_string_value(json_object_get(root, "serialId")); - if (serialId_ != nullptr) { - metadata.append(" | ").append(serialId_); + const char* tag = json_string_value(json_object_get(root, "tag")); + if (tag != nullptr) { + this->tag.assign(tag); } json_decref(root); free(data); - return metadata; + return true; } - return ""; + } + return false; +} + +std::string Metadata::get() { + if (read()) { + std::string metadataMessage {}; + metadataMessage.assign(this->Date); + if (this->storage != "") + metadataMessage.append(LanguageUtils::gettext(", from ")).append(this->storage); + metadataMessage.append(" | ").append(this->serialId); + return metadataMessage; + } + return ""; +} + +std::string Metadata::simpleFormat() { + if (this->Date != "") { + std::string metadataMessage {}; + metadataMessage.assign(this->Date); + if (this->storage != "") + metadataMessage.append(LanguageUtils::gettext(", from ")).append(this->storage); + metadataMessage.append(" | ").append(this->serialId); + return metadataMessage; } return ""; } bool Metadata::set(const std::string &date, bool isUSB) { + + this->Date = date; + this->storage = isUSB ? "USB" : "NAND"; + this->serialId = thisConsoleSerialId; + + return write(); +} + +bool Metadata::write() { json_t *config = json_object(); if (config == nullptr) return false; - json_object_set_new(config, "Date", json_string(date.c_str())); - json_object_set_new(config, "serialId", json_string(serialId.c_str())); - json_object_set_new(config, "storage", json_string(isUSB ? "USB" : "NAND")); + json_object_set_new(config, "Date", json_string(this->Date.c_str())); + json_object_set_new(config, "serialId", json_string(this->serialId.c_str())); + json_object_set_new(config, "storage", json_string(this->storage.c_str())); + json_object_set_new(config, "tag", json_string(this->tag.c_str())); char *configString = json_dumps(config, 0); if (configString == nullptr) @@ -59,7 +98,7 @@ bool Metadata::set(const std::string &date, bool isUSB) { json_decref(config); - FILE *fp = fopen(path.c_str(), "wb"); + FILE *fp = fopen(this->path.c_str(), "wb"); if (fp == nullptr) return false; diff --git a/src/main.cpp b/src/main.cpp index 59ed121..4f17ed0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,13 @@ #include #include +//#define DEBUG + +#ifdef DEBUG +#include +#include +#endif + static int wiiuTitlesCount = 0, vWiiTitlesCount = 0; extern char *batchBackupPath; @@ -34,6 +41,7 @@ static bool contains(const T (&arr)[N], const T &element) { } static void disclaimer() { + consolePrintPosAligned(13, 0, 1,"SaveMii v%u.%u.%u", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); consolePrintPosAligned(14, 0, 1, LanguageUtils::gettext("Disclaimer:")); consolePrintPosAligned(15, 0, 1, LanguageUtils::gettext("There is always the potential for a brick.")); consolePrintPosAligned(16, 0, 1, @@ -46,7 +54,7 @@ static void getWiiUSerialId() { int32_t mcpHandle = MCP_Open(); if ( mcpHandle >= 0 ) { if (MCP_GetSysProdSettings(mcpHandle,&sysProd)==0) { - Metadata::serialId = std::string(sysProd.code_id) + sysProd.serial_id; + Metadata::thisConsoleSerialId = std::string(sysProd.code_id) + sysProd.serial_id; } MCP_Close(mcpHandle); } @@ -79,12 +87,15 @@ static Title *loadWiiUTitles(int run) { for (uint32_t i = 0; i < receivedCount; i++) { char *element = tList + (i * 0x61); savesl[j].highID = *(uint32_t *) (element); - if (!contains(highIDs, savesl[j].highID)) { + bool isUSB = ( memcmp(element + 0x56, "usb", 4) == 0 ); + bool isMLC = ( memcmp(element + 0x56, "mlc", 4) == 0 ); + if (!contains(highIDs, savesl[j].highID) || !(isUSB || isMLC) ) { usable--; continue; } savesl[j].lowID = *(uint32_t *) (element + 4); - savesl[j].dev = static_cast((memcmp(element + 0x56, "usb", 4) != 0)); + savesl[j].dev = static_cast(isMLC); // 0 = usb, 1 = nand + savesl[j].found = false; j++; } @@ -216,6 +227,10 @@ static Title *loadWiiUTitles(int run) { free(xmlBuf); } + if (strlen(titles[wiiuTitlesCount].shortName) == 0u) + sprintf(titles[wiiuTitlesCount].shortName,"%08x%08x", + titles[wiiuTitlesCount].highID, + titles[wiiuTitlesCount].lowID); titles[wiiuTitlesCount].isTitleDupe = false; for (int i = 0; i < wiiuTitlesCount; i++) { @@ -229,10 +244,20 @@ static Title *loadWiiUTitles(int run) { titles[wiiuTitlesCount].highID = highID; titles[wiiuTitlesCount].lowID = lowID; + titles[wiiuTitlesCount].is_Wii = ((highID & 0xFFFFFFF0) == 0x00010000); titles[wiiuTitlesCount].isTitleOnUSB = isTitleOnUSB; titles[wiiuTitlesCount].listID = wiiuTitlesCount; if (loadTitleIcon(&titles[wiiuTitlesCount]) < 0) - titles[wiiuTitlesCount].iconBuf = nullptr; + titles[wiiuTitlesCount].iconBuf = nullptr; + + std::string fwpath = StringUtils::stringFormat("%s/usr/title/000%x/%x/code/fw.img", + titles[wiiuTitlesCount].isTitleOnUSB ? getUSB().c_str() : "storage_mlc01:", + titles[wiiuTitlesCount].highID, + titles[wiiuTitlesCount].lowID); + if (checkEntry(fwpath.c_str()) != 0) + titles[wiiuTitlesCount].noFwImg = true; + else + titles[wiiuTitlesCount].noFwImg = false; wiiuTitlesCount++; @@ -333,6 +358,10 @@ static Title *loadWiiTitles() { titles[i].shortName[k++] = 0x80 | (bnrBuf[j] & 0x3F); } } + if (strlen(titles[i].shortName) == 0u) + sprintf(titles[i].shortName,"%08x%08x", + titles[i].highID, + titles[i].lowID); memset(titles[i].longName, 0, sizeof(titles[i].longName)); for (int j = 0x20, k = 0; j < 0x40; j++) { @@ -364,6 +393,8 @@ static Title *loadWiiTitles() { titles[i].highID = strtoul(highID, nullptr, 16); titles[i].lowID = strtoul(data->d_name, nullptr, 16); + titles[i].is_Wii = true; + titles[i].noFwImg = true; titles[i].listID = i; memcpy(titles[i].productCode, &titles[i].lowID, 4); @@ -403,6 +434,11 @@ static void unloadTitles(Title *titles, int count) { int main() { +#ifdef DEBUG + WHBLogUdpInit(); + WHBLogPrintf("Hello from savemii!"); +#endif + AXInit(); AXQuit(); @@ -414,18 +450,41 @@ int main() { State::registerProcUICallbacks(); - if (!DrawUtils::initFont()) { + if (!DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD)) { OSFatal("Failed to init font"); } + DrawUtils::setFont(); + + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BLACK); + consolePrintPosAligned(10, 0, 1, LanguageUtils::gettext("Initializing WPAD and KAPD")); + DrawUtils::endDraw(); + WPADInit(); KPADInit(); WPADEnableURCC(1); + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BLACK); + consolePrintPosAligned(10, 0, 1, LanguageUtils::gettext("Getting Serial ID")); + DrawUtils::endDraw(); + getWiiUSerialId(); + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BLACK); + consolePrintPosAligned(10, 0, 1, LanguageUtils::gettext("Initializing loadWiiU Titles")); + DrawUtils::endDraw(); + loadWiiUTitles(0); + + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BLACK); + consolePrintPosAligned(10, 0, 1, LanguageUtils::gettext("Initializing ROMFS")); + DrawUtils::endDraw(); + int res = romfsInit(); if (res) { promptError("Failed to init romfs: %d", res); @@ -447,6 +506,7 @@ int main() { DrawUtils::clear(COLOR_BLACK); DrawUtils::endDraw(); + Title *wiiutitles = loadWiiUTitles(1); Title *wiititles = loadWiiTitles(); getAccountsWiiU(); @@ -454,6 +514,14 @@ int main() { sortTitle(wiiutitles, wiiutitles + wiiuTitlesCount, 1, true); sortTitle(wiititles, wiititles + vWiiTitlesCount, 1, true); + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BLACK); + disclaimer(); + DrawUtils::drawTGA(298, 144, 1, icon_tga); + consolePrintPosAligned(10, 0, 1, LanguageUtils::gettext("Initializing BackupSets metadata.")); + consolePrintPosAligned(11, 0, 1, LanguageUtils::gettext("Please wait. First write to SD may be slow.")); + DrawUtils::endDraw(); + BackupSetList::initBackupSetList(); Input input{}; diff --git a/src/menu/BRTitleSelectState.cpp b/src/menu/BRTitleSelectState.cpp new file mode 100644 index 0000000..daf7a7d --- /dev/null +++ b/src/menu/BRTitleSelectState.cpp @@ -0,0 +1,404 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#ifdef DEBUG +#include +#include +#endif + +//#define TESTSAVEINIT +#ifdef TESTSAVEINIT +bool testForceSaveInitFalse = true +#endif + +#define MAX_TITLE_SHOW 14 + +BRTitleSelectState::BRTitleSelectState(int sduser, int wiiuuser, bool common, bool wipeBeforeRestore, bool fullBackup, + Title *titles, int titlesCount, bool isWiiUBatchRestore) : + sduser(sduser), + wiiuuser(wiiuuser), + common(common), + wipeBeforeRestore(wipeBeforeRestore), + fullBackup(fullBackup), + titles(titles), + titlesCount(titlesCount), + isWiiUBatchRestore(isWiiUBatchRestore) +{ + + c2t.clear(); + // from the subset of titles with backup data, filter out the ones without the specified user info + for (int i = 0; i < this->titlesCount; i++) { + this->titles[i].currentBackup.candidateToBeRestored = false; + this->titles[i].currentBackup.selected = false; + this->titles[i].currentBackup.hasUserSavedata = false; + this->titles[i].currentBackup.hasCommonSavedata = false; + this->titles[i].currentBackup.batchRestoreState = NOT_TRIED; + if ( this->titles[i].currentBackup.hasBatchBackup == false ) + continue; + if (strcmp(this->titles[i].shortName, "DONT TOUCH ME") == 0) + continue; + + uint32_t highID = this->titles[i].highID; + uint32_t lowID = this->titles[i].lowID; + bool isWii = titles[i].is_Wii; + + std::string srcPath = getDynamicBackupPath(highID, lowID, 0); + + if (! isWii) { + std::string usersavePath = srcPath+"/"+getSDacc()[sduser].persistentID; + + if (! folderEmpty(usersavePath.c_str())) + this->titles[i].currentBackup.hasUserSavedata = true; + + std::string commonSavePath = srcPath+"/common"; + if (! folderEmpty(commonSavePath.c_str())) + this->titles[i].currentBackup.hasCommonSavedata = true; + + if ( sduser != -1 && common == false && ! this->titles[i].currentBackup.hasUserSavedata) + continue; + + // shouldn't happen for wii u titles, but ... + if ( sduser != -1 && ! this->titles[i].currentBackup.hasCommonSavedata && ! this->titles[i].currentBackup.hasUserSavedata ) + continue; + + this->titles[i].currentBackup.candidateToBeRestored = true; // backup has enough data to try restore + this->titles[i].currentBackup.selected = true; // from candidates list, user can select/deselest at wish +#ifdef TESTSAVEINIT + if (testForceSaveInitFalse) { // first title will have fake false saveinit + this->titles[i].saveInit = false; + testForceSaveInitFalse = false; + } +#endif + if ( ! this->titles[i].saveInit ) + this->titles[i].currentBackup.selected = false; // we discourage a restore to a not init titles + } + else + { + if (strcmp(this->titles[i].productCode, "OHBC") == 0) + continue; + this->titles[i].currentBackup.candidateToBeRestored = true; + this->titles[i].currentBackup.selected = true; + } + // to recover title from "candidate title" index + this->c2t.push_back(i); + this->titles[i].currentBackup.lastErrCode = 0; + + } + candidatesCount = (int) this->c2t.size(); +}; + +void BRTitleSelectState::updateC2t() +{ + int j = 0; + for (int i = 0; i < this->titlesCount; i++) { + if ( ! this->titles[i].currentBackup.candidateToBeRestored ) + continue; + c2t[j++]=i; + } +} + +void BRTitleSelectState::render() { + if (this->state == STATE_DO_SUBSTATE) { + if (this->subState == nullptr) { + OSFatal("SubState was null"); + } + this->subState->render(); + return; + } + if (this->state == STATE_BATCH_RESTORE_TITLE_SELECT) { + int nameVWiiOffset = 0; + if (! isWiiUBatchRestore) + nameVWiiOffset = 1; + + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Batch Restore - Select & Go")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0, 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), + (this->titleSort > 0) ? (this->sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); + if ((this->titles == nullptr) || (this->titlesCount == 0 || (this->candidatesCount == 0))) { + DrawUtils::endDraw(); + promptError(LanguageUtils::gettext("There are no titles matching selected filters.")); + this->noTitles = true; + DrawUtils::beginDraw(); + consolePrintPosAligned(8, 4, 1, LanguageUtils::gettext("No titles found")); + consolePrintPosAligned(17, 4, 1, LanguageUtils::gettext("Any Button: Back")); + return; + } + consolePrintPosAligned(39, 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), + (this->titleSort > 0) ? (this->sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); + std::string nxtAction; + std::string lastState; + for (int i = 0; i < MAX_TITLE_SHOW; i++) { + if (i + this->scroll < 0 || i + this->scroll >= (int) this->candidatesCount) + break; + bool isWii = this->titles[c2t[i + this->scroll]].is_Wii; + + DrawUtils::setFontColor(COLOR_LIST); + if ( this->titles[c2t[i + this->scroll]].currentBackup.selected) + consolePrintPos(M_OFF, i + 2,"\ue071"); + + if (this->titles[c2t[i + this->scroll]].currentBackup.selected && ! this->titles[c2t[i + this->scroll]].saveInit) { + DrawUtils::setFontColor(COLOR_LIST_SELECTED_NOSAVE); + consolePrintPos(M_OFF, i + 2,"\ue071"); + } + + if ( this->titles[c2t[i + this->scroll]].currentBackup.selected) + DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); + else + DrawUtils::setFontColorByCursor(COLOR_LIST_SKIPPED,COLOR_LIST_SKIPPED_AT_CURSOR,cursorPos,i); + + if (this->titles[c2t[i + this->scroll]].currentBackup.selected && ! this->titles[c2t[i + this->scroll]].saveInit) { + DrawUtils::setFontColorByCursor(COLOR_LIST_SELECTED_NOSAVE,COLOR_LIST_SELECTED_NOSAVE_AT_CURSOR,cursorPos,i); + } + if (strcmp(this->titles[c2t[i + this->scroll]].shortName, "DONT TOUCH ME") == 0) + DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); + if (this->titles[c2t[i + this->scroll]].currentBackup.batchRestoreState == KO) + DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); + if (this->titles[c2t[i + this->scroll]].currentBackup.batchRestoreState == OK) + DrawUtils::setFontColorByCursor(COLOR_LIST_RESTORE_SUCCESS,COLOR_LIST_RESTORE_SUCCESS_AT_CURSOR,cursorPos,i); + + switch (this->titles[c2t[i + this->scroll]].currentBackup.batchRestoreState) { + case NOT_TRIED : + lastState = ""; + nxtAction = this->titles[c2t[i + this->scroll]].currentBackup.selected ? LanguageUtils::gettext(">> Restore") : LanguageUtils::gettext(">> Skip"); + break; + case OK : + lastState = LanguageUtils::gettext("[OK]"); + nxtAction = LanguageUtils::gettext("|Restored|"); + break; + case ABORTED : + lastState = LanguageUtils::gettext("[AB]"); + nxtAction = this->titles[c2t[i + this->scroll]].currentBackup.selected ? LanguageUtils::gettext(">> Retry") : LanguageUtils::gettext(">> Skip"); + break; + case WR : + lastState = LanguageUtils::gettext("[WR]"); + nxtAction = this->titles[c2t[i + this->scroll]].currentBackup.selected ? LanguageUtils::gettext(">> Retry") : LanguageUtils::gettext(">> Skip"); + break; + case KO: + lastState = LanguageUtils::gettext("[KO]"); + nxtAction = this->titles[c2t[i + this->scroll]].currentBackup.selected ? LanguageUtils::gettext(">> Retry") : LanguageUtils::gettext(">> Skip"); + break; + default: + lastState = ""; + nxtAction = ""; + break; + } + + char shortName[32]; + for (int p=0;p<32;p++) + shortName[p] = this->titles[c2t[i + this->scroll]].shortName[p]; + shortName[31] = '\0'; + consolePrintPos(M_OFF + 3 + nameVWiiOffset, i + 2, " %s %s%s%s%s %s%s", + shortName, + this->titles[c2t[i + this->scroll]].isTitleOnUSB ? "(USB)" : "(NAND)", + this->titles[c2t[i + this->scroll]].isTitleDupe ? " [D]" : "", + (this->titles[c2t[i + this->scroll]].noFwImg && ! this->titles[c2t[i + this->scroll]].is_Wii) ? " [vWiiInject]" : "", + this->titles[c2t[i + this->scroll]].saveInit ? "" : " [No Init]", + lastState.c_str(), + nxtAction.c_str()); + if (this->titles[c2t[i + this->scroll]].iconBuf != nullptr) { + if (isWii) + DrawUtils::drawRGB5A3((M_OFF + 6) * 12, (i + 3) * 24 + 8, 0.25, + titles[c2t[i + this->scroll]].iconBuf); + else + DrawUtils::drawTGA((M_OFF + 7) * 12 - 5, (i + 3) * 24 + 4, 0.18, this->titles[c2t[i + this->scroll]].iconBuf); + } + } + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(-1, 2 + cursorPos, "\u2192"); + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back")); + } +} + +ApplicationState::eSubState BRTitleSelectState::update(Input *input) { + if (this->state == STATE_BATCH_RESTORE_TITLE_SELECT) { + if (input->get(TRIGGER, PAD_BUTTON_B) || noTitles) + return SUBSTATE_RETURN; + if (input->get(TRIGGER, PAD_BUTTON_R)) { + this->titleSort = (this->titleSort + 1) % 4; + sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); + this->updateC2t(); + } + if (input->get(TRIGGER, PAD_BUTTON_L)) { + if (this->titleSort > 0) { + this->sortAscending = !this->sortAscending; + sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); + this->updateC2t(); + } + } + if (input->get(TRIGGER, PAD_BUTTON_A)) { + char summary[512]; + const char* summaryTemplate; + char usermsg[128]; + if (isWiiUBatchRestore) { + summaryTemplate = LanguageUtils::gettext("You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n"); + if (sduser > - 1) { + snprintf(usermsg,64,LanguageUtils::gettext("- Restore from %s to < %s (%s) >"),getSDacc()[sduser].persistentID,getWiiUacc()[wiiuuser].miiName,getWiiUacc()[wiiuuser].persistentID); + } + snprintf(summary,512,summaryTemplate, + (sduser == -1) ? LanguageUtils::gettext("- Restore allusers") : usermsg, + (common || sduser == -1 ) ? LanguageUtils::gettext("- Include common savedata: Y") : LanguageUtils::gettext("- Include common savedata: N"), + wipeBeforeRestore ? LanguageUtils::gettext("- Wipe data: Y") : LanguageUtils::gettext("- Wipe data: N"), + fullBackup ? LanguageUtils::gettext("- Perform full backup: Y") : LanguageUtils::gettext("- Perform full backup: N")); + } else { + summaryTemplate = LanguageUtils::gettext("You have selected the following options:\n%s\n%s.\nContinue?\n\n"); + snprintf(summary,512,summaryTemplate, + wipeBeforeRestore ? LanguageUtils::gettext("- Wipe data: Y") : LanguageUtils::gettext("- Wipe data: N"), + fullBackup ? LanguageUtils::gettext("- Perform full backup: Y") : LanguageUtils::gettext("- Perform full backup: N")); + } + + if (!promptConfirm(ST_WARNING,summary)) { + DrawUtils::setRedraw(true); + return SUBSTATE_RUNNING; + } + + for (int i = 0; i < titlesCount ; i++) { + if (! this->titles[i].currentBackup.selected ) + continue; + if (! this->titles[i].saveInit) { + if (!promptConfirm(ST_ERROR, LanguageUtils::gettext("You have selected uninitialized titles (not recommended). Are you 100%% sure?"))) { + DrawUtils::setRedraw(true); + return SUBSTATE_RUNNING; + } + break; + } + } + + if ( fullBackup ) { + const std::string batchDatetime = getNowDateForFolder(); + backupAllSave(this->titles, this->titlesCount, batchDatetime, true); + if(isWiiUBatchRestore) + writeBackupAllMetadata(batchDatetime,LanguageUtils::gettext("pre-BatchRestore Backup (WiiU)")); + else + writeBackupAllMetadata(batchDatetime,LanguageUtils::gettext("pre-BatchRestore Backup (vWii)")); + BackupSetList::setIsInitializationRequired(true); + } + + int retCode = 0; + + for (int i = 0; i < titlesCount ; i++) { + if (! this->titles[i].currentBackup.selected ) + continue; + this->titles[i].currentBackup.batchRestoreState = OK; + bool effectiveCommon = common && this->titles[i].currentBackup.hasCommonSavedata; + if ( wipeBeforeRestore ) { + if (sduser != -1) { + if ( ! this->titles[i].currentBackup.hasUserSavedata && effectiveCommon) { // if sduser does not exist, don't try to wipe wiiuser, but only common + // -2 is a flag just to only operate on common saves (because sd user does not exist for this title) + retCode = wipeSavedata(&this->titles[i], -2, effectiveCommon, false); + if (retCode > 0) + this->titles[i].currentBackup.batchRestoreState = WR; + else if (retCode < 0) + this->titles[i].currentBackup.batchRestoreState = ABORTED; + goto wipeDone; + } + } + + retCode = wipeSavedata(&this->titles[i], wiiuuser, effectiveCommon, false); + if (retCode > 0) + this->titles[i].currentBackup.batchRestoreState = WR; + } + + wipeDone: + int globalRetCode = retCode<<8; + if (sduser != -1) { + if ( ! this->titles[i].currentBackup.hasUserSavedata && effectiveCommon) { + // -2 is a flag just to only operate on common saves (because sd user does not exist for this title) + retCode = restoreSavedata(&this->titles[i], 0, -2 , wiiuuser, effectiveCommon, false); + if (retCode > 0) + this->titles[i].currentBackup.batchRestoreState = KO; + goto restoreDone; + } + } + retCode = restoreSavedata(&this->titles[i], 0, sduser, wiiuuser, effectiveCommon, false); //always from slot 0 + if (retCode > 0) + this->titles[i].currentBackup.batchRestoreState = KO; + + restoreDone: + if (this->titles[i].currentBackup.batchRestoreState == OK || this->titles[i].currentBackup.batchRestoreState == WR ) + this->titles[i].currentBackup.selected = false; + + globalRetCode = globalRetCode + retCode; + this->titles[i].currentBackup.lastErrCode = globalRetCode; + } + + int titlesOK = 0; + int titlesAborted = 0; + int titlesWarning = 0; + int titlesKO = 0; + int titlesSkipped = 0; + for (int i = 0; i < this->candidatesCount ; i++) { + switch (this->titles[c2t[i]].currentBackup.batchRestoreState) { + case OK : + titlesOK++; + break; + case WR : + titlesWarning++; + break; + case KO: + titlesKO++; + break; + case ABORTED : + titlesAborted++; + break; + default: + titlesSkipped++; + break; + } + } + summaryTemplate = LanguageUtils::gettext("Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n"); + snprintf(summary,512,summaryTemplate,titlesOK,titlesWarning,titlesKO,titlesAborted,titlesSkipped); + promptMessage(COLOR_BG_SUCCESS,summary); + + DrawUtils::beginDraw(); + DrawUtils::clear(COLOR_BACKGROUND); + DrawUtils::endDraw(); + DrawUtils::setRedraw(true); + return SUBSTATE_RUNNING; + } + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { + if (this->candidatesCount <= 14) + cursorPos = (cursorPos + 1) % this->candidatesCount; + else if (cursorPos < 6) + cursorPos++; + else if (((cursorPos + this->scroll + 1) % this->candidatesCount) != 0) + scroll++; + else + cursorPos = scroll = 0; + } else if (input->get(TRIGGER, PAD_BUTTON_UP)) { + if (scroll > 0) + cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); + else if (cursorPos > 0) + cursorPos--; + else if (this->candidatesCount > 14) + scroll = this->candidatesCount - (cursorPos = 6) - 1; + else + cursorPos = this->candidatesCount - 1; + } + if (input->get(TRIGGER, PAD_BUTTON_Y) || input->get(TRIGGER, PAD_BUTTON_RIGHT) || input->get(TRIGGER, PAD_BUTTON_LEFT)) { + if (this->titles[c2t[cursorPos + this->scroll]].currentBackup.batchRestoreState != OK) + this->titles[c2t[cursorPos + this->scroll]].currentBackup.selected = this->titles[c2t[cursorPos + this->scroll]].currentBackup.selected ? false:true; + else + return SUBSTATE_RUNNING; + } + } else if (this->state == STATE_DO_SUBSTATE) { + auto retSubState = this->subState->update(input); + if (retSubState == SUBSTATE_RUNNING) { + // keep running. + return SUBSTATE_RUNNING; + } else if (retSubState == SUBSTATE_RETURN) { + this->subState.reset(); + this->state = STATE_BATCH_RESTORE_TITLE_SELECT; + } + } + return SUBSTATE_RUNNING; +} \ No newline at end of file diff --git a/src/menu/BackupSetListFilter.cpp b/src/menu/BackupSetListFilter.cpp new file mode 100644 index 0000000..8e9e41a --- /dev/null +++ b/src/menu/BackupSetListFilter.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void BackupSetListFilterState::render() { + if (this->state == STATE_BACKUPSET_FILTER) { + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0,4,1,"Filter BackupSets"); + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPos(0,4,LanguageUtils::gettext("Show only BackupSets satisfying all these conditions:")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(M_OFF, 6, "Console: %s", (*backupSetList->bsMetadataValues.serialId.iterator).c_str()); + consolePrintPos(M_OFF, 7, "Tag: %s", (*backupSetList->bsMetadataValues.tag.iterator).c_str()); + consolePrintPos(M_OFF, 8, "Month: %s", (*backupSetList->bsMetadataValues.month.iterator).c_str()); + consolePrintPos(M_OFF, 9, "Year: %s", (*backupSetList->bsMetadataValues.year.iterator).c_str()); + consolePrintPos(-1, 6 + cursorPos, "\u2192"); + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Apply Filter \uE002: Reset Filters \ue001: Back")); + + } +} + +ApplicationState::eSubState BackupSetListFilterState::update(Input *input) { + if (input->get(TRIGGER, PAD_BUTTON_B)) { + return SUBSTATE_RETURN; + } + if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { + switch (cursorPos) { + case 0: + BSMetadataValues::Left(backupSetList->bsMetadataValues.serialId); + break; + case 1: + BSMetadataValues::Left(backupSetList->bsMetadataValues.tag); + break; + case 2: + BSMetadataValues::Left(backupSetList->bsMetadataValues.month); + break; + case 3: + BSMetadataValues::Left(backupSetList->bsMetadataValues.year); + break; + default: + break; + } + } + if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { + switch (cursorPos) { + case 0: + BSMetadataValues::Right(backupSetList->bsMetadataValues.serialId); + break; + case 1: + BSMetadataValues::Right(backupSetList->bsMetadataValues.tag); + break; + case 2: + BSMetadataValues::Right(backupSetList->bsMetadataValues.month); + break; + case 3: + BSMetadataValues::Right(backupSetList->bsMetadataValues.year); + break; + default: + break; + } + } + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { + if (entrycount <= 14) + cursorPos = (cursorPos + 1) % entrycount; + } + if (input->get(TRIGGER, PAD_BUTTON_UP)) { + if (cursorPos > 0) + --cursorPos; + } + if (input->get(TRIGGER, PAD_BUTTON_A)) { + backupSetList->filter(); + backupSetList->sort(BackupSetList::getSortAscending()); + BackupSetListState::resetCursorAndScroll(); + return SUBSTATE_RETURN; + } + if (input->get(TRIGGER,PAD_BUTTON_X)) { + backupSetList->bsMetadataValues.resetFilter(); + } + return SUBSTATE_RUNNING; +} \ No newline at end of file diff --git a/src/menu/BackupSetListState.cpp b/src/menu/BackupSetListState.cpp index eaf2b0d..546e708 100644 --- a/src/menu/BackupSetListState.cpp +++ b/src/menu/BackupSetListState.cpp @@ -1,21 +1,34 @@ #include +#include +#include +#include +#include +#include #include #include #include #include -#include +#include #define MAX_ROWS_SHOW 14 -static int cursorPos = 0; -static int scroll = 0; +int BackupSetListState::cursorPos = 0; +int BackupSetListState::scroll = 0; static std::string language; BackupSetListState::BackupSetListState() { - this->sortAscending = BackupSetList::sortAscending; + finalScreen = true; + this->sortAscending = BackupSetList::sortAscending; +} + +BackupSetListState::BackupSetListState(Title *titles, int titlesCount, bool isWiiUBatchRestore) : + titles(titles), + titlesCount(titlesCount), + isWiiUBatchRestore(isWiiUBatchRestore) { + finalScreen = false; } -void BackupSetListState::resetCursorPosition() { // after batch Backup +void BackupSetListState::resetCursorPosition() { // if bslist is modified after a new batch Backup if ( cursorPos == 0 ) return; if (BackupSetList::sortAscending) { @@ -26,70 +39,179 @@ void BackupSetListState::resetCursorPosition() { // after batch Backup } } +void BackupSetListState::resetCursorAndScroll() { // if we apply a new filter + cursorPos=0; + scroll=0; +} + void BackupSetListState::render() { + if (this->state == STATE_DO_SUBSTATE) { + if (this->subState == nullptr) { + OSFatal("SubState was null"); + } + this->subState->render(); + return; + } + if (this->state == STATE_BACKUPSET_MENU) { + std::string backupSetItem; + DrawUtils::setFontColor(COLOR_INFO); + if (BackupSetList::currentBackupSetList->entriesView == BackupSetList::currentBackupSetList->entries) { + consolePrintPosAligned(0, 4, 1, LanguageUtils::gettext("BackupSets")); + } else { + consolePrintPosAligned(0, 4, 1, LanguageUtils::gettext("BackupSets (filter applied)")); + } + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0,4,2, LanguageUtils::gettext("\ue083 Sort: %s \ue084"), + this->sortAscending ? "\u2191" : "\u2193"); + for (int i = 0; i < MAX_ROWS_SHOW; i++) { + if (i + scroll < 0 || i + scroll >= BackupSetList::currentBackupSetList->entriesView) + break; + backupSetItem = BackupSetList::currentBackupSetList->at(i + scroll); + - std::string backupSetItem; - consolePrintPos(44, 0, LanguageUtils::gettext("\ue083 Sort: %s \ue084"), - this->sortAscending ? "\u2191" : "\u2193"); - for (int i = 0; i < MAX_ROWS_SHOW; i++) { - if (i + scroll < 0 || i + scroll >= BackupSetList::currentBackupSetList->entries) - break; - backupSetItem = BackupSetList::currentBackupSetList->at(i + scroll); - DrawUtils::setFontColor(COLOR_LIST); - if ( backupSetItem == BackupSetList::ROOT_BS) - DrawUtils::setFontColor(COLOR_LIST_HIGH); - if ( backupSetItem == BackupSetList::getBackupSetEntry()) - DrawUtils::setFontColor(COLOR_INFO); - consolePrintPos(M_OFF, i + 2, " %s", backupSetItem.c_str()); + DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); + + DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); + if ( backupSetItem == BackupSetList::ROOT_BS) + DrawUtils::setFontColorByCursor(COLOR_LIST_HIGH,COLOR_LIST_HIGH_AT_CURSOR,cursorPos,i); + if ( backupSetItem == BackupSetList::getBackupSetEntry()) + DrawUtils::setFontColorByCursor(COLOR_CURRENT_BS,COLOR_CURRENT_BS_AT_CURSOR,cursorPos,i); + + consolePrintPos(M_OFF-1, i + 2, " %s", backupSetItem.substr(0,15).c_str()); + consolePrintPos(21, i+2,"%s", BackupSetList::currentBackupSetList->getStretchedSerialIdAt(i+scroll).c_str()); + consolePrintPos(33, i+2,"%s", BackupSetList::currentBackupSetList->getTagAt(i+scroll).c_str()); } - DrawUtils::setFontColor(COLOR_TEXT); - consolePrintPos(-1, 2 + cursorPos, "\u2192"); - consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select BackupSet \ue001: Back")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(-1, 2 + cursorPos, "\u2192"); + if (cursorPos + scroll > 0) + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back")); + else + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select BackupSet \ue003: Filter List \ue001: Back")); + } } ApplicationState::eSubState BackupSetListState::update(Input *input) { - if (input->get(TRIGGER, PAD_BUTTON_B)) - return SUBSTATE_RETURN; - if (input->get(TRIGGER, PAD_BUTTON_A)) { - BackupSetList::setBackupSetEntry(cursorPos + scroll); - BackupSetList::setBackupSetSubPath(); - DrawUtils::setRedraw(true); - return SUBSTATE_RETURN; - } - if (input->get(TRIGGER, PAD_BUTTON_L)) { - if ( this->sortAscending ) { - this->sortAscending = false; - BackupSetList::currentBackupSetList->sort(this->sortAscending); - cursorPos = 0; - scroll = 0; + if (this->state == STATE_BACKUPSET_MENU) { + if (input->get(TRIGGER, PAD_BUTTON_B)) + return SUBSTATE_RETURN; + if (input->get(TRIGGER, PAD_BUTTON_A)) { + if (! finalScreen) { + if (cursorPos + scroll == 0) { + promptError(LanguageUtils::gettext("Root BackupSet cannot be selected for batchRestore")); + return SUBSTATE_RUNNING; + } + } + BackupSetList::setBackupSetEntry(cursorPos + scroll); + BackupSetList::setBackupSetSubPath(); + DrawUtils::setRedraw(true); + if (finalScreen) + return SUBSTATE_RETURN; + else // is a step in batchRestore + { + this->state = STATE_DO_SUBSTATE; + this->subState = std::make_unique(titles, titlesCount, isWiiUBatchRestore); + } } - } - if (input->get(TRIGGER, PAD_BUTTON_R)) { - if ( ! this->sortAscending ) { - this->sortAscending = true; - BackupSetList::currentBackupSetList->sort(this->sortAscending); - cursorPos = 0; - scroll = 0; + if (input->get(TRIGGER, PAD_BUTTON_Y)) { + this->state = STATE_DO_SUBSTATE; + this->substateCalled = STATE_BACKUPSET_FILTER; + this->subState = std::make_unique(BackupSetList::currentBackupSetList); + } + if (input->get(TRIGGER, PAD_BUTTON_L)) { + if ( this->sortAscending ) { + this->sortAscending = false; + BackupSetList::currentBackupSetList->sort(this->sortAscending); + cursorPos = 0; + scroll = 0; + } + } + if (input->get(TRIGGER, PAD_BUTTON_R)) { + if ( ! this->sortAscending ) { + this->sortAscending = true; + BackupSetList::currentBackupSetList->sort(this->sortAscending); + cursorPos = 0; + scroll = 0; + } + } + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { + if (BackupSetList::currentBackupSetList->entriesView <= MAX_ROWS_SHOW) + cursorPos = (cursorPos + 1) % BackupSetList::currentBackupSetList->entriesView; + else if (cursorPos < 6) + cursorPos++; + else if (((cursorPos + scroll + 1) % BackupSetList::currentBackupSetList->entriesView) != 0) + scroll++; + else + cursorPos = scroll = 0; + tag = BackupSetList::currentBackupSetList->getTagAt(cursorPos+scroll); + newTag = tag; + } + if (input->get(TRIGGER, PAD_BUTTON_UP)) { + if (scroll > 0) + cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); + else if (cursorPos > 0) + cursorPos--; + else if (BackupSetList::currentBackupSetList->entriesView > MAX_ROWS_SHOW) + scroll = BackupSetList::currentBackupSetList->entriesView - (cursorPos = 6) - 1; + else + cursorPos = BackupSetList::currentBackupSetList->entriesView - 1; + tag = BackupSetList::currentBackupSetList->getTagAt(cursorPos+scroll); + newTag = tag; + } + if (input->get(TRIGGER, PAD_BUTTON_MINUS)) { + int entry = cursorPos+scroll; + if (entry > 0) + { + if (BackupSetList::getBackupSetSubPath() == BackupSetList::getBackupSetSubPath(entry)) + { + BackupSetList::setBackupSetEntry(entry-1); + BackupSetList::setBackupSetSubPath(); + } + if ( wipeBackupSet(BackupSetList::getBackupSetSubPath(entry))) + { + BackupSetList::initBackupSetList(); + cursorPos--; + } + DrawUtils::setRedraw(true); + } + } + if (input->get(TRIGGER, PAD_BUTTON_PLUS)) { + int entry = cursorPos+scroll; + if (entry > 0) + { + this->state = STATE_DO_SUBSTATE; + this->substateCalled = STATE_KEYBOARD; + this->subState = std::make_unique(newTag); + } + } + } else if (this->state == STATE_DO_SUBSTATE) { + auto retSubState = this->subState->update(input); + if (retSubState == SUBSTATE_RUNNING) { + // keep running. + return SUBSTATE_RUNNING; + } else if (retSubState == SUBSTATE_RETURN) { + if (this->substateCalled == STATE_KEYBOARD) { + if ( tag != newTag ) { + std::string entryPath = BackupSetList::currentBackupSetList->at(cursorPos + scroll); + Metadata *metadataObj = new Metadata(getBatchBackupPathRoot(entryPath)); + metadataObj->read(); + metadataObj->setTag(newTag); + metadataObj->write(); + BackupSetList::currentBackupSetList->setTagBSVAt(cursorPos + scroll,newTag); + BackupSetList::currentBackupSetList->setTagBSAt(BackupSetList::currentBackupSetList->v2b[cursorPos + scroll],newTag); + if (newTag != "") + BackupSetList::currentBackupSetList->resetTagRange(); + delete metadataObj; + } + } + if (BackupSetList::getIsInitializationRequired() ) { + BackupSetList::initBackupSetList(); + BackupSetListState::resetCursorPosition(); + BackupSetList::setIsInitializationRequired(false); + } + this->subState.reset(); + this->state = STATE_BACKUPSET_MENU; + this->substateCalled = NONE; } - } - if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { - if (BackupSetList::currentBackupSetList->entries <= MAX_ROWS_SHOW) - cursorPos = (cursorPos + 1) % BackupSetList::currentBackupSetList->entries; - else if (cursorPos < 6) - cursorPos++; - else if (((cursorPos + scroll + 1) % BackupSetList::currentBackupSetList->entries) != 0) - scroll++; - else - cursorPos = scroll = 0; - } else if (input->get(TRIGGER, PAD_BUTTON_UP)) { - if (scroll > 0) - cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); - else if (cursorPos > 0) - cursorPos--; - else if (BackupSetList::currentBackupSetList->entries > MAX_ROWS_SHOW) - scroll = BackupSetList::currentBackupSetList->entries - (cursorPos = 6) - 1; - else - cursorPos = BackupSetList::currentBackupSetList->entries - 1; } return SUBSTATE_RUNNING; } \ No newline at end of file diff --git a/src/menu/BatchBackupState.cpp b/src/menu/BatchBackupState.cpp index 840a312..cab9f3b 100644 --- a/src/menu/BatchBackupState.cpp +++ b/src/menu/BatchBackupState.cpp @@ -13,12 +13,18 @@ static int cursorPos = 0; void BatchBackupState::render() { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Batch Backup")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Backup All (%u Title%s)"), this->wiiuTitlesCount + this->vWiiTitlesCount, ((this->wiiuTitlesCount + this->vWiiTitlesCount) > 1) ? "s" : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" Backup Wii U (%u Title%s)"), this->wiiuTitlesCount, (this->wiiuTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Backup vWii (%u Title%s)"), this->vWiiTitlesCount, (this->vWiiTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2 + cursorPos, "\u2192"); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Backup \ue001: Back")); } @@ -38,12 +44,15 @@ ApplicationState::eSubState BatchBackupState::update(Input *input) { case 0: backupAllSave(this->wiiutitles, this->wiiuTitlesCount, batchDatetime); backupAllSave(this->wiititles, this->vWiiTitlesCount, batchDatetime); + writeBackupAllMetadata(batchDatetime,"WiiU and vWii titles"); break; case 1: backupAllSave(this->wiiutitles, this->wiiuTitlesCount, batchDatetime); + writeBackupAllMetadata(batchDatetime,"WiiU titles"); break; case 2: backupAllSave(this->wiititles, this->vWiiTitlesCount, batchDatetime); + writeBackupAllMetadata(batchDatetime,"vWii titles"); break; default: return SUBSTATE_RETURN; diff --git a/src/menu/BatchRestoreOptions.cpp b/src/menu/BatchRestoreOptions.cpp new file mode 100644 index 0000000..5898335 --- /dev/null +++ b/src/menu/BatchRestoreOptions.cpp @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#ifdef DEBUG +#include +#include +#endif + +#define ENTRYCOUNT 5 + +extern Account *sdacc; +extern uint8_t sdaccn; + +BatchRestoreOptions::BatchRestoreOptions(Title *titles, + int titlesCount,bool isWiiUBatchRestore) : titles(titles), + titlesCount(titlesCount), isWiiUBatchRestore(isWiiUBatchRestore) { + minCursorPos = isWiiUBatchRestore ? 0 : 3; + cursorPos = minCursorPos; + for (int i = 0; ititlesCount; i++) { + this->titles[i].currentBackup= { + .hasBatchBackup = false, + .candidateToBeRestored = false, + .selected = false, + .hasUserSavedata = false, + .hasCommonSavedata = false, + .batchRestoreState = NOT_TRIED + }; + if (this->titles[i].highID == 0 || this->titles[i].lowID == 0) + continue; + //if (! this->titles[i].saveInit) // we allow uninitializedTitles + // continue; + if (this->titles[i].isTitleDupe && ! this->titles[i].isTitleOnUSB) + continue; + if (strcmp(this->titles[i].shortName, "DONT TOUCH ME") == 0) // skip CBHC savedata + continue; + if (this->titles[i].is_Wii && isWiiUBatchRestore) // wii titles installed as wiiU appear in vWii restore + continue; + uint32_t highID = this->titles[i].highID; + uint32_t lowID = this->titles[i].lowID; + std::string srcPath = getDynamicBackupPath(highID, lowID, 0); + DIR *dir = opendir(srcPath.c_str()); + if (dir != nullptr) { + if (isWiiUBatchRestore) { + struct dirent *data; + while ((data = readdir(dir)) != nullptr) { + if(strcmp(data->d_name,".") == 0 || strcmp(data->d_name,"..") == 0 || ! (data->d_type & DT_DIR)) + continue; + if (data->d_name[0] == '8') + batchSDUsers.insert(data->d_name); + this->titles[i].currentBackup.hasBatchBackup=true; + } + } else { + this->titles[i].currentBackup.hasBatchBackup = ! folderEmpty (srcPath.c_str()); + } + + } + closedir(dir); + } + + if (sdacc != nullptr) + free(sdacc); + sdaccn = batchSDUsers.size(); + + int i=0; + sdacc = (Account *) malloc(sdaccn * sizeof(Account)); + for ( auto user : batchSDUsers ) { + strcpy(sdacc[i].persistentID,user.substr(0,8).c_str()); + sdacc[i].pID = strtoul(user.c_str(), nullptr, 16); + sdacc[i].slot = i; + i++; + } +} + +void BatchRestoreOptions::render() { + if (this->state == STATE_DO_SUBSTATE) { + if (this->subState == nullptr) { + OSFatal("SubState was null"); + } + this->subState->render(); + return; + } + + if (this->state == STATE_BATCH_RESTORE_OPTIONS_MENU) { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPos(16,0, LanguageUtils::gettext("BatchRestore - Options")); + DrawUtils::setFontColor(COLOR_INFO_AT_CURSOR); + consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("BS: %s"),BackupSetList::getBackupSetEntry().c_str()); + DrawUtils::setFontColor(COLOR_TEXT); + if (isWiiUBatchRestore) { + consolePrintPos(M_OFF, 3, LanguageUtils::gettext("Select SD user to copy from:")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); + if (sduser == -1) + consolePrintPos(M_OFF, 4, " < %s >", LanguageUtils::gettext("all users")); + else + consolePrintPos(M_OFF, 4, " < %s >", getSDacc()[sduser].persistentID); + + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(M_OFF, 6 , LanguageUtils::gettext("Select Wii U user to copy to")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); + if (this->wiiuuser == -1) + consolePrintPos(M_OFF, 7, " < %s >", LanguageUtils::gettext("same user than in source")); + else + consolePrintPos(M_OFF, 7, " < %s (%s) >", + getWiiUacc()[wiiuuser].miiName, getWiiUacc()[wiiuuser].persistentID); + + if (this->wiiuuser > -1) { + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(M_OFF, 9, LanguageUtils::gettext("Include 'common' save?")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); + consolePrintPos(M_OFF, 10, " < %s >", common ? LanguageUtils::gettext("yes") : LanguageUtils::gettext("no ")); + } + } + + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); + consolePrintPos(M_OFF, 12 - (isWiiUBatchRestore ? 0 : 8) , LanguageUtils::gettext(" Wipe target users savedata before restoring: < %s >"), wipeBeforeRestore ? LanguageUtils::gettext("Yes") : LanguageUtils::gettext("No")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); + consolePrintPos(M_OFF, 14 - (isWiiUBatchRestore ? 0 : 8), LanguageUtils::gettext(" Backup all data before restoring (strongly recommended): < %s >"), fullBackup ? LanguageUtils::gettext("Yes"):LanguageUtils::gettext("No")); + + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(M_OFF, 4 + (cursorPos < 3 ? cursorPos * 3 : 3+(cursorPos-3)*2 + 5) - (isWiiUBatchRestore ? 0 : 8), "\u2192"); + + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Ok! Go to Title selection \ue001: Back")); + } +} + +ApplicationState::eSubState BatchRestoreOptions::update(Input *input) { + if (this->state == STATE_BATCH_RESTORE_OPTIONS_MENU) { + if (input->get(TRIGGER, PAD_BUTTON_A)) { + this->state = STATE_DO_SUBSTATE; + this->subState = std::make_unique(sduser, wiiuuser, common, wipeBeforeRestore, fullBackup, this->titles, this->titlesCount, isWiiUBatchRestore); + } + if (input->get(TRIGGER, PAD_BUTTON_B)) + return SUBSTATE_RETURN; + if (input->get(TRIGGER, PAD_BUTTON_X)) { + this->state = STATE_DO_SUBSTATE; + } + if (input->get(TRIGGER, PAD_BUTTON_UP)) { + if (--cursorPos < minCursorPos) + ++cursorPos; + if (cursorPos == 2 && sduser == -1 ) + --cursorPos; + } + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { + if (++cursorPos == ENTRYCOUNT) + --cursorPos; + if (cursorPos == 2 && sduser == -1 ) + ++cursorPos; + } + if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { + switch (cursorPos) { + case 0: + sduser = ((sduser == -1) ? -1 : (sduser - 1)); + this->wiiuuser = ((sduser == -1) ? -1 : this->wiiuuser); + break; + case 1: + wiiuuser = (((wiiuuser == -1) || (sduser == -1)) ? -1 : (wiiuuser - 1)); + wiiuuser = ((sduser > -1) && (wiiuuser == -1)) ? 0 : wiiuuser; + break; + case 2: + common = common ? false : true; + break; + case 3: + wipeBeforeRestore = wipeBeforeRestore ? false : true; + break; + case 4: + fullBackup = fullBackup ? false : true; + break; + default: + break; + } + } + if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { + switch (cursorPos) { + case 0: + sduser = ((sduser == (getSDaccn() - 1)) ? (getSDaccn() - 1) : (sduser + 1)); + wiiuuser = ((sduser > -1) && (wiiuuser == -1)) ? 0 : wiiuuser; + break; + case 1: + wiiuuser = ((wiiuuser == (getWiiUaccn() - 1)) ? (getWiiUaccn() - 1) : (wiiuuser + 1)); + wiiuuser = (sduser == -1) ? -1 : wiiuuser; + break; + case 2: + common = common ? false : true; + break; + case 3: + wipeBeforeRestore = wipeBeforeRestore ? false : true; + break; + case 4: + fullBackup = fullBackup ? false : true; + break; + default: + break; + } + } + } else if (this->state == STATE_DO_SUBSTATE) { + auto retSubState = this->subState->update(input); + if (retSubState == SUBSTATE_RUNNING) { + // keep running. + return SUBSTATE_RUNNING; + } else if (retSubState == SUBSTATE_RETURN) { + this->subState.reset(); + this->state = STATE_BATCH_RESTORE_OPTIONS_MENU; + } + } + return SUBSTATE_RUNNING; +} \ No newline at end of file diff --git a/src/menu/BatchRestoreState.cpp b/src/menu/BatchRestoreState.cpp new file mode 100644 index 0000000..ed3f282 --- /dev/null +++ b/src/menu/BatchRestoreState.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +#include +#include + +#define ENTRYCOUNT 2 + +static int cursorPos = 0; + +void BatchRestoreState::render() { + if (this->state == STATE_DO_SUBSTATE) { + if (this->subState == nullptr) { + OSFatal("SubState was null"); + } + this->subState->render(); + return; + } + if (this->state == STATE_BATCH_RESTORE_MENU) { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Batch Restore")); + DrawUtils::setFontColor(COLOR_TEXT); + + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); + consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" Restore Wii U (%u Title%s)"), this->wiiuTitlesCount, + (this->wiiuTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); + consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Restore vWii (%u Title%s)"), this->vWiiTitlesCount, + (this->vWiiTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(M_OFF, 3 + cursorPos, "\u2192"); + DrawUtils::setFontColor(COLOR_INFO); + 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.")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Continue to batch restore \ue001: Back")); + } +} + +ApplicationState::eSubState BatchRestoreState::update(Input *input) { + if (this->state == STATE_BATCH_RESTORE_MENU) { + if (input->get(TRIGGER, PAD_BUTTON_A)) { + const std::string batchDatetime = getNowDateForFolder(); + switch (cursorPos) { + case 0: + this->state = STATE_DO_SUBSTATE; + this->subState = std::make_unique(this->wiiutitles, this->wiiuTitlesCount, true); + break; + case 1: + this->state = STATE_DO_SUBSTATE; + this->subState = std::make_unique(this->wiititles, this->vWiiTitlesCount, false); + break; + default: + return SUBSTATE_RUNNING; + } + } + if (input->get(TRIGGER, PAD_BUTTON_B)) + return SUBSTATE_RETURN; + if (input->get(TRIGGER, PAD_BUTTON_UP)) + if (--cursorPos == -1) + ++cursorPos; + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) + if (++cursorPos == ENTRYCOUNT) + --cursorPos; + } else if (this->state == STATE_DO_SUBSTATE) { + auto retSubState = this->subState->update(input); + if (retSubState == SUBSTATE_RUNNING) { + // keep running. + return SUBSTATE_RUNNING; + } else if (retSubState == SUBSTATE_RETURN) { + this->subState.reset(); + this->state = STATE_BATCH_RESTORE_MENU; + } + } + return SUBSTATE_RUNNING; +} \ No newline at end of file diff --git a/src/menu/ConfigMenuState.cpp b/src/menu/ConfigMenuState.cpp index bbd0d6a..2beea72 100644 --- a/src/menu/ConfigMenuState.cpp +++ b/src/menu/ConfigMenuState.cpp @@ -2,14 +2,24 @@ #include #include #include +#include +#include static int cursorPos = 0; static std::string language; void ConfigMenuState::render() { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Configuration Options")); + DrawUtils::setFontColor(COLOR_TEXT); language = LanguageUtils::getLoadedLanguage(); consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Language: %s"), language.c_str()); + + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPos(M_OFF + 2, 8,LanguageUtils::gettext("WiiU Serial Id: %s"),Metadata::thisConsoleSerialId.c_str()); + + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2 + cursorPos, "\u2192"); consolePrintPosAligned(17,4,2,LanguageUtils::gettext("\ue001: Back")); } diff --git a/src/menu/KeyboardState.cpp b/src/menu/KeyboardState.cpp new file mode 100644 index 0000000..2fea9db --- /dev/null +++ b/src/menu/KeyboardState.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define KB_X_OFFSET 2 +#define KB_Y_OFFSET 3 +#define KB_ROW_OFFSET 6 + +void KeyboardState::render() { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Keyboard")); + DrawUtils::setFontColor(COLOR_TEXT); + if (this->state == STATE_KEYBOARD) { + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0,4,1,"Keyboard"); + + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(3,0,1,("["+keyboard->input+"]").c_str()); + DrawUtils::setFontColor(COLOR_TEXT); + DrawUtils::setFont(); //was kFont + for (int row_=0;row_<4;row_++) + for (int column_=0;column_getKeyboardRowSize(row_);column_++) { + kConsolePrintPos(KB_X_OFFSET+column_,KB_Y_OFFSET+row_,KB_ROW_OFFSET*row_, "%s", keyboard->getKey(row_,column_).c_str()); + DrawUtils::drawKey(KB_X_OFFSET+column_,KB_Y_OFFSET+row_,KB_ROW_OFFSET*row_,COLOR_WHITE); + } + DrawUtils::setFontColor(COLOR_KEY_S); + kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET-3,"%s", keyboard->getCurrentKey().c_str()); + kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET+3,"%s", keyboard->getCurrentKey().c_str()); + DrawUtils::setFontColor(COLOR_KEY); + kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET,"%s", keyboard->getCurrentKey().c_str()); + DrawUtils::drawKey(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET,COLOR_KEY_C); + DrawUtils::setFontColor(COLOR_TEXT); + DrawUtils::setFont(); + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back")); + } +} + +ApplicationState::eSubState KeyboardState::update(Input *input) { + if (input->get(TRIGGER, PAD_BUTTON_B)) { + return SUBSTATE_RETURN; + } + if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { + cursorPosX = keyboard->kbLeft(); + } + if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { + cursorPosX = keyboard->kbRight(); + } + if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { + cursorPosY = keyboard->kbDown(); + cursorPosX = keyboard->getColumn(); + } + if (input->get(TRIGGER, PAD_BUTTON_UP)) { + cursorPosY = keyboard->kbUp(); + cursorPosX = keyboard->getColumn(); + } + if (input->get(TRIGGER, PAD_BUTTON_A)) { + keyboard->kbKeyPressed(); + } + if (input->get(TRIGGER,PAD_BUTTON_X)) { + keyboard->delPressed(); + } + if (input->get(TRIGGER,PAD_BUTTON_Y)) { + keyboard->shiftPressed(); + cursorPosX = keyboard->getColumn(); + } + if (input->get(TRIGGER,PAD_BUTTON_PLUS)) { + this->input = keyboard->input; + return SUBSTATE_RETURN; + } + return SUBSTATE_RUNNING; +} \ No newline at end of file diff --git a/src/menu/MainMenuState.cpp b/src/menu/MainMenuState.cpp index dcbf2c0..10c734b 100644 --- a/src/menu/MainMenuState.cpp +++ b/src/menu/MainMenuState.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -8,7 +10,10 @@ #include #include -#define ENTRYCOUNT 3 +#include +#include + +#define ENTRYCOUNT 5 static int cursorPos = 0; @@ -21,11 +26,21 @@ void MainMenuState::render() { return; } if (this->state == STATE_MAIN_MENU) { + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Main menu")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Wii U Save Management (%u Title%s)"), this->wiiuTitlesCount, (this->wiiuTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" vWii Save Management (%u Title%s)"), this->vWiiTitlesCount, (this->vWiiTitlesCount > 1) ? "s" : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Batch Backup")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); + consolePrintPos(M_OFF, 5, LanguageUtils::gettext(" Batch Restore")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); + consolePrintPos(M_OFF, 6, LanguageUtils::gettext(" BackupSet Management")); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2 + cursorPos, "\u2192"); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\uE002: Options \ue000: Select Mode")); } @@ -36,10 +51,12 @@ ApplicationState::eSubState MainMenuState::update(Input *input) { if (input->get(TRIGGER, PAD_BUTTON_A)) { switch (cursorPos) { case 0: + //BackupSetList::setBackupSetToRoot(); this->state = STATE_DO_SUBSTATE; this->subState = std::make_unique(this->wiiutitles, this->wiiuTitlesCount); break; case 1: + //BackupSetList::setBackupSetToRoot(); this->state = STATE_DO_SUBSTATE; this->subState = std::make_unique(this->wiititles, this->vWiiTitlesCount); break; @@ -47,6 +64,17 @@ ApplicationState::eSubState MainMenuState::update(Input *input) { this->state = STATE_DO_SUBSTATE; this->subState = std::make_unique(this->wiiutitles, this->wiititles, this->wiiuTitlesCount, this->vWiiTitlesCount); break; + case 3: + //BackupSetList::setBackupSetToRoot(); + this->state = STATE_DO_SUBSTATE; + this->subState = std::make_unique(this->wiiutitles, this->wiititles, this->wiiuTitlesCount, this->vWiiTitlesCount); + break; + case 4: + //BackupSetList::setBackupSetToRoot(); + this->state = STATE_DO_SUBSTATE; + this->substateCalled = STATE_BACKUPSET_MENU; + this->subState = std::make_unique(); + break; default: break; } @@ -67,6 +95,10 @@ ApplicationState::eSubState MainMenuState::update(Input *input) { // keep running. return SUBSTATE_RUNNING; } else if (retSubState == SUBSTATE_RETURN) { + // if ( this->substateCalled == STATE_BACKUPSET_MENU) { + // slot = 0; + // getAccountsSD(&this->title, slot); + // } this->subState.reset(); this->state = STATE_MAIN_MENU; } diff --git a/src/menu/TitleOptionsState.cpp b/src/menu/TitleOptionsState.cpp index 1a2f772..bedb7a3 100644 --- a/src/menu/TitleOptionsState.cpp +++ b/src/menu/TitleOptionsState.cpp @@ -2,12 +2,15 @@ #include #include #include +#include #include #include #include #include #include +#define TAG_OFF 17 + void TitleOptionsState::render() { if (this->state == STATE_DO_SUBSTATE) { if (this->subState == nullptr) { @@ -17,43 +20,51 @@ void TitleOptionsState::render() { return; } if (this->state == STATE_TITLE_OPTIONS) { - if (this->task == restore) { - DrawUtils::setFontColor(COLOR_INFO); - consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("BackupSet: %s"),BackupSetList::getBackupSetEntry().c_str()); - DrawUtils::setFontColor(COLOR_TEXT); + bool emptySlot = isSlotEmpty(this->title.highID, this->title.lowID, slot); + if (this->task == backup || this->task == restore) { + DrawUtils::setFontColor(COLOR_INFO_AT_CURSOR); + consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("BackupSet: %s"), + ( this->task == backup ) ? BackupSetList::ROOT_BS.c_str() : BackupSetList::getBackupSetEntry().c_str()); } this->isWiiUTitle = (this->title.highID == 0x00050000) || (this->title.highID == 0x00050002); entrycount = 3; + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2, "[%08X-%08X] %s", this->title.highID, this->title.lowID, this->title.shortName); if (this->task == copytoOtherDevice) { consolePrintPos(M_OFF, 4, LanguageUtils::gettext("Destination:")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 5, " (%s)", this->title.isTitleOnUSB ? "NAND" : "USB"); } else if (this->task > 2) { entrycount = 2; consolePrintPos(M_OFF, 4, LanguageUtils::gettext("Select %s:"), LanguageUtils::gettext("version")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 5, " < v%u >", this->versionList != nullptr ? this->versionList[slot] : 0); } else if (this->task == wipe) { consolePrintPos(M_OFF, 4, LanguageUtils::gettext("Delete from:")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 5, " (%s)", this->title.isTitleOnUSB ? "USB" : "NAND"); } else { consolePrintPos(M_OFF, 4, LanguageUtils::gettext("Select %s:"), LanguageUtils::gettext("slot")); - + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); if (((this->title.highID & 0xFFFFFFF0) == 0x00010000) && (slot == 255)) consolePrintPos(M_OFF, 5, " < SaveGame Manager GX > (%s)", - isSlotEmpty(this->title.highID, this->title.lowID, slot) ? LanguageUtils::gettext("Empty") + emptySlot ? LanguageUtils::gettext("Empty") : LanguageUtils::gettext("Used")); else consolePrintPos(M_OFF, 5, " < %03u > (%s)", slot, - isSlotEmpty(this->title.highID, this->title.lowID, slot) ? LanguageUtils::gettext("Empty") + emptySlot ? LanguageUtils::gettext("Empty") : LanguageUtils::gettext("Used")); + } + DrawUtils::setFontColor(COLOR_TEXT); if (this->isWiiUTitle) { if (task == restore) { - if (!isSlotEmpty(this->title.highID, this->title.lowID, slot)) { + if (!emptySlot) { entrycount++; consolePrintPos(M_OFF, 7, LanguageUtils::gettext("Select SD user to copy from:")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); if (sduser == -1) consolePrintPos(M_OFF, 8, " < %s >", LanguageUtils::gettext("all users")); else @@ -65,8 +76,10 @@ void TitleOptionsState::render() { } } + DrawUtils::setFontColor(COLOR_TEXT); if (task == wipe) { consolePrintPos(M_OFF, 7, LanguageUtils::gettext("Select Wii U user to delete from:")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); if (this->wiiuuser == -1) consolePrintPos(M_OFF, 8, " < %s >", LanguageUtils::gettext("all users")); else @@ -78,14 +91,19 @@ void TitleOptionsState::render() { : LanguageUtils::gettext("Empty")); } + DrawUtils::setFontColor(COLOR_TEXT); if ((task == backup) || (task == restore) || (task == copytoOtherDevice)) { - if ((task == restore) && isSlotEmpty(this->title.highID, this->title.lowID, slot)) + if ((task == restore) && emptySlot) entrycount--; else { consolePrintPos(M_OFF, (task == restore) ? 10 : 7, LanguageUtils::gettext("Select Wii U user%s:"), (task == copytoOtherDevice) ? LanguageUtils::gettext(" to copy from") : ((task == restore) ? LanguageUtils::gettext(" to copy to") : "")); + if (task == restore) + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); + else + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); if (this->wiiuuser == -1) - consolePrintPos(M_OFF, (task == restore) ? 11 : 8, " < %s >", LanguageUtils::gettext("all users")); + consolePrintPos(M_OFF, (task == restore) ? 11 : 8, " < %s >", (task == copytoOtherDevice || task == backup) ? LanguageUtils::gettext("all users") : LanguageUtils::gettext("same user than in source")); else consolePrintPos(M_OFF, (task == restore) ? 11 : 8, " < %s (%s) > (%s)", getWiiUacc()[wiiuuser].miiName, getWiiUacc()[wiiuuser].persistentID, @@ -98,19 +116,29 @@ void TitleOptionsState::render() { : LanguageUtils::gettext("Empty")); } } + + DrawUtils::setFontColor(COLOR_TEXT); if ((task == backup) || (task == restore)) - if (!isSlotEmpty(this->title.highID, this->title.lowID, slot)) { + if (!emptySlot) { Metadata *metadataObj = new Metadata(this->title.highID, this->title.lowID, slot); - consolePrintPos(M_OFF, 15, LanguageUtils::gettext("Date: %s"), - metadataObj->get().c_str()); + if (metadataObj->read()) { + consolePrintPos(M_OFF, 15, LanguageUtils::gettext("Date: %s"), + metadataObj->simpleFormat().c_str()); + tag = metadataObj->getTag(); + if ( tag != "" ) { + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); + consolePrintPos(TAG_OFF, 5,"[%s]",tag.c_str()); + } + } delete metadataObj; } if (task == copytoOtherDevice) { entrycount++; consolePrintPos(M_OFF, 10, LanguageUtils::gettext("Select Wii U user%s:"), (task == copytoOtherDevice) ? LanguageUtils::gettext(" to copy to") : ""); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); if (wiiuuser_d == -1) - consolePrintPos(M_OFF, 11, " < %s >", LanguageUtils::gettext("all users")); + consolePrintPos(M_OFF, 11, " < %s >", LanguageUtils::gettext("same user than in source")); else consolePrintPos(M_OFF, 11, " < %s (%s) > (%s)", getWiiUacc()[wiiuuser_d].miiName, getWiiUacc()[wiiuuser_d].persistentID, @@ -120,6 +148,7 @@ void TitleOptionsState::render() { : LanguageUtils::gettext("Empty")); } + DrawUtils::setFontColor(COLOR_TEXT); if ((task != importLoadiine) && (task != exportLoadiine)) { if (this->wiiuuser > -1) { if (hasCommonSave(&this->title, @@ -128,6 +157,10 @@ void TitleOptionsState::render() { this->versionList != nullptr ? this->versionList[slot] : 0)) { consolePrintPos(M_OFF, (task == restore) || (task == copytoOtherDevice) ? 13 : 10, LanguageUtils::gettext("Include 'common' save?")); + if ((task == restore) || (task == copytoOtherDevice)) + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); + else + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); consolePrintPos(M_OFF, (task == restore) || (task == copytoOtherDevice) ? 14 : 11, " < %s >", common ? LanguageUtils::gettext("yes") : LanguageUtils::gettext("no ")); } else { @@ -143,6 +176,7 @@ void TitleOptionsState::render() { } else { if (hasCommonSave(&this->title, true, true, slot, this->versionList != nullptr ? this->versionList[slot] : 0)) { consolePrintPos(M_OFF, 7, LanguageUtils::gettext("Include 'common' save?")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); consolePrintPos(M_OFF, 8, " < %s >", common ? LanguageUtils::gettext("yes") : LanguageUtils::gettext("no ")); } else { common = false; @@ -151,6 +185,7 @@ void TitleOptionsState::render() { } } + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 5 + cursorPos * 3, "\u2192"); if (this->title.iconBuf != nullptr) DrawUtils::drawTGA(660, 100, 1, this->title.iconBuf); @@ -158,31 +193,52 @@ void TitleOptionsState::render() { entrycount = 1; if (this->title.iconBuf != nullptr) DrawUtils::drawRGB5A3(650, 100, 1, this->title.iconBuf); - if (!isSlotEmpty(this->title.highID, this->title.lowID, slot)) { + if (!emptySlot) { Metadata *metadataObj = new Metadata(this->title.highID, this->title.lowID, slot); - consolePrintPos(M_OFF, 15, LanguageUtils::gettext("Date: %s"), - metadataObj->get().c_str()); + if (metadataObj->read()) { + consolePrintPos(M_OFF, 15, LanguageUtils::gettext("Date: %s"), + metadataObj->simpleFormat().c_str()); + tag = metadataObj->getTag(); + if ( tag != "" ) + consolePrintPos(TAG_OFF, 5,"[%s]",tag.c_str()); + } delete metadataObj; } } + DrawUtils::setFontColor(COLOR_INFO); switch (task) { case backup: - consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Backup \ue001: Back")); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Backup")); + DrawUtils::setFontColor(COLOR_TEXT); + if (emptySlot) + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Backup \ue001: Back")); + else + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back")); break; case restore: - consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\uE002: Change BackupSet \ue000: Restore \ue001: Back")); + consolePrintPos(20,0,LanguageUtils::gettext("Restore")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue002: Change BackupSet \ue000: Restore \ue001: Back")); break; case wipe: + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Wipe")); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Wipe \ue001: Back")); break; case importLoadiine: + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Import Loadiine")); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Import \ue001: Back")); break; case exportLoadiine: + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Export Loadiine")); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Export \ue001: Back")); break; case copytoOtherDevice: + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Copy to Other Device")); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Copy \ue001: Back")); break; } @@ -198,6 +254,7 @@ ApplicationState::eSubState TitleOptionsState::update(Input *input) { if (input->get(TRIGGER, PAD_BUTTON_X)) if (this->task == restore) { this->state = STATE_DO_SUBSTATE; + this->substateCalled = STATE_BACKUPSET_MENU; this->subState = std::make_unique(); } if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { @@ -373,6 +430,12 @@ ApplicationState::eSubState TitleOptionsState::update(Input *input) { if (cursorPos > 0) --cursorPos; } + if (input->get(TRIGGER, PAD_BUTTON_MINUS)) + if (this->task == backup) { + if (!isSlotEmpty(this->title.highID, this->title.lowID, slot)) + deleteSlot(&this->title, slot); + DrawUtils::setRedraw(true); + } if (input->get(TRIGGER, PAD_BUTTON_A)) { switch (this->task) { case backup: @@ -385,6 +448,7 @@ ApplicationState::eSubState TitleOptionsState::update(Input *input) { break; case wipe: wipeSavedata(&this->title, wiiuuser, common); + cursorPos = 0; DrawUtils::setRedraw(true); break; case copytoOtherDevice: @@ -399,16 +463,33 @@ ApplicationState::eSubState TitleOptionsState::update(Input *input) { break; } } + if (input->get(TRIGGER, PAD_BUTTON_PLUS)) { + this->state = STATE_DO_SUBSTATE; + this->substateCalled = STATE_KEYBOARD; + this->subState = std::make_unique(newTag); + } } else if (this->state == STATE_DO_SUBSTATE) { auto retSubState = this->subState->update(input); if (retSubState == SUBSTATE_RUNNING) { // keep running. return SUBSTATE_RUNNING; } else if (retSubState == SUBSTATE_RETURN) { + if ( this->substateCalled == STATE_KEYBOARD) { + if (newTag != tag) { + Metadata *metadataObj = new Metadata(this->title.highID, this->title.lowID, slot); + metadataObj->read(); + metadataObj->setTag(newTag); + metadataObj->write(); + delete metadataObj; + } + } + if ( this->substateCalled == STATE_BACKUPSET_MENU) { + slot = 0; + getAccountsSD(&this->title, slot); + } this->subState.reset(); this->state = STATE_TITLE_OPTIONS; - slot = 0; - getAccountsSD(&this->title, slot); + this->substateCalled = NONE; } } return SUBSTATE_RUNNING; diff --git a/src/menu/TitleTaskState.cpp b/src/menu/TitleTaskState.cpp index 91f26b7..2d6f226 100644 --- a/src/menu/TitleTaskState.cpp +++ b/src/menu/TitleTaskState.cpp @@ -24,27 +24,39 @@ void TitleTaskState::render() { return; } if (this->state == STATE_TITLE_TASKS) { + DrawUtils::setFontColor(COLOR_INFO_AT_CURSOR); + consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("WiiU Serial Id: %s"),Metadata::thisConsoleSerialId.c_str()); DrawUtils::setFontColor(COLOR_INFO); - consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("WiiU Serial Id: %s"),Metadata::serialId.c_str()); - DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPos(22,0,LanguageUtils::gettext("Tasks")); this->isWiiUTitle = (this->title.highID == 0x00050000) || (this->title.highID == 0x00050002); entrycount = 3 + 2 * static_cast(this->isWiiUTitle) + 1 * static_cast(this->isWiiUTitle && (this->title.isTitleDupe)); + if (cursorPos > entrycount) + cursorPos = 0; + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2, " [%08X-%08X] [%s]", this->title.highID, this->title.lowID, this->title.productCode); consolePrintPos(M_OFF, 3, " %s", this->title.shortName); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); consolePrintPos(M_OFF, 5, LanguageUtils::gettext(" Backup savedata")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); consolePrintPos(M_OFF, 6, LanguageUtils::gettext(" Restore savedata")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); consolePrintPos(M_OFF, 7, LanguageUtils::gettext(" Wipe savedata")); if (this->isWiiUTitle) { + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); consolePrintPos(M_OFF, 8, LanguageUtils::gettext(" Import from loadiine")); + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); consolePrintPos(M_OFF, 9, LanguageUtils::gettext(" Export to loadiine")); - if (this->title.isTitleDupe) + if (this->title.isTitleDupe) { + DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,5); consolePrintPos(M_OFF, 10, LanguageUtils::gettext(" Copy Savedata to Title in %s"), this->title.isTitleOnUSB ? "NAND" : "USB"); + } if (this->title.iconBuf != nullptr) DrawUtils::drawTGA(660, 80, 1, this->title.iconBuf); } else if (this->title.iconBuf != nullptr) DrawUtils::drawRGB5A3(645, 80, 1, this->title.iconBuf); + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(M_OFF, 2 + 3 + cursorPos, "\u2192"); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Task \ue001: Back")); } diff --git a/src/menu/WiiUTitleListState.cpp b/src/menu/WiiUTitleListState.cpp index d25e93f..957439b 100644 --- a/src/menu/WiiUTitleListState.cpp +++ b/src/menu/WiiUTitleListState.cpp @@ -9,7 +9,8 @@ #include #define MAX_TITLE_SHOW 14 -static int cursorPos = 0; +int WiiUTitleListState::cursorPos = 0; +int WiiUTitleListState::scroll = 0; void WiiUTitleListState::render() { if (this->state == STATE_DO_SUBSTATE) { @@ -23,30 +24,38 @@ void WiiUTitleListState::render() { if ((this->titles == nullptr) || (this->titlesCount == 0)) { promptError(LanguageUtils::gettext("No Wii U titles found.")); this->noTitles = true; + DrawUtils::beginDraw(); + consolePrintPosAligned(8, 4, 1, LanguageUtils::gettext("No Wii U titles found")); + consolePrintPosAligned(17, 4, 1, LanguageUtils::gettext("Any Button: Back")); + return; } - consolePrintPos(39, 0, LanguageUtils::gettext("%s Sort: %s \ue084"), + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Wii U Titles")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0 , 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), (this->titleSort > 0) ? (this->sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); for (int i = 0; i < MAX_TITLE_SHOW; i++) { if (i + this->scroll < 0 || i + this->scroll >= this->titlesCount) break; - DrawUtils::setFontColor(static_cast(0x00FF00FF)); + + DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); if (!this->titles[i + this->scroll].saveInit) - DrawUtils::setFontColor(static_cast(0xFFFF00FF)); + DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); if (strcmp(this->titles[i + this->scroll].shortName, "DONT TOUCH ME") == 0) - DrawUtils::setFontColor(static_cast(0xFF0000FF)); - if (strlen(this->titles[i + this->scroll].shortName) != 0u) - consolePrintPos(M_OFF, i + 2, " %s %s%s%s", this->titles[i + this->scroll].shortName, + DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); + + consolePrintPos(M_OFF+1, i + 2, " %s %s%s%s%s", + this->titles[i + this->scroll].shortName, this->titles[i + this->scroll].isTitleOnUSB ? "(USB)" : "(NAND)", this->titles[i + this->scroll].isTitleDupe ? " [D]" : "", - this->titles[i + this->scroll].saveInit ? "" : LanguageUtils::gettext(" [Not Init]")); - else - consolePrintPos(M_OFF, i + 2, " %08lx%08lx", this->titles[i + this->scroll].highID, - this->titles[i + this->scroll].lowID); - DrawUtils::setFontColor(COLOR_TEXT); + this->titles[i + this->scroll].noFwImg ? LanguageUtils::gettext(" [vWiiInject]") : "", + this->titles[i + this->scroll].saveInit ? "" : LanguageUtils::gettext(" [Not Init]") + ); if (this->titles[i + this->scroll].iconBuf != nullptr) { DrawUtils::drawTGA((M_OFF + 4) * 12 - 2, (i + 3) * 24, 0.18, this->titles[i + this->scroll].iconBuf); } } + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(-1, 2 + cursorPos, "\u2192"); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Game \ue001: Back")); } @@ -76,12 +85,17 @@ ApplicationState::eSubState WiiUTitleListState::update(Input *input) { return SUBSTATE_RUNNING; } } + /* std::string path = StringUtils::stringFormat("%s/usr/title/000%x/%x/code/fw.img", (this->titles[this->targ].isTitleOnUSB) ? getUSB().c_str() : "storage_mlc01:", this->titles[this->targ].highID, this->titles[this->targ].lowID); if (checkEntry(path.c_str()) != 0) + */ + if(this->titles[this->targ].noFwImg) if (!promptConfirm(ST_ERROR, LanguageUtils::gettext("vWii saves are in the vWii section. Continue?"))) return SUBSTATE_RUNNING; + + if (!this->titles[this->targ].saveInit) { if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Recommended to run Game at least one time. Continue?")) || !promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you REALLY sure?"))) { diff --git a/src/menu/vWiiTitleListState.cpp b/src/menu/vWiiTitleListState.cpp index 0f336ee..b1bf0bd 100644 --- a/src/menu/vWiiTitleListState.cpp +++ b/src/menu/vWiiTitleListState.cpp @@ -8,7 +8,8 @@ #include #define MAX_TITLE_SHOW 14 -static int cursorPos = 0; +int vWiiTitleListState::scroll = 0; +int vWiiTitleListState::cursorPos = 0; void vWiiTitleListState::render() { if (this->state == STATE_DO_SUBSTATE) { @@ -22,30 +23,35 @@ void vWiiTitleListState::render() { if ((this->titles == nullptr) || (this->titlesCount == 0)) { promptError(LanguageUtils::gettext("No vWii titles found.")); this->noTitles = true; + DrawUtils::beginDraw(); + consolePrintPosAligned(8, 4, 1, LanguageUtils::gettext("No vWii titles found.")); + consolePrintPosAligned(17, 4, 1, LanguageUtils::gettext("Any Button: Back")); + return; } - consolePrintPos(39, 0, LanguageUtils::gettext("%s Sort: %s \ue084"), + DrawUtils::setFontColor(COLOR_INFO); + consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("vWii Titles")); + DrawUtils::setFontColor(COLOR_TEXT); + consolePrintPosAligned(0, 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), (titleSort > 0) ? (sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); for (int i = 0; i < 14; i++) { if (i + this->scroll < 0 || i + this->scroll >= this->titlesCount) break; - DrawUtils::setFontColor(static_cast(0x00FF00FF)); - if (!titles[i + this->scroll].saveInit) - DrawUtils::setFontColor(static_cast(0xFFFF00FF)); - if (strcmp(titles[i + this->scroll].shortName, "DONT TOUCH ME") == 0) - DrawUtils::setFontColor(static_cast(0xFF0000FF)); - if (strlen(titles[i + this->scroll].shortName) != 0u) - consolePrintPos(M_OFF, i + 2, " %s %s%s", titles[i + this->scroll].shortName, + + DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); + if (!this->titles[i + this->scroll].saveInit) + DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); + if (strcmp(this->titles[i + this->scroll].shortName, "DONT TOUCH ME") == 0) + DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); + + consolePrintPos(M_OFF + 1, i + 2, " %s %s%s", titles[i + this->scroll].shortName, titles[i + this->scroll].isTitleDupe ? " [D]" : "", titles[i + this->scroll].saveInit ? "" : LanguageUtils::gettext(" [Not Init]")); - else - consolePrintPos(M_OFF, i + 2, " %08lx%08lx", titles[i + this->scroll].highID, - titles[i + this->scroll].lowID); - DrawUtils::setFontColor(COLOR_TEXT); if (titles[i + this->scroll].iconBuf != nullptr) { DrawUtils::drawRGB5A3((M_OFF + 2) * 12 - 2, (i + 3) * 24 + 3, 0.25, titles[i + this->scroll].iconBuf); } } + DrawUtils::setFontColor(COLOR_TEXT); consolePrintPos(-3, 2 + cursorPos, "\u2192"); consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Game \ue001: Back")); } diff --git a/src/savemng.cpp b/src/savemng.cpp index 186e30b..cd2d778 100644 --- a/src/savemng.cpp +++ b/src/savemng.cpp @@ -12,6 +12,12 @@ #include #include +//#define DEBUG +#ifdef DEBUG +#include +#include +#endif + #define __FSAShimSend ((FSError(*)(FSAShimBuffer *, uint32_t))(0x101C400 + 0x042d90)) #define IO_MAX_FILE_BUFFER (1024 * 1024) // 1 MB @@ -20,7 +26,7 @@ const char *batchBackupPath = "fs:/vol/external01/wiiu/backups/batch"; // Must b const char *loadiineSavePath = "fs:/vol/external01/wiiu/saves"; const char *legacyBackupPath = "fs:/vol/external01/savegames"; -static char *p1; +//static char *p1; Account *wiiuacc; Account *sdacc; uint8_t wiiuaccn = 0, sdaccn = 5; @@ -41,6 +47,22 @@ static file_buffer buffers[16]; static char *fileBuf[2]; static bool buffersInitialized = false; +//#define MOCK +#ifdef MOCK + // number of times the function will return a failed operation + int f_copyDir = 1; + // TODO checkEntry is called from main to initialize title list + // so the approach of globally mock it to test restores cannot be used + //int f_checkEntry = 3; + int f_removeDir = 1; + //unlink will fail if false + bool unlink_c = true; + bool unlink_b = true; +#endif + + + + std::string newlibtoFSA(std::string path) { if (path.rfind("storage_slccmpt01:", 0) == 0) { StringUtils::replace(path, "storage_slccmpt01:", "/vol/storage_slccmpt01"); @@ -66,6 +88,11 @@ std::string getBatchBackupPath(uint32_t highID, uint32_t lowID, uint8_t slot, st return StringUtils::stringFormat("%s/%s/%08x%08x/%u", batchBackupPath, datetime.c_str(),highID, lowID, slot); } +std::string getBatchBackupPathRoot(std::string datetime) { + return StringUtils::stringFormat("%s/%s", batchBackupPath, datetime.c_str()); +} + + uint8_t getSDaccn() { return sdaccn; } @@ -82,16 +109,27 @@ Account *getSDacc() { return sdacc; } +// TODO how to mock checkEntry only for restore ops +#ifndef MOCK_CHECKENTRY int checkEntry(const char *fPath) { struct stat st {}; if (stat(fPath, &st) == -1) - return 0; + return 0; // path does not exist if (S_ISDIR(st.st_mode)) - return 2; + return 2; // is a directory - return 1; + return 1; // is a file +} +#else +int checkEntry(const char *fPath) { + WHBLogPrintf("checkEntry %s --> %s (%d)",fPath,f_checkEntry >0 ? "KO":"OK",f_checkEntry); + if (f_checkEntry-- > 0 ) + return 1; + else + return 2; } +#endif bool initFS() { FSAInit(); @@ -179,13 +217,13 @@ static int32_t loadFilePart(const char *fPath, uint32_t start, uint32_t size, ui fclose(file); } return ret; -} +} int32_t loadTitleIcon(Title *title) { uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; std::string path; if (isWii) { @@ -204,10 +242,10 @@ int32_t loadTitleIcon(Title *title) { return -23; } -static bool folderEmpty(const char *fPath) { +bool folderEmpty(const char *fPath) { DIR *dir = opendir(fPath); if (dir == nullptr) - return false; + return true; // if empty or non-existant, return true. bool empty = true; struct dirent *data; @@ -306,6 +344,19 @@ void consolePrintPos(int x, int y, const char *format, ...) { // Source: ftpiiu free(tmp); } +void kConsolePrintPos(int x, int y, int x_offset, const char *format, ...) { // Source: ftpiiu + char *tmp = nullptr; + y += Y_OFF; + + va_list va; + va_start(va, format); + if ((vasprintf(&tmp, format, va) >= 0) && (tmp != nullptr)) + DrawUtils::print(x * 52 + x_offset, y * 50, tmp); + va_end(va); + if (tmp != nullptr) + free(tmp); +} + void consolePrintPosMultiline(int x, int y, const char *format, ...) { va_list va; va_start(va, format); @@ -343,6 +394,7 @@ bool promptConfirm(Style st, const std::string &question) { DrawUtils::setFontColor(COLOR_TEXT); const std::string msg1 = LanguageUtils::gettext("\ue000 Yes - \ue001 No"); const std::string msg2 = LanguageUtils::gettext("\ue000 Confirm - \ue001 Cancel"); + const std::string msg3 = LanguageUtils::gettext("\ue003 Confirm - \ue001 Cancel"); std::string msg; switch (st & 0x0F) { case ST_YES_NO: @@ -354,7 +406,9 @@ bool promptConfirm(Style st, const std::string &question) { default: msg = msg2; } - if (st & ST_WARNING) { + if (st & ST_WIPE) // for wipe bakupSet operation, we will ask that the user press X + msg = msg3; + if (st & ST_WARNING || st & ST_WIPE ) { DrawUtils::clear(Color(0x7F7F0000)); } else if (st & ST_ERROR) { DrawUtils::clear(Color(0x7F000000)); @@ -362,8 +416,20 @@ bool promptConfirm(Style st, const std::string &question) { DrawUtils::clear(Color(0x007F0000)); } if (!(st & ST_MULTILINE)) { - consolePrintPos(31 - (DrawUtils::getTextWidth((char *) question.c_str()) / 24), 7, question.c_str()); - consolePrintPos(31 - (DrawUtils::getTextWidth((char *) msg.c_str()) / 24), 9, msg.c_str()); + std::string splitted; + std::stringstream question_ss(question); + int nLines = 0; + int maxLineSize = 0; + int lineSize = 0; + while (getline(question_ss,splitted,'\n')) { + lineSize = DrawUtils::getTextWidth((char *) splitted.c_str()); + maxLineSize = lineSize > maxLineSize ? lineSize : maxLineSize; + nLines++; + } + int initialYPos = 6 - nLines/2; + initialYPos = initialYPos > 0 ? initialYPos : 0; + consolePrintPos(31 - (maxLineSize / 24), initialYPos, question.c_str()); + consolePrintPos(31 - (DrawUtils::getTextWidth((char *) msg.c_str()) / 24), initialYPos+2+nLines, msg.c_str()); } int ret = 0; @@ -371,9 +437,18 @@ bool promptConfirm(Style st, const std::string &question) { Input input{}; while (true) { input.read(); - if (input.get(TRIGGER, PAD_BUTTON_A)) { - ret = 1; - break; + if ( st & ST_WIPE) { + if (input.get(TRIGGER, PAD_BUTTON_Y)) { + ret = 1; + break; + } + } + else + { + if (input.get(TRIGGER, PAD_BUTTON_A)) { + ret = 1; + break; + } } if (input.get(TRIGGER, PAD_BUTTON_B)) { ret = 0; @@ -399,9 +474,47 @@ void promptError(const char *message, ...) { free(tmp); DrawUtils::endDraw(); va_end(va); - sleep(4); + sleep(3); } +void promptMessage(Color bgcolor, const char *message, ...) { + DrawUtils::beginDraw(); + DrawUtils::clear(bgcolor); + va_list va; + va_start(va, message); + char *tmp = nullptr; + if ((vasprintf(&tmp, message, va) >= 0) && (tmp != nullptr)) { + std::string splitted; + std::stringstream message_ss(tmp); + int nLines = 0; + int maxLineSize = 0; + int lineSize = 0; + while (getline(message_ss,splitted,'\n')) { + lineSize = DrawUtils::getTextWidth((char *) splitted.c_str()); + maxLineSize = lineSize > maxLineSize ? lineSize : maxLineSize; + nLines++; + } + int initialYPos = 6 - nLines/2; + initialYPos = initialYPos > 0 ? initialYPos : 0; + + int x = 31 - (maxLineSize / 24); + x = (x < -4 ? -4 : x); + DrawUtils::print((x + 4) * 12, (initialYPos + 1) * 24, tmp); + DrawUtils::print((x + 4) * 12, (initialYPos + 1 + 4 + nLines) * 24, LanguageUtils::gettext("Press \ue000 to continue")); + } + if (tmp != nullptr) + free(tmp); + DrawUtils::endDraw(); + va_end(va); + Input input{}; + while (true) { + input.read(); + if (input.get(TRIGGER, PAD_BUTTON_A)) + break; + } +} + + void getAccountsWiiU() { /* get persistent ID - thanks to Maschell */ nn::act::Initialize(); @@ -570,6 +683,7 @@ static bool copyFile(const std::string &pPath, const std::string &oPath) { return true; } +#ifndef MOCK static bool copyDir(const std::string &pPath, const std::string &tPath) { // Source: ft2sd DIR *dir = opendir(pPath.c_str()); if (dir == nullptr) @@ -596,7 +710,6 @@ static bool copyDir(const std::string &pPath, const std::string &tPath) { // Sou return false; } } else { - p1 = data->d_name; showFileOperation(data->d_name, pPath + StringUtils::stringFormat("/%s", data->d_name), targetPath); if (!copyFile(pPath + StringUtils::stringFormat("/%s", data->d_name), targetPath)) { @@ -610,7 +723,18 @@ static bool copyDir(const std::string &pPath, const std::string &tPath) { // Sou return true; } +#else +static bool copyDir(const std::string &pPath, const std::string &tPath) { + WHBLogPrintf("copy %s %s --> %s(%d)",pPath.c_str(),tPath.c_str(),f_copyDir >0 ? "KO":"OK",f_copyDir); + if (f_copyDir-- > 0) + return false; + else + return true; +} +#endif + +#ifndef MOCK static bool removeDir(const std::string &pPath) { DIR *dir = opendir(pPath.c_str()); if (dir == nullptr) @@ -648,6 +772,15 @@ static bool removeDir(const std::string &pPath) { closedir(dir); return true; } +#else +static bool removeDir(const std::string &pPath) { + WHBLogPrintf("removeDir %s --> %s(%d)",pPath.c_str(),f_removeDir >0 ? "KO":"OK",f_removeDir); + if (f_removeDir-- > 0) + return false; + else + return true; +} +#endif static std::string getUserID() { // Source: loadiine_gx2 /* get persistent ID - thanks to Maschell */ @@ -755,7 +888,7 @@ bool hasAccountSave(Title *title, bool inSD, bool iine, uint32_t user, uint8_t s uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; if (highID == 0 || lowID == 0) return false; @@ -808,7 +941,7 @@ bool hasCommonSave(Title *title, bool inSD, bool iine, uint8_t slot, int version uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; if (isWii) return false; @@ -863,7 +996,7 @@ void copySavedata(Title *title, Title *titleb, int8_t wiiuuser, int8_t wiiuuser_ return; int slotb = getEmptySlot(titleb->highID, titleb->lowID); if ((slotb >= 0) && promptConfirm(ST_YES_NO, LanguageUtils::gettext("Backup current savedata first to next empty slot?"))) { - backupSavedata(titleb, slotb, wiiuuser, common); + backupSavedata(titleb, slotb, wiiuuser, common, LanguageUtils::gettext("pre-copyToOtherDev backup")); promptError(LanguageUtils::gettext("Backup done. Now copying Savedata.")); } @@ -962,15 +1095,32 @@ void writeMetadata(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB, const delete metadataObj; } -void backupAllSave(Title *titles, int count, const std::string &batchDatetime) { + +void writeMetadataWithTag(uint32_t highID,uint32_t lowID,uint8_t slot, bool isUSB, const std::string &tag) { + Metadata *metadataObj = new Metadata(highID, lowID, slot); + metadataObj->setTag(tag); + metadataObj->set(getNowDate(),isUSB); + delete metadataObj; +} + +void writeBackupAllMetadata(const std::string & batchDatetime, const std::string & tag) { + Metadata *metadataObj = new Metadata(batchDatetime,"", Metadata::thisConsoleSerialId, tag); + metadataObj->write(); + delete metadataObj; +} + +void backupAllSave(Title *titles, int count, const std::string & batchDatetime, bool onlySelectedTitles /*= false*/) { for ( int sourceStorage = 0; sourceStorage < 2 ; sourceStorage++ ) { for (int i = 0; i < count; i++) { if (titles[i].highID == 0 || titles[i].lowID == 0 || !titles[i].saveInit) continue; + if (onlySelectedTitles) + if (! titles[i].currentBackup.selected) + continue; uint32_t highID = titles[i].highID; uint32_t lowID = titles[i].lowID; bool isUSB = titles[i].isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = titles[i].is_Wii; if ((sourceStorage == 0 && !isUSB) || (sourceStorage == 1 && isUSB)) // backup first WiiU USB savedata to slot 0 continue; uint8_t slot = getEmptySlot(highID,lowID,batchDatetime); @@ -987,7 +1137,8 @@ void backupAllSave(Title *titles, int count, const std::string &batchDatetime) { } } -void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common) { +void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common, const std::string &tag /* = "" */) { + int errorCode = 0; if (!isSlotEmpty(title->highID, title->lowID, slot) && !promptConfirm(ST_WARNING, LanguageUtils::gettext("Backup found on this slot. Overwrite it?"))) { return; @@ -995,97 +1146,199 @@ void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common) { uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; const std::string path = (isWii ? "storage_slccmpt01:/title" : (isUSB ? (getUSB() + "/usr/save").c_str() : "storage_mlc01:/usr/save")); std::string srcPath = StringUtils::stringFormat("%s/%08x/%08x/%s", path.c_str(), highID, lowID, isWii ? "data" : "user"); - std::string dstPath; - dstPath = getDynamicBackupPath(highID, lowID, slot); + std::string dstPath = getDynamicBackupPath(highID, lowID, slot); createFolder(dstPath.c_str()); + + std::string srcCommonPath = srcPath + "/common"; + std::string dstCommonPath = dstPath + "/common"; + bool commonSaved = false; - if ((wiiuuser > -1) && !isWii) { - if (common) { - if (copyDir(srcPath+"/common", dstPath+"/common")) + bool doBase; + bool doCommon; + bool singleUser = false; + + if ( isWii ) { + doBase = true; + doCommon = false; + } + else + { + switch (wiiuuser) { + case -1: // allusers + doBase = true; + doCommon = false; + break; + default: // wiiuuser = 0 .. n + doBase = true; + doCommon = common; + singleUser = true; + srcPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); + dstPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); + break; + } + } + + + if (doCommon) { + if (copyDir(srcCommonPath, dstCommonPath)) commonSaved = true; - else - promptError(LanguageUtils::gettext("Common save not found.")); + else { + promptError(LanguageUtils::gettext("Common save not found.")); + errorCode = 1 ; } - srcPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); - dstPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); - if (checkEntry(srcPath.c_str()) == 0) { - if (commonSaved) - writeMetadata(highID,lowID,slot,isUSB); + } + + if (doBase) { + if (singleUser) + { + if (checkEntry(srcPath.c_str()) == 0) { // no dir for user data + if (commonSaved) + writeMetadataWithTag(highID,lowID,slot,isUSB,tag); + else + { + promptError(LanguageUtils::gettext("No save found for this user.")); + dstPath = getDynamicBackupPath(highID, lowID, slot); + removeDir(dstPath); + unlink(dstPath.c_str()); + errorCode += 2; + } + } + else { + if (!copyDir(srcPath, dstPath)) { + promptError(LanguageUtils::gettext("Backup failed. DO NOT restore from this slot.")); + writeMetadataWithTag(highID,lowID,slot,isUSB,LanguageUtils::gettext("UNUSABLE SLOT - BACKUP FAILED")); + errorCode += 4; + } + else + writeMetadataWithTag(highID,lowID,slot,isUSB,tag); + } + } + else // allusers + { + if (!copyDir(srcPath, dstPath)) { + promptError(LanguageUtils::gettext("Backup failed. DO NOT restore from this slot.")); + writeMetadataWithTag(highID,lowID,slot,isUSB,LanguageUtils::gettext("UNUSABLE SLOT - BACKUP FAILED")); + errorCode += 8; + } else - promptError(LanguageUtils::gettext("No save found for this user.")); - return; + writeMetadataWithTag(highID,lowID,slot,isUSB,tag); } } - if (!copyDir(srcPath, dstPath)) - promptError(LanguageUtils::gettext("Backup failed. DO NOT restore from this slot.")); - else - writeMetadata(highID,lowID,slot,isUSB); - } -void restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, bool common) { - if (isSlotEmpty(title->highID, title->lowID, slot)) { - promptError(LanguageUtils::gettext("No backup found on selected slot.")); - return; +int restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, bool common, bool interactive /*= true*/) { + int errorCode = 0; + if (isSlotEmpty(title->highID, title->lowID, slot)) { + promptError(LanguageUtils::gettext("%s\nNo backup found on selected slot."),title->shortName); + return -2; + } + if (interactive) { + if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you sure?"))) + return -1; + // individual backups always to ROOT backupSet + BackupSetList::saveBackupSetSubPath(); + BackupSetList::setBackupSetSubPathToRoot(); + int slotb = getEmptySlot(title->highID, title->lowID); + if ((slotb >= 0) && promptConfirm(ST_YES_NO, LanguageUtils::gettext("Backup current savedata first to next empty slot?"))) + backupSavedata(title, slotb, wiiuuser, common , LanguageUtils::gettext("pre-Restore backup")); + BackupSetList::restoreBackupSetSubPath(); } - if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you sure?"))) - return; - // backups to ROOT backupSet - BackupSetList::saveBackupSetSubPath(); - BackupSetList::setBackupSetSubPathToRoot(); - int slotb = getEmptySlot(title->highID, title->lowID); - if ((slotb >= 0) && promptConfirm(ST_YES_NO, LanguageUtils::gettext("Backup current savedata first to next empty slot?"))) - backupSavedata(title, slotb, wiiuuser, common); - BackupSetList::restoreBackupSetSubPath(); uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; std::string srcPath; srcPath = getDynamicBackupPath(highID, lowID, slot); const std::string path = (isWii ? "storage_slccmpt01:/title" : (isUSB ? (getUSB() + "/usr/save").c_str() : "storage_mlc01:/usr/save")); std::string dstPath = StringUtils::stringFormat("%s/%08x/%08x/%s", path.c_str(), highID, lowID, isWii ? "data" : "user"); + createFolderUnlocked(dstPath); + std::string srcCommonPath = srcPath + "/common"; + std::string dstCommonPath = dstPath + "/common"; + bool commonSaved = false; - if ((sduser > -1) && !isWii) { - if (common) { - FSAMakeQuota(handle, newlibtoFSA(dstPath + "/common").c_str(), 0x666, title->accountSaveSize); - if (copyDir(srcPath + "/common", dstPath + "/common")) - commonSaved = true; - else - promptError(LanguageUtils::gettext("Common save not restored.")); - } - srcPath.append(StringUtils::stringFormat("/%s", sdacc[sduser].persistentID)); - dstPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); - if (checkEntry(srcPath.c_str()) == 2) { - FSAMakeQuota(handle, newlibtoFSA(dstPath).c_str(), 0x666, title->accountSaveSize); - if (!copyDir(srcPath, dstPath)) - promptError(LanguageUtils::gettext("Restore failed.")); - } - else - if (!commonSaved) - promptError(LanguageUtils::gettext("No save found for this user.")); + bool doBase; + bool doCommon; + bool singleUser = false; + + if ( isWii ) { + doBase = true; + doCommon = false; } else { - FSAMakeQuotaFromDir(srcPath.c_str(), dstPath.c_str(), title->accountSaveSize); - if (!copyDir(srcPath, dstPath)) - promptError(LanguageUtils::gettext("Restore failed.")); + switch (sduser) { + case -2: // no usser + doBase = false; + doCommon = common; + break; + case -1: // allusers + doBase = true; + doCommon = false; + break; + default: // wiiuuser = 0 .. n + doBase = true; + doCommon = common; + singleUser = true; + srcPath.append(StringUtils::stringFormat("/%s", sdacc[sduser].persistentID)); + dstPath.append(StringUtils::stringFormat("/%s", wiiuacc[wiiuuser].persistentID)); + break; + } } - - + if (doCommon) { + #ifndef MOCK + FSAMakeQuota(handle, newlibtoFSA(dstCommonPath).c_str(), 0x666, title->accountSaveSize); + #endif + if (copyDir(srcCommonPath, dstCommonPath)) + commonSaved = true; + else { + promptError(LanguageUtils::gettext("%s\nCommon save not restored."),title->shortName); + errorCode = 1; + } + } + if (doBase) { + if (singleUser) + { + if (checkEntry(srcPath.c_str()) == 2) { + #ifndef MOCK + FSAMakeQuota(handle, newlibtoFSA(dstPath).c_str(), 0x666, title->accountSaveSize); + #endif + if (!copyDir(srcPath, dstPath)) { + promptError(LanguageUtils::gettext("%s\nRestore failed."),title->shortName); + errorCode += 2; + } + } + else + if (!commonSaved) + promptError(LanguageUtils::gettext("%s\nNo save found for this user."),title->shortName); + } + else + { + #ifndef MOCK + FSAMakeQuotaFromDir(srcPath.c_str(), dstPath.c_str(), title->accountSaveSize); + #endif + if (!copyDir(srcPath, dstPath)) { + promptError(LanguageUtils::gettext("%s\nRestore failed."),title->shortName); + errorCode += 4; + } + } + + } + +#ifndef MOCK if (!title->saveInit && !isWii) { std::string userPath = StringUtils::stringFormat("%s/%08x/%08x/user", path.c_str(), highID, lowID); FSAShimBuffer *shim = (FSAShimBuffer *) memalign(0x40, sizeof(FSAShimBuffer)); if (!shim) { - return; + errorCode +=8; + return errorCode; } shim->clientHandle = handle; @@ -1107,6 +1360,7 @@ void restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, copyFile(titleMetaPath + "/meta.xml", metaPath + "/meta.xml"); copyFile(titleMetaPath + "/iconTex.tga", metaPath + "/iconTex.tga"); } +#endif if (dstPath.rfind("storage_slccmpt01:", 0) == 0) { FSAFlushVolume(handle, "/vol/storage_slccmpt01"); @@ -1117,40 +1371,86 @@ void restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, } else if (dstPath.rfind("storage_usb02:", 0) == 0) { FSAFlushVolume(handle, "/vol/storage_usb02"); } + return errorCode; } -void wipeSavedata(Title *title, int8_t wiiuuser, bool common) { - if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you sure?")) || !promptConfirm(ST_WARNING, LanguageUtils::gettext("Hm, are you REALLY sure?"))) - return; - int slotb = getEmptySlot(title->highID, title->lowID); - if ((slotb >= 0) && promptConfirm(ST_YES_NO, LanguageUtils::gettext("Backup current savedata first?"))) - backupSavedata(title, slotb, wiiuuser, common); +int wipeSavedata(Title *title, int8_t wiiuuser, bool common, bool interactive /*= true*/) { + int errorCode = 0; + if (interactive) { + if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you sure?")) || !promptConfirm(ST_WARNING, LanguageUtils::gettext("Hm, are you REALLY sure?"))) + return -1; + int slotb = getEmptySlot(title->highID, title->lowID); + if ((slotb >= 0) && promptConfirm(ST_YES_NO, LanguageUtils::gettext("Backup current savedata first?"))) + backupSavedata(title, slotb, wiiuuser, common, LanguageUtils::gettext("pre-Wipe backup")); + } uint32_t highID = title->highID; uint32_t lowID = title->lowID; bool isUSB = title->isTitleOnUSB; - bool isWii = ((highID & 0xFFFFFFF0) == 0x00010000); + bool isWii = title->is_Wii; std::string srcPath; - std::string origPath; + std::string commonPath; std::string path; path = (isWii ? "storage_slccmpt01:/title" : (isUSB ? (getUSB() + "/usr/save") : "storage_mlc01:/usr/save")); srcPath = StringUtils::stringFormat("%s/%08x/%08x/%s", path.c_str(), highID, lowID, isWii ? "data" : "user"); - if ((wiiuuser > -1) && !isWii) { - if (common) { - origPath = srcPath + "/common"; - if (!removeDir(origPath)) - promptError(LanguageUtils::gettext("Common save not found.")); - if (unlink(origPath.c_str()) == -1) - promptError(LanguageUtils::gettext("Failed to delete common folder: %s"), strerror(errno)); + commonPath = srcPath + "/common"; + + bool doBase; + bool doCommon; + + if ( isWii ) { + doBase = true; + doCommon = false; + } + else + { + switch (wiiuuser) { + case -2: // no usser + doBase = false; + doCommon = common; + break; + case -1: // allusers + doBase = true; + doCommon = false; + break; + default: // wiiuuser = 0 .. n + doBase = true; + doCommon = common; + srcPath += "/" + std::string(wiiuacc[wiiuuser].persistentID); + break; + } + } + + if (doCommon) { + if (!removeDir(commonPath)) { + promptError(LanguageUtils::gettext("%s \n Common save not found."),title->shortName); + errorCode = 1; + } + #ifndef MOCK + if (unlink(commonPath.c_str()) == -1) { + #else + if (!unlink_c) { + #endif + promptError(LanguageUtils::gettext("%s \n Failed to delete common folder:\n %s"), title->shortName,strerror(errno)); + errorCode += 2; } - srcPath += "/" + std::string(wiiuacc[wiiuuser].persistentID); } - if (checkEntry(srcPath.c_str()) == 2) { - if (!removeDir(srcPath)) - promptError(LanguageUtils::gettext("Failed to delete savefile.")); - if ((wiiuuser > -1) && !isWii) { - if (unlink(srcPath.c_str()) == -1) - promptError(LanguageUtils::gettext("Failed to delete user folder: %s"), strerror(errno)); + if (doBase) { + if (checkEntry(srcPath.c_str()) == 2) { + if (!removeDir(srcPath)) { + promptError(LanguageUtils::gettext("%s \n Failed to delete savefile."),title->shortName); + errorCode += 4; + } + if ((wiiuuser > -1) && !isWii) { + #ifndef MOCK + if (unlink(srcPath.c_str()) == -1) { + #else + if (!unlink_b) { + #endif + promptError(LanguageUtils::gettext("%s \n Failed to delete user folder:\n %s"), title->shortName,strerror(errno)); + errorCode += 8; + } + } } } @@ -1165,6 +1465,7 @@ void wipeSavedata(Title *title, int8_t wiiuuser, bool common) { volPath = "/vol/storage_slccmpt01"; } FSAFlushVolume(handle, volPath.c_str()); + return errorCode; } void importFromLoadiine(Title *title, bool common, int version) { @@ -1227,3 +1528,56 @@ void exportToLoadiine(Title *title, bool common, int version) { promptError(LanguageUtils::gettext("Common save not found.")); } } + +void deleteSlot(Title *title, uint8_t slot) { + if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you sure?")) || !promptConfirm(ST_WARNING, LanguageUtils::gettext("Hm, are you REALLY sure?"))) + return; + uint32_t highID = title->highID; + uint32_t lowID = title->lowID; + const std::string path = getDynamicBackupPath(highID, lowID, slot); + if (path.find(backupPath) == std::string::npos) { + promptError(LanguageUtils::gettext("Error setting path. Aborting.")); + return; + } + if (checkEntry(path.c_str()) == 2) { + if (removeDir(path)) { + if (unlink(path.c_str()) == -1) + promptError(LanguageUtils::gettext("Failed to delete slot %u."),slot); + } + else + promptError(LanguageUtils::gettext("Failed to delete slot %u."),slot); + } + else + { + promptError(LanguageUtils::gettext("Folder does not exist.")); + } +} + +bool wipeBackupSet(const std::string &subPath) { + if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Wipe BackupSet - Are you sure?")) || !promptConfirm(ST_WIPE, LanguageUtils::gettext("Wipe BackupSet - Hm, are you REALLY sure?"))) + return false; + const std::string path = StringUtils::stringFormat("%s%s", backupPath,subPath.c_str()); + if (path.find(batchBackupPath) == std::string::npos) { + promptError(LanguageUtils::gettext("Error setting path. Aborting.")); + return false; + } + if (checkEntry(path.c_str()) == 2) { + if (removeDir(path)) { + if (unlink(path.c_str()) == -1) { + promptError(LanguageUtils::gettext("Failed to delete backupSet %s."),subPath.c_str()); + return false; + } + } + else + { + promptError(LanguageUtils::gettext("Failed to delete backupSet %s."),subPath.c_str()); + return false; + } + } + else + { + promptError(LanguageUtils::gettext("Folder does not exist.")); + } + return true; +} + \ No newline at end of file diff --git a/src/utils/DrawUtils.cpp b/src/utils/DrawUtils.cpp index 471de02..14d3dc4 100644 --- a/src/utils/DrawUtils.cpp +++ b/src/utils/DrawUtils.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -13,6 +14,9 @@ #include #include +#include +#include + // buffer width #define TV_WIDTH 0x500 #define DRC_WIDTH 0x380 @@ -27,7 +31,11 @@ uint8_t *DrawUtils::drcBuffer = nullptr; uint32_t DrawUtils::sBufferSizeTV = 0, DrawUtils::sBufferSizeDRC = 0; BOOL DrawUtils::sConsoleHasForeground = TRUE; +static SFT cFont = {}; static SFT pFont = {}; +#ifdef KFONT +static SFT kFont = {}; +#endif static Color font_col(0xFFFFFFFF); @@ -188,10 +196,11 @@ void DrawUtils::drawRect(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, u drawLine(x1, y1, x1, y2, r, g, b, a); } -bool DrawUtils::initFont() { + +bool DrawUtils::initFont(OSSharedDataType fontType) { void *font = nullptr; uint32_t size = 0; - OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size); + OSGetSharedData(fontType, 0, &font, &size); if (font && size) { pFont.xScale = 22; @@ -207,35 +216,59 @@ bool DrawUtils::initFont() { return false; } -bool DrawUtils::setFont(OSSharedDataType fontType) { - void *font = nullptr; - uint32_t size = 0; - OSGetSharedData(fontType, 0, &font, &size); - if (font && size) { - pFont.xScale = 22; - pFont.yScale = 22, - pFont.flags = SFT_DOWNWARD_Y; - pFont.font = sft_loadmem(font, size); - if (!pFont.font) { +bool DrawUtils::setFont() { + cFont = pFont; + return true; +} + +#ifdef KFONT +bool DrawUtils::initKFont() { + uint8_t * kfont = nullptr; + uint32_t size = 0; + size = loadFile("romfs:/ttf/21513_Keyboard.ttf",&kfont); + if (kfont && size) { + kFont.xScale = 44; + kFont.yScale = 44, + kFont.flags = SFT_DOWNWARD_Y; + kFont.font = sft_loadmem(kfont, size); + if (!kFont.font) { return false; } - OSMemoryBarrier(); - return true; + } else { + return false; } - return false; + return true; } +bool DrawUtils::setKFont() { + cFont = kFont; + return true; +} +#endif + void DrawUtils::deinitFont() { sft_freefont(pFont.font); pFont.font = nullptr; pFont = {}; +#ifdef KFONT + sft_freefont(kFont.font); + kFont.font = nullptr; + kFont = {}; +#endif } void DrawUtils::setFontColor(Color col) { font_col = col; } +void DrawUtils::setFontColorByCursor(Color col, Color colAtCursor,int cursorPos, int line) { + if (cursorPos == line) + font_col = colAtCursor; + else + font_col = col; +} + static void draw_freetype_bitmap(SFT_Image *bmp, int32_t x, int32_t y) { int32_t i, j, p, q; @@ -283,18 +316,23 @@ void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignR uint16_t textureWidth = 0, textureHeight = 0; for (; *string; string++) { SFT_Glyph gid; // unsigned long gid; - if (sft_lookup(&pFont, *string, &gid) >= 0) { + if (sft_lookup(&cFont, *string, &gid) >= 0) { SFT_GMetrics mtx; - if (sft_gmetrics(&pFont, gid, &mtx) < 0) { + if (sft_gmetrics(&cFont, gid, &mtx) < 0) { return; } + + if (*string == '\n') { - penY += mtx.minHeight; + //penY += mtx.minHeight; + penY += 30; // temporal fix for multiline output penX = x; continue; } + + textureWidth = (mtx.minWidth + 3) & ~3; textureHeight = mtx.minHeight; @@ -316,7 +354,7 @@ void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignR return; } img.pixels = buffer.get(); - if (sft_render(&pFont, gid, img) < 0) { + if (sft_render(&cFont, gid, img) < 0) { return; } else { draw_freetype_bitmap(&img, (int32_t) (penX + mtx.leftSideBearing), (int32_t) (penY + mtx.yOffset)); @@ -349,9 +387,9 @@ uint32_t DrawUtils::getTextWidth(const wchar_t *string) { for (; *string; string++) { SFT_Glyph gid; // unsigned long gid; - if (sft_lookup(&pFont, *string, &gid) >= 0) { + if (sft_lookup(&cFont, *string, &gid) >= 0) { SFT_GMetrics mtx; - sft_gmetrics(&pFont, gid, &mtx); + sft_gmetrics(&cFont, gid, &mtx); width += (int32_t) mtx.advanceWidth; } } @@ -458,4 +496,11 @@ void DrawUtils::drawRGB5A3(int x, int y, float scale, uint8_t *fileContent) { drawRect(x - 3, y - 3, x + nw + 2, y + nh + 2, 255, 255, 255, 128); } } +} + +void DrawUtils::drawKey(int x,int y,int x_off,Color color) { + int xtop = x*52-26+x_off+5; + int ytop = (y+Y_OFF)*50-25-5; + drawRect(xtop,ytop,xtop+52,ytop+50,color.r,color.g,color.b,color.a); + } \ No newline at end of file diff --git a/src/utils/InputUtils.cpp b/src/utils/InputUtils.cpp index 750e166..7523f47 100644 --- a/src/utils/InputUtils.cpp +++ b/src/utils/InputUtils.cpp @@ -61,6 +61,12 @@ bool Input::get(ButtonState state, Button button) const { if (kpadClassicState & WPAD_CLASSIC_BUTTON_X) return true; if (kpadProState & WPAD_PRO_BUTTON_X) return true; break; + case PAD_BUTTON_Y: + if (vpadState & VPAD_BUTTON_Y) return true; + if (kpadState & WPAD_BUTTON_2) return true; + if (kpadClassicState & WPAD_CLASSIC_BUTTON_Y) return true; + if (kpadProState & WPAD_PRO_BUTTON_Y) return true; + break; case PAD_BUTTON_UP: if (vpadState & VPAD_BUTTON_UP) return true; if (vpadState & VPAD_STICK_L_EMULATION_UP) return true; @@ -99,7 +105,6 @@ bool Input::get(ButtonState state, Button button) const { break; case PAD_BUTTON_L: if (vpadState & VPAD_BUTTON_L) return true; - if (kpadState & WPAD_BUTTON_MINUS) return true; if (kpadClassicState & WPAD_CLASSIC_BUTTON_L) return true; if (kpadProState & WPAD_PRO_TRIGGER_L) return true; break; @@ -109,6 +114,18 @@ bool Input::get(ButtonState state, Button button) const { if (kpadClassicState & WPAD_CLASSIC_BUTTON_R) return true; if (kpadProState & WPAD_PRO_TRIGGER_R) return true; break; + case PAD_BUTTON_PLUS: + if (vpadState & VPAD_BUTTON_PLUS) return true; + if (kpadState & WPAD_BUTTON_PLUS) return true; + if (kpadClassicState & WPAD_CLASSIC_BUTTON_PLUS) return true; + if (kpadProState & WPAD_PRO_BUTTON_PLUS) return true; + break; + case PAD_BUTTON_MINUS: + if (vpadState & VPAD_BUTTON_MINUS) return true; + if (kpadState & WPAD_BUTTON_MINUS) return true; + if (kpadClassicState & WPAD_CLASSIC_BUTTON_MINUS) return true; + if (kpadProState & WPAD_PRO_BUTTON_MINUS) return true; + break; case PAD_BUTTON_ANY: if (vpadState) return true; if (kpadState) return true; diff --git a/src/utils/KeyboardUtils.cpp b/src/utils/KeyboardUtils.cpp new file mode 100644 index 0000000..736c2b8 --- /dev/null +++ b/src/utils/KeyboardUtils.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#define MAX_INPUT_SIZE 30 + +void Keyboard::render() { +} + +std::string Keyboard::ucs4ToUtf8(const std::u32string& in) +{ + std::wstring_convert, char32_t> conv; + return conv.to_bytes(in); +} + +std::u32string Keyboard::utf8ToUcs4(const std::string& in) +{ + std::wstring_convert, char32_t> conv; + return conv.from_bytes(in); +} + +int Keyboard::kbLeft() { + if (column > 0) + column--; + else + column = getKeyboardRowSize(row)-1; + setCurrentKey(); + return column; +} + +int Keyboard::kbRight() { + if ( column < getKeyboardRowSize(row)-1) + column++; + else + column = 0; + setCurrentKey(); + return column; +} + +int Keyboard::kbUp() { + if ( row > 0 ) + row--; + else + row = (int) currentKeyboard.size()-1; + if (column > getKeyboardRowSize(row)-1) + column = getKeyboardRowSize(row)-1; + setCurrentKey(); + return row; +} + +int Keyboard::kbDown() { + if ( row < (int) currentKeyboard.size()-1 ) + row++; + else + row = 0; + if (column > getKeyboardRowSize(row)-1) + column = getKeyboardRowSize(row)-1; + setCurrentKey(); + return row; +} + +void Keyboard::shiftPressed() { + currentKeyboard = ( currentKeyboard == keysNormal ? keysShift : keysNormal ); + if (column > getKeyboardRowSize(row)-1) + column = getKeyboardRowSize(row)-1; + setCurrentKey(); +} + +void Keyboard::kbKeyPressed() { + if (input.size() < MAX_INPUT_SIZE ) + input.append(ucs4ToUtf8(currentKey)); +} + +void Keyboard::delPressed() { + if (input.size() > 0) + input.pop_back(); +} + +void Keyboard::setCurrentKey() { + currentKey = currentKeyboard[row].substr(column,1); +} + +std::string Keyboard::getKey(int row_,int column_) { + return ucs4ToUtf8(currentKeyboard[row_].substr(column_,1)); +} + +std::string Keyboard::getCurrentKey() { + return ucs4ToUtf8(currentKeyboard[row].substr(column,1)); +} + +int Keyboard::getKeyboardRowSize(int row_) { + return currentKeyboard[row_].size(); +} \ No newline at end of file diff --git a/src/utils/LanguageUtils.cpp b/src/utils/LanguageUtils.cpp index 468145a..44c66c5 100644 --- a/src/utils/LanguageUtils.cpp +++ b/src/utils/LanguageUtils.cpp @@ -13,57 +13,57 @@ void LanguageUtils::loadLanguage(Swkbd_LanguageType language) { loadedLang = language; switch (language) { case Swkbd_LanguageType__Japanese: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/japanese.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/japanese.json"); break; case Swkbd_LanguageType__English: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/english.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/english.json"); break; /*case Swkbd_LanguageType__French: - gettextLoadLanguage("romfs:/french.json"); + gettextLoadLanguage("romfs:/languages/french.json"); break; */ case Swkbd_LanguageType__German: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/german.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/german.json"); break; case Swkbd_LanguageType__Italian: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/italian.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/italian.json"); break; case Swkbd_LanguageType__Spanish: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/spanish.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/spanish.json"); break; case Swkbd_LanguageType__Chinese1: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_CHINESE); - gettextLoadLanguage("romfs:/TChinese.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_CHINESE); + gettextLoadLanguage("romfs:/languages/TChinese.json"); break; case Swkbd_LanguageType__Korean: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_KOREAN); - gettextLoadLanguage("romfs:/korean.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_KOREAN); + gettextLoadLanguage("romfs:/languages/korean.json"); break; /* case Swkbd_LanguageType__Dutch: - gettextLoadLanguage("romfs:/dutch.json"); + gettextLoadLanguage("romfs:/languages/dutch.json"); break; */ case Swkbd_LanguageType__Portuguese: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/portuguese.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/portuguese.json"); break; case Swkbd_LanguageType__Russian: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/russian.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/russian.json"); break; case Swkbd_LanguageType__Chinese2: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_CHINESE); - gettextLoadLanguage("romfs:/SChinese.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_CHINESE); + gettextLoadLanguage("romfs:/languages/SChinese.json"); break; default: - DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); - gettextLoadLanguage("romfs:/english.json"); + DrawUtils::initFont(OS_SHAREDDATATYPE_FONT_STANDARD); + gettextLoadLanguage("romfs:/languages/english.json"); break; } }