Hide 'extended network settings' instead of setting it disabled
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c84f70ec10
commit
83695511d3
14 changed files with 557 additions and 134 deletions
38
pom.xml
38
pom.xml
|
@ -8,13 +8,13 @@
|
|||
<name>NS-USBloader</name>
|
||||
|
||||
<artifactId>ns-usbloader</artifactId>
|
||||
<version>6.2</version>
|
||||
<version>7.0</version>
|
||||
|
||||
<url>https://redrise.ru</url>
|
||||
<description>
|
||||
NS multi tool
|
||||
</description>
|
||||
<inceptionYear>2019</inceptionYear>
|
||||
<inceptionYear>2019.0.2.1</inceptionYear>
|
||||
<organization>
|
||||
<name>Dmitry Isaenko</name>
|
||||
<url>https://developersu.blogspot.com/</url>
|
||||
|
@ -61,28 +61,28 @@
|
|||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>linux</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
@ -90,28 +90,28 @@
|
|||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>win</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
@ -119,28 +119,28 @@
|
|||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
@ -148,28 +148,28 @@
|
|||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac-aarch64</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-media</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac-aarch64</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac-aarch64</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>19</version>
|
||||
<version>19.0.2.1</version>
|
||||
<classifier>mac-aarch64</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
@ -309,7 +309,7 @@
|
|||
<fileVersion>1.0.0.0</fileVersion>
|
||||
<txtFileVersion>${project.version}</txtFileVersion>
|
||||
<fileDescription>NS multi tool</fileDescription>
|
||||
<copyright>GNU General Public License v3, 2019 ${project.organization.name}, Russia.</copyright>
|
||||
<copyright>GNU General Public License v3, 2019.0.2.1 ${project.organization.name}, Russia.</copyright>
|
||||
<productVersion>1.0.0.0</productVersion>
|
||||
<txtProductVersion>${project.version}</txtProductVersion>
|
||||
<companyName>${project.organization.name}</companyName>
|
||||
|
|
|
@ -41,15 +41,17 @@ import nsusbloader.NSLDataTypes.EModule;
|
|||
import nsusbloader.ServiceWindow;
|
||||
import nsusbloader.Utilities.patches.es.EsPatchMaker;
|
||||
import nsusbloader.Utilities.patches.fs.FsPatchMaker;
|
||||
import nsusbloader.Utilities.patches.loader.LoaderPatchMaker;
|
||||
|
||||
// TODO: CLI SUPPORT
|
||||
public class PatchesController implements Initializable {
|
||||
@FXML
|
||||
private VBox patchesToolPane;
|
||||
@FXML
|
||||
private Button selFwFolderBtn, selProdKeysBtn, makeEsBtn, makeFsBtn;
|
||||
private Button makeEsBtn, makeFsBtn, makeLoaderBtn;
|
||||
@FXML
|
||||
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl;
|
||||
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl,
|
||||
locationAtmosphereLbl, shortNameAtmoLbl;
|
||||
private Thread workThread;
|
||||
|
||||
private String previouslyOpenedPath;
|
||||
|
@ -72,13 +74,14 @@ public class PatchesController implements Initializable {
|
|||
locationKeysLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||
shortNameKeysLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||
|
||||
convertRegionEs = new Region();
|
||||
convertRegionEs.getStyleClass().add("regionCake");
|
||||
locationAtmosphereLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||
shortNameAtmoLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||
|
||||
convertRegionEs = createCakeRegion();
|
||||
makeEsBtn.setGraphic(convertRegionEs);
|
||||
|
||||
Region cakeRegionFs = new Region();
|
||||
cakeRegionFs.getStyleClass().add("regionCake");
|
||||
makeFsBtn.setGraphic(cakeRegionFs);
|
||||
makeFsBtn.setGraphic(createCakeRegion());
|
||||
makeLoaderBtn.setGraphic(createCakeRegion());
|
||||
|
||||
AppPreferences preferences = AppPreferences.getInstance();
|
||||
String keysLocation = preferences.getKeysLocation();
|
||||
|
@ -89,11 +92,23 @@ public class PatchesController implements Initializable {
|
|||
}
|
||||
|
||||
saveToLbl.setText(preferences.getPatchesSaveToLocation());
|
||||
makeEsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
|
||||
makeEsBtn.disableProperty().bind(Bindings.or(
|
||||
Bindings.isEmpty(locationFirmwareLbl.textProperty()),
|
||||
Bindings.isEmpty(locationKeysLbl.textProperty())));
|
||||
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
||||
|
||||
makeFsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
|
||||
makeFsBtn.disableProperty().bind(Bindings.or(
|
||||
Bindings.isEmpty(locationFirmwareLbl.textProperty()),
|
||||
Bindings.isEmpty(locationKeysLbl.textProperty())));
|
||||
makeFsBtn.setOnAction(actionEvent -> makeFs());
|
||||
|
||||
makeLoaderBtn.disableProperty().bind(Bindings.isEmpty(locationAtmosphereLbl.textProperty()));
|
||||
makeLoaderBtn.setOnAction(actionEvent -> makeLoader());
|
||||
}
|
||||
private Region createCakeRegion(){
|
||||
Region cakeRegion = new Region();
|
||||
cakeRegion.getStyleClass().add("regionCake");
|
||||
return cakeRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,6 +150,18 @@ public class PatchesController implements Initializable {
|
|||
if (firmware == null)
|
||||
return;
|
||||
locationFirmwareLbl.setText(firmware.getAbsolutePath());
|
||||
previouslyOpenedPath = firmware.getParent();
|
||||
}
|
||||
@FXML
|
||||
private void selectAtmosphereFolder(){
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle(resourceBundle.getString("tabPatches_Lbl_Atmo"));
|
||||
directoryChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||
File firmware = directoryChooser.showDialog(patchesToolPane.getScene().getWindow());
|
||||
if (firmware == null)
|
||||
return;
|
||||
locationAtmosphereLbl.setText(firmware.getAbsolutePath());
|
||||
previouslyOpenedPath = firmware.getParent();
|
||||
}
|
||||
@FXML
|
||||
private void selectSaveTo(){
|
||||
|
@ -153,16 +180,17 @@ public class PatchesController implements Initializable {
|
|||
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("keys", "*.dat", "*.keys"));
|
||||
File keys = fileChooser.showOpenDialog(patchesToolPane.getScene().getWindow());
|
||||
if (keys == null || ! keys.exists())
|
||||
return;
|
||||
|
||||
if (keys != null && keys.exists()) {
|
||||
locationKeysLbl.setText(keys.getAbsolutePath());
|
||||
}
|
||||
previouslyOpenedPath = keys.getParent();
|
||||
}
|
||||
|
||||
private void makeEs(){
|
||||
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessageEsFs"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -186,7 +214,7 @@ public class PatchesController implements Initializable {
|
|||
private void makeFs(){
|
||||
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessageEsFs"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,6 +235,29 @@ public class PatchesController implements Initializable {
|
|||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
private void makeLoader(){
|
||||
if (locationAtmosphereLbl.getText().isEmpty()){
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("tabPatches_ServiceWindowMessageLoader"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (workThread != null && workThread.isAlive())
|
||||
return;
|
||||
statusLbl.setText("");
|
||||
|
||||
if (MediatorControl.getInstance().getTransferActive()) {
|
||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||
resourceBundle.getString("windowBodyPleaseStopOtherProcessFirst"));
|
||||
return;
|
||||
}
|
||||
|
||||
LoaderPatchMaker loaderPatchMaker = new LoaderPatchMaker(locationAtmosphereLbl.getText(), saveToLbl.getText());
|
||||
workThread = new Thread(loaderPatchMaker);
|
||||
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
private void interruptProcessOfPatchMaking(){
|
||||
if (workThread == null || ! workThread.isAlive())
|
||||
return;
|
||||
|
@ -222,6 +273,7 @@ public class PatchesController implements Initializable {
|
|||
|
||||
convertRegionEs.getStyleClass().clear();
|
||||
makeFsBtn.setVisible(! isActive);
|
||||
makeLoaderBtn.setVisible(! isActive);
|
||||
|
||||
if (isActive) {
|
||||
MediatorControl.getInstance().getContoller().logArea.clear();
|
||||
|
@ -231,8 +283,8 @@ public class PatchesController implements Initializable {
|
|||
makeEsBtn.setText(resourceBundle.getString("btn_Stop"));
|
||||
makeEsBtn.getStyleClass().remove("buttonUp");
|
||||
makeEsBtn.getStyleClass().add("buttonStop");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
convertRegionEs.getStyleClass().add("regionCake");
|
||||
|
||||
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
||||
|
@ -240,7 +292,6 @@ public class PatchesController implements Initializable {
|
|||
makeEsBtn.getStyleClass().remove("buttonStop");
|
||||
makeEsBtn.getStyleClass().add("buttonUp");
|
||||
}
|
||||
}
|
||||
|
||||
public void setOneLineStatus(boolean statusSuccess){
|
||||
if (statusSuccess)
|
||||
|
|
|
@ -55,7 +55,7 @@ public class SettingsBlockTinfoilController implements Initializable {
|
|||
|
||||
final AppPreferences preferences = AppPreferences.getInstance();
|
||||
|
||||
networkExpertSettingsVBox.disableProperty().bind(networkExpertModeCB.selectedProperty().not());
|
||||
networkExpertSettingsVBox.visibleProperty().bind(networkExpertModeCB.selectedProperty());
|
||||
|
||||
pcIpTF.disableProperty().bind(autoDetectIpCB.selectedProperty());
|
||||
pcPortTF.disableProperty().bind(randomlySelectPortCB.selectedProperty());
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
Copyright 2019-2020 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
NS-USBloader is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Debug tool like hexdump <3
|
||||
*/
|
||||
public class RainbowHexDump {
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_BLACK = "\u001B[30m";
|
||||
private static final String ANSI_RED = "\u001B[31m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
private static final String ANSI_YELLOW = "\u001B[33m";
|
||||
private static final String ANSI_BLUE = "\u001B[34m";
|
||||
private static final String ANSI_PURPLE = "\u001B[35m";
|
||||
private static final String ANSI_CYAN = "\u001B[36m";
|
||||
private static final String ANSI_WHITE = "\u001B[37m";
|
||||
|
||||
public static void hexDumpUTF8(byte[] byteArray){
|
||||
System.out.print(ANSI_BLUE);
|
||||
for (int i=0; i < byteArray.length; i++)
|
||||
System.out.printf("%02d-", i%100);
|
||||
System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
|
||||
for (byte b: byteArray)
|
||||
System.out.printf("%02x ", b);
|
||||
System.out.println();
|
||||
System.out.print("\t\t\t"
|
||||
+ new String(byteArray, StandardCharsets.UTF_8)
|
||||
+ "\n");
|
||||
}
|
||||
|
||||
public static void hexDumpUTF8ForWin(byte[] byteArray){
|
||||
for (int i=0; i < byteArray.length; i++)
|
||||
System.out.printf("%02d-", i%100);
|
||||
System.out.println(">"+byteArray.length);
|
||||
for (byte b: byteArray)
|
||||
System.out.printf("%02x ", b);
|
||||
System.out.println();
|
||||
System.out.print(new String(byteArray, StandardCharsets.UTF_8)
|
||||
+ "\n");
|
||||
}
|
||||
|
||||
public static void hexDumpUTF16LE(byte[] byteArray){
|
||||
System.out.print(ANSI_BLUE);
|
||||
for (int i=0; i < byteArray.length; i++)
|
||||
System.out.printf("%02d-", i%100);
|
||||
System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
|
||||
for (byte b: byteArray)
|
||||
System.out.printf("%02x ", b);
|
||||
System.out.print(new String(byteArray, StandardCharsets.UTF_16LE)
|
||||
+ "\n");
|
||||
}
|
||||
}
|
|
@ -111,7 +111,7 @@ public class BinToAsmPrinter {
|
|||
return printImTooLazy("LDP", instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch ((instructionExpression >> 23 & 0xff)){
|
||||
switch ((instructionExpression >> 23 & 0x1ff)){
|
||||
case 0xA5:
|
||||
return printMOVSimplified(instructionExpression, offset);
|
||||
case 0x22:
|
||||
|
@ -123,10 +123,10 @@ public class BinToAsmPrinter {
|
|||
case 0xA2:
|
||||
return printSUBSimplified(instructionExpression, offset);
|
||||
case 0xE2:
|
||||
//case 0x1e2:
|
||||
case 0x1e2:
|
||||
return printCMPSimplified(instructionExpression, offset);
|
||||
case 0x24:
|
||||
//case 0x124:
|
||||
case 0x124:
|
||||
return printANDSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
|
@ -142,6 +142,10 @@ public class BinToAsmPrinter {
|
|||
return printTBZSimplified(instructionExpression, offset);
|
||||
case 0x54:
|
||||
return printBConditionalSimplified(instructionExpression, offset);
|
||||
case 0xeb:
|
||||
case 0x6b:
|
||||
if ((instructionExpression & 0x1f) == 0b11111)
|
||||
return printCMPShiftedRegisterSimplified(instructionExpression, offset);
|
||||
}
|
||||
|
||||
switch (instructionExpression >> 26 & 0b111111) {
|
||||
|
@ -498,6 +502,37 @@ public class BinToAsmPrinter {
|
|||
LSL);
|
||||
}
|
||||
|
||||
private static String printCMPShiftedRegisterSimplified(int instructionExpression, int offset){
|
||||
String sf = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||
int Rn = instructionExpression >> 5 & 0x1F;
|
||||
int Rm = instructionExpression >> 16 & 0x1F;
|
||||
int imm6 = instructionExpression >> 10 & 0x3f;
|
||||
int LSL = (instructionExpression >> 22 & 0b11);
|
||||
String LSLStr;
|
||||
switch (LSL){
|
||||
case 0b00:
|
||||
LSLStr = "LSL";
|
||||
break;
|
||||
case 0b01:
|
||||
LSLStr = "LSR";
|
||||
break;
|
||||
case 0b10:
|
||||
LSLStr = "ASR";
|
||||
break;
|
||||
case 0b11:
|
||||
LSLStr = "RESERVED";
|
||||
break;
|
||||
default:
|
||||
LSLStr = "?";
|
||||
}
|
||||
|
||||
return String.format(
|
||||
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CMP (sr) " + ANSI_GREEN + sf + "%d," +
|
||||
ANSI_BLUE + sf + "%d " + ANSI_BLUE + LSLStr + ANSI_PURPLE + " %d" + ANSI_RESET + "\n",
|
||||
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
|
||||
Rn, Rm, imm6);
|
||||
}
|
||||
|
||||
private static String printANDSimplified(int instructionExpression, int offset){
|
||||
String sf = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||
int Rn = instructionExpression & 0x1F;
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.nio.file.Paths;
|
|||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class IniMaker {
|
||||
public class FsIniMaker {
|
||||
private static final String FILE_HEADER_TEXT = "# UTF-8\n" +
|
||||
"# A KIP section is [kip1_name:sha256_hex_8bytes]\n" +
|
||||
"# A patchset is .patch_name=kip_section_dec:offset_hex_0x:length_hex_0x:src_data_hex,dst_data_hex\n" +
|
||||
|
@ -48,7 +48,7 @@ public class IniMaker {
|
|||
private String patchSet1;
|
||||
private String patchSet2;
|
||||
|
||||
IniMaker(ILogPrinter logPrinter,
|
||||
public FsIniMaker(ILogPrinter logPrinter,
|
||||
String saveToLocation,
|
||||
byte[] _textSection,
|
||||
int wizardOffset1,
|
|
@ -76,7 +76,7 @@ public class FsPatch {
|
|||
findAllOffsets();
|
||||
mkDirs();
|
||||
writeFile();
|
||||
new IniMaker(logPrinter,
|
||||
new FsIniMaker(logPrinter,
|
||||
saveToLocation,
|
||||
_textSection,
|
||||
wizard.getOffset1(),
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
Copyright 2019-2023 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
NS-USBloader is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.loader;
|
||||
|
||||
import nsusbloader.ModelControllers.ILogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.Utilities.patches.MalformedIniFileException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class LoaderIniMaker {
|
||||
private static final String FILE_HEADER_TEXT = "# UTF-8\n" +
|
||||
"# A KIP section is [kip1_name:sha256_hex_8bytes]\n" +
|
||||
"# A patchset is .patch_name=kip_section_dec:offset_hex_0x:length_hex_0x:src_data_hex,dst_data_hex\n" +
|
||||
"# _dec: 1 char decimal | _hex_0x: max u32 prefixed with 0x | _hex: hex array.\n" +
|
||||
"# Kip1 section decimals: TEXT: 0, RODATA: 1, DATA: 2.\n"; // Sending good vibes to Mr. ITotalJustice
|
||||
|
||||
private final ILogPrinter logPrinter;
|
||||
private final String saveToLocation;
|
||||
private final int offset;
|
||||
|
||||
private String sectionDeclaration;
|
||||
private String patchSet;
|
||||
|
||||
LoaderIniMaker(ILogPrinter logPrinter,
|
||||
String saveToLocation,
|
||||
int foundOffset,
|
||||
String patchName) throws Exception{
|
||||
this.logPrinter = logPrinter;
|
||||
this.saveToLocation = saveToLocation;
|
||||
this.offset = foundOffset + 6;
|
||||
|
||||
mkDirs();
|
||||
makeSectionDeclaration(patchName);
|
||||
makePatchSet1();
|
||||
writeFile();
|
||||
}
|
||||
|
||||
private void mkDirs(){
|
||||
File parentFolder = new File(saveToLocation + File.separator + "bootloader");
|
||||
parentFolder.mkdirs();
|
||||
}
|
||||
|
||||
private void makeSectionDeclaration(String patchName){
|
||||
sectionDeclaration = "[Loader:"+patchName.substring(0, 16)+"]";
|
||||
}
|
||||
|
||||
private void makePatchSet1(){
|
||||
patchSet = String.format(".nosigchk=0:0x%02X:0x1:01,00", offset);
|
||||
}
|
||||
|
||||
private void writeFile() throws Exception{
|
||||
final String iniLocation = saveToLocation + File.separator + "bootloader" + File.separator + "patches.ini";
|
||||
final Path iniLocationPath = Paths.get(iniLocation);
|
||||
|
||||
boolean iniNotExists = Files.notExists(iniLocationPath);
|
||||
|
||||
try (RandomAccessFile ini = new RandomAccessFile(iniLocation, "rw")){
|
||||
if (iniNotExists)
|
||||
ini.writeBytes(FILE_HEADER_TEXT);
|
||||
else {
|
||||
String line;
|
||||
while ((line = ini.readLine()) != null){
|
||||
if (! line.startsWith(sectionDeclaration))
|
||||
continue;
|
||||
|
||||
String expression = ini.readLine();
|
||||
|
||||
if (expression == null || ! expression.startsWith(patchSet))
|
||||
throw new MalformedIniFileException("Somewhere near "+ini.getFilePointer());
|
||||
|
||||
return; // Ini file already contains correct information regarding patch file we made.
|
||||
}
|
||||
}
|
||||
|
||||
ini.writeBytes("\n#Loader (Atmosphere)\n");
|
||||
ini.writeBytes(sectionDeclaration);
|
||||
ini.writeBytes("\n");
|
||||
|
||||
ini.writeBytes(patchSet);
|
||||
ini.writeBytes("\n");
|
||||
}
|
||||
catch (MalformedIniFileException e){
|
||||
e.printStackTrace();
|
||||
logPrinter.print(
|
||||
"Existing patches.ini file is malformed or contains incorrect (outdated) information regarding current patch.\n" +
|
||||
"It's now saved at "+iniLocation+".OLD\n" +
|
||||
"New patches.ini file created instead.", EMsgType.WARNING);
|
||||
Files.move(iniLocationPath, Paths.get(iniLocation+".OLD"),
|
||||
StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
|
||||
writeFile();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
Copyright 2018-2023 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
NS-USBloader is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
---
|
||||
Based on https://github.com/mrdude2478/IPS_Patch_Creator patch script made by GBATemp member MrDude.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.loader;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.fs.other.System2.ini1.KIP1Provider;
|
||||
import nsusbloader.ModelControllers.ILogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.Utilities.patches.BinToAsmPrinter;
|
||||
import nsusbloader.Utilities.patches.SimplyFind;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LoaderPatch {
|
||||
private static final byte[] HEADER = "PATCH".getBytes(StandardCharsets.US_ASCII);
|
||||
private static final byte[] FOOTER = "EOF".getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
private static final String ATMOSPHERE_NEW_PATTERN = "01C0BE121F00016B";
|
||||
//private static final String ATMOSPHERE_OLD_PATTERN = "003C00121F280071"; Must be patched using different (to current implementation) code
|
||||
|
||||
private final String saveToLocation;
|
||||
private final ILogPrinter logPrinter;
|
||||
|
||||
private String patchName;
|
||||
private byte[] _textSection;
|
||||
|
||||
private int offset;
|
||||
|
||||
LoaderPatch(KIP1Provider loaderProvider,
|
||||
String saveToLocation,
|
||||
ILogPrinter logPrinter) throws Exception{
|
||||
this.saveToLocation = saveToLocation;
|
||||
this.logPrinter = logPrinter;
|
||||
|
||||
getPatchName(loaderProvider);
|
||||
getTextSection(loaderProvider);
|
||||
findOffset();
|
||||
mkDirs();
|
||||
writeFile();
|
||||
new LoaderIniMaker(logPrinter, saveToLocation, offset, patchName);
|
||||
}
|
||||
private void getPatchName(KIP1Provider kip1Provider) throws Exception{
|
||||
int kip1EncryptedSize = (int) kip1Provider.getSize();
|
||||
byte[] kip1EncryptedRaw = new byte[kip1EncryptedSize];
|
||||
|
||||
try (BufferedInputStream kip1ProviderStream = kip1Provider.getStreamProducer().produce()) {
|
||||
if (kip1EncryptedSize != kip1ProviderStream.read(kip1EncryptedRaw))
|
||||
throw new Exception("Unencrypted FS KIP1 read failure");
|
||||
}
|
||||
|
||||
byte[] sha256ofKip1 = MessageDigest.getInstance("SHA-256").digest(kip1EncryptedRaw);
|
||||
patchName = Converter.byteArrToHexStringAsLE(sha256ofKip1, true) + ".ips";
|
||||
}
|
||||
private void getTextSection(KIP1Provider kip1Provider) throws Exception{
|
||||
_textSection = kip1Provider.getAsDecompressed().getTextRaw();
|
||||
}
|
||||
private void findOffset() throws Exception{
|
||||
SimplyFind simplyFind = new SimplyFind(ATMOSPHERE_NEW_PATTERN, _textSection); // Atm 13+
|
||||
if (simplyFind.getResults().size() == 0)
|
||||
throw new Exception("Offset not found");
|
||||
|
||||
offset = simplyFind.getResults().get(0);
|
||||
|
||||
if (offset <= 0)
|
||||
throw new Exception("Found offset is incorrect");
|
||||
|
||||
for (int i = 0; i < simplyFind.getResults().size(); i++) {
|
||||
int offsetInternal = simplyFind.getResults().get(i) + 4;
|
||||
logPrinter.print("Only first (#1) found record will be patched!", EMsgType.INFO);
|
||||
logPrinter.print("Found #" + (i+1) +"\n"+
|
||||
BinToAsmPrinter.printSimplified(Converter.getLEint(_textSection, offsetInternal), offsetInternal) +
|
||||
BinToAsmPrinter.printSimplified(Converter.getLEint(_textSection, offsetInternal + 4), offsetInternal + 4) +
|
||||
BinToAsmPrinter.printSimplified(Converter.getLEint(_textSection, offsetInternal + 8), offsetInternal + 8) +
|
||||
BinToAsmPrinter.printSimplified(Converter.getLEint(_textSection, offsetInternal + 12), offsetInternal + 12),
|
||||
EMsgType.NULL);
|
||||
}
|
||||
}
|
||||
private void mkDirs(){
|
||||
File parentFolder = new File(saveToLocation + File.separator +
|
||||
"atmosphere" + File.separator + "kip_patches" + File.separator + "loader_patches");
|
||||
parentFolder.mkdirs();
|
||||
}
|
||||
|
||||
private void writeFile() throws Exception{
|
||||
String patchFileLocation = saveToLocation + File.separator +
|
||||
"atmosphere" + File.separator + "kip_patches" + File.separator + "fs_patches" + File.separator + patchName;
|
||||
|
||||
ByteBuffer handyFsPatch = ByteBuffer.allocate(0x100).order(ByteOrder.LITTLE_ENDIAN);
|
||||
handyFsPatch.put(HEADER);
|
||||
handyFsPatch.put(getPatch1(offset));
|
||||
handyFsPatch.put(FOOTER);
|
||||
|
||||
byte[] fsPatch = new byte[handyFsPatch.position()];
|
||||
handyFsPatch.rewind();
|
||||
handyFsPatch.get(fsPatch);
|
||||
|
||||
try (BufferedOutputStream stream = new BufferedOutputStream(
|
||||
Files.newOutputStream(Paths.get(patchFileLocation)))){
|
||||
stream.write(fsPatch);
|
||||
}
|
||||
logPrinter.print("Patch created at "+patchFileLocation, EMsgType.PASS);
|
||||
}
|
||||
|
||||
private byte[] getPatch1(int offset) throws Exception{
|
||||
int requiredInstructionOffsetInternal = offset + 6;
|
||||
int requiredInstructionOffsetReal = requiredInstructionOffsetInternal + 0x100;
|
||||
final byte[] patch = new byte[]{0x00, 0x01, 0x00};
|
||||
|
||||
int instructionPatched = Converter.getLEint(_textSection, offset + 4) & 0xff00ffff;
|
||||
|
||||
logPrinter.print("Patch will be applied", EMsgType.PASS);
|
||||
logPrinter.print(BinToAsmPrinter.printSimplified(instructionPatched, offset+4), EMsgType.NULL);
|
||||
|
||||
ByteBuffer prePatch = ByteBuffer.allocate(7).order(ByteOrder.BIG_ENDIAN)
|
||||
.putInt(requiredInstructionOffsetReal)
|
||||
.put(patch);
|
||||
|
||||
return Arrays.copyOfRange(prePatch.array(), 1, 7);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of NS-USBloader.
|
||||
|
||||
NS-USBloader is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
NS-USBloader is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package nsusbloader.Utilities.patches.loader;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.fs.other.System2.ini1.KIP1Provider;
|
||||
import nsusbloader.ModelControllers.CancellableRunnable;
|
||||
import nsusbloader.ModelControllers.ILogPrinter;
|
||||
import nsusbloader.ModelControllers.Log;
|
||||
import nsusbloader.NSLDataTypes.EModule;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.Utilities.patches.SimplyFind;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
|
||||
public class LoaderPatchMaker extends CancellableRunnable {
|
||||
|
||||
private final ILogPrinter logPrinter;
|
||||
private final String atmosphereLocation;
|
||||
private final String saveTo;
|
||||
|
||||
private String package3Location;
|
||||
private KIP1Provider loaderProvider;
|
||||
|
||||
private boolean oneLinerStatus = false;
|
||||
|
||||
public LoaderPatchMaker(String atmosphereLocation, String saveTo){
|
||||
this.logPrinter = Log.getPrinter(EModule.PATCHES);
|
||||
/*
|
||||
this.logPrinter = new ILogPrinter() {
|
||||
public void print(String message, EMsgType type) throws InterruptedException {}
|
||||
public void updateProgress(Double value) throws InterruptedException {}
|
||||
public void update(HashMap<String, File> nspMap, EFileStatus status) {}
|
||||
public void update(File file, EFileStatus status) {}
|
||||
public void updateOneLinerStatus(boolean status) {}
|
||||
public void close() {}
|
||||
};
|
||||
//*/
|
||||
this.atmosphereLocation = atmosphereLocation;
|
||||
this.saveTo = saveTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
logPrinter.print("..:: Make Loader Patches ::..", EMsgType.INFO);
|
||||
checkPackage3();
|
||||
createLoaderKip1Provider();
|
||||
makePatches();
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
try{
|
||||
logPrinter.print(e.getMessage(), EMsgType.FAIL);
|
||||
} catch (Exception ignore){}
|
||||
}
|
||||
finally {
|
||||
logPrinter.updateOneLinerStatus(oneLinerStatus);
|
||||
logPrinter.close();
|
||||
}
|
||||
}
|
||||
private void checkPackage3() throws Exception{
|
||||
logPrinter.print("Looking at Atmosphere", EMsgType.INFO);
|
||||
if (Files.notExists(Paths.get(atmosphereLocation)))
|
||||
throw new Exception("Atmosphere directory does not exist at " + atmosphereLocation);
|
||||
|
||||
package3Location = atmosphereLocation +File.separator+"package3";
|
||||
if (Files.exists(Paths.get(package3Location)))
|
||||
return;
|
||||
|
||||
package3Location = atmosphereLocation +File.separator+"fusee-secondary.bin";
|
||||
if (Files.notExists(Paths.get(package3Location)))
|
||||
throw new Exception("package3 / fusee-secondary.bin file not found at " + atmosphereLocation);
|
||||
}
|
||||
|
||||
private void createLoaderKip1Provider() throws Exception{
|
||||
Path package3Path = Paths.get(package3Location);
|
||||
|
||||
try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(package3Path))) {
|
||||
byte[] data = new byte[0x400];
|
||||
if (0x400 != stream.read(data))
|
||||
throw new Exception("Failed to read first 0x400 bytes of package3 / fusee-secondary file.");
|
||||
|
||||
SimplyFind simplyFind = new SimplyFind(".6f61646572", data); // eq. '.oader'
|
||||
List<Integer> results = simplyFind.getResults();
|
||||
if (results.size() == 0)
|
||||
throw new Exception("Failed to find 'Loader' offset at package3 / fusee-secondary file.");
|
||||
|
||||
int offset = results.get(0);
|
||||
int kip1Offset = Converter.getLEint(data, offset - 0x10);
|
||||
int kip1Size = Converter.getLEint(data, offset - 0xC);
|
||||
|
||||
loaderProvider = new KIP1Provider(package3Location, kip1Offset);
|
||||
|
||||
if (kip1Size != loaderProvider.getSize())
|
||||
throw new Exception("Incorrect calculations for KIP1. PK31 value: "+kip1Size+"KIP1Provider value: "+loaderProvider.getSize());
|
||||
logPrinter.print("Loader KIP1 found", EMsgType.PASS);
|
||||
}
|
||||
}
|
||||
private void makePatches() throws Exception{
|
||||
new LoaderPatch(loaderProvider, saveTo, logPrinter);
|
||||
oneLinerStatus = true;
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@
|
|||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Firmware" wrapText="true" />
|
||||
<Label fx:id="shortNameFirmwareLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selFwFolderBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectFirmware" styleClass="buttonSelect" text="%tabSplMrg_Btn_SelectFolder" wrapText="true">
|
||||
<Button minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectFirmware" styleClass="buttonSelect" text="%tabSplMrg_Btn_SelectFolder" wrapText="true">
|
||||
<graphic>
|
||||
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
|
||||
</graphic>
|
||||
|
@ -60,6 +60,23 @@
|
|||
<Font name="System Italic" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<HBox alignment="CENTER_LEFT" spacing="5.0">
|
||||
<children>
|
||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Atmo" wrapText="true" />
|
||||
<Label fx:id="shortNameAtmoLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectAtmosphereFolder" styleClass="buttonSelect" text="%tabSplMrg_Btn_SelectFolder" wrapText="true">
|
||||
<graphic>
|
||||
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</children>
|
||||
</HBox>
|
||||
<Label fx:id="locationAtmosphereLbl" disable="true" textOverrun="LEADING_WORD_ELLIPSIS">
|
||||
<font>
|
||||
<Font name="System Italic" size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</VBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
|
@ -70,7 +87,7 @@
|
|||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Keys" wrapText="true" />
|
||||
<Label fx:id="shortNameKeysLbl" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selProdKeysBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectProdKeys" styleClass="buttonSelect" text="%btn_Select">
|
||||
<Button minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectProdKeys" styleClass="buttonSelect" text="%btn_Select">
|
||||
<graphic>
|
||||
<SVGPath content="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" fill="#289de8" />
|
||||
</graphic>
|
||||
|
@ -90,7 +107,7 @@
|
|||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabSplMrg_Lbl_SaveToLocation" wrapText="true" />
|
||||
<Label fx:id="saveToLbl" />
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="selProdKeysBtn1" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectSaveTo" styleClass="buttonSelect" text="%btn_Select">
|
||||
<Button minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectSaveTo" styleClass="buttonSelect" text="%btn_Select">
|
||||
<graphic>
|
||||
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
|
||||
</graphic>
|
||||
|
@ -114,6 +131,7 @@
|
|||
<children>
|
||||
<Button fx:id="makeEsBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeEs" />
|
||||
<Button fx:id="makeFsBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeFs" />
|
||||
<Button fx:id="makeLoaderBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeAtmo" />
|
||||
</children>
|
||||
</HBox>
|
||||
<padding>
|
||||
|
|
|
@ -87,6 +87,7 @@ tabPatches_Lbl_Title=Patches
|
|||
tabPatches_Lbl_Keys=Keys:
|
||||
tabPatches_Btn_MakeEs=Make ES
|
||||
tabPatches_Btn_MakeFs=Make FS
|
||||
tabPatches_Btn_MakeAtmo=Make Atmo
|
||||
tabPatches_Btn_MakeAtmo=Make Loader (Atmosphere)
|
||||
tabPatches_Btn_MakeAll=Make all
|
||||
tabPatches_ServiceWindowMessage=Both firmware and keys should be set to generate patches. Otherwise, it's not clear what to patch.
|
||||
tabPatches_ServiceWindowMessageEsFs=Both firmware and keys should be set to generate patches. Otherwise, it's not clear what to patch.
|
||||
tabPatches_ServiceWindowMessageLoader=Atmosphere folder should be defined to generate 'Loader' patch.
|
||||
|
|
|
@ -80,13 +80,14 @@ tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
|
|||
tabPatches_Btn_asZipFile=\u0432 \u0432\u0438\u0434\u0435 ZIP
|
||||
tabPatches_Btn_fromFolder=\u0418\u0437 \u043F\u0430\u043F\u043A\u0438
|
||||
tabPatches_Btn_MakeAll=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0441\u0451
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F Atmo
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F Loader (Atmosphere)
|
||||
tabPatches_Btn_MakeEs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F ES
|
||||
tabPatches_Btn_MakeFs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F FS
|
||||
tabPatches_Lbl_Atmo=Atmosphere:
|
||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0438
|
||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
|
||||
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u0430\u0442\u0447\u0435\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043A\u0430\u043A \u043F\u0443\u0442\u044C \u043A \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0435, \u0442\u0430\u043A \u0438 \u043F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0435\u0439. \u0418\u043D\u0430\u0447\u0435 \u043D\u0435 \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u0447\u0442\u043E \u0436\u0435 \u043F\u0430\u0442\u0447\u0438\u0442\u044C.
|
||||
tabPatches_ServiceWindowMessageEsFs=\u0414\u043B\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u0430\u0442\u0447\u0435\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043A\u0430\u043A \u043F\u0443\u0442\u044C \u043A \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0435, \u0442\u0430\u043A \u0438 \u043F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0435\u0439. \u0418\u043D\u0430\u0447\u0435 \u043D\u0435 \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u0447\u0442\u043E \u0436\u0435 \u043F\u0430\u0442\u0447\u0438\u0442\u044C.
|
||||
tabPatches_ServiceWindowMessageLoader=\u0414\u043B\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u0430\u0442\u0447\u0430 \u00ABLoader\u00BB \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0443\u0442\u044C \u043A Atmosphere.
|
||||
|
||||
|
||||
|
|
|
@ -80,12 +80,13 @@ tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
|
|||
tabPatches_Btn_asZipFile=\u044F\u043A ZIP
|
||||
tabPatches_Btn_fromFolder=\u0417 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0456\u0457
|
||||
tabPatches_Btn_MakeAll=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0432\u0441\u0456
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F Atmo
|
||||
tabPatches_Btn_MakeAtmo=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F Loader (Atmosphere)
|
||||
tabPatches_Btn_MakeEs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F ES
|
||||
tabPatches_Btn_MakeFs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F FS
|
||||
tabPatches_Lbl_Atmo=Atmosphere:
|
||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0456
|
||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
|
||||
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u043F\u0430\u0442\u0447\u0456\u0432 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u043E \u0432\u043A\u0430\u0437\u0430\u0442\u0438 \u044F\u043A \u0448\u043B\u044F\u0445 \u0434\u043E \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0438, \u0442\u0430\u043A \u0456 \u0434\u043E \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0456\u0432. \u0411\u043E \u0456\u043D\u0430\u043A\u0448\u0435 \u043D\u0435 \u0437\u0440\u043E\u0437\u0443\u043C\u0456\u043B\u043E \u0449\u043E \u0436 \u0442\u0440\u0435\u0431\u0430 \u043F\u0430\u0442\u0447\u0438\u0442\u0438.
|
||||
tabPatches_ServiceWindowMessageEsFs=\u0414\u043B\u044F \u0441\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u043F\u0430\u0442\u0447\u0456\u0432 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u043E \u0432\u043A\u0430\u0437\u0430\u0442\u0438 \u044F\u043A \u0448\u043B\u044F\u0445 \u0434\u043E \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0438, \u0442\u0430\u043A \u0456 \u0434\u043E \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0456\u0432. \u0411\u043E \u0456\u043D\u0430\u043A\u0448\u0435 \u043D\u0435 \u0437\u0440\u043E\u0437\u0443\u043C\u0456\u043B\u043E \u0449\u043E \u0436 \u0442\u0440\u0435\u0431\u0430 \u043F\u0430\u0442\u0447\u0438\u0442\u0438.
|
||||
tabPatches_ServiceWindowMessageLoader=\u0414\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0456\u0457 "Loader"-\u043F\u0430\u0442\u0447\u0443 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u043E \u0432\u043A\u0430\u0437\u0430\u0442\u0438 \u0448\u043B\u044F\u0445 \u0434\u043E Atmosphere.
|
||||
|
||||
|
|
Loading…
Reference in a new issue