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>
|
<name>NS-USBloader</name>
|
||||||
|
|
||||||
<artifactId>ns-usbloader</artifactId>
|
<artifactId>ns-usbloader</artifactId>
|
||||||
<version>6.2</version>
|
<version>7.0</version>
|
||||||
|
|
||||||
<url>https://redrise.ru</url>
|
<url>https://redrise.ru</url>
|
||||||
<description>
|
<description>
|
||||||
NS multi tool
|
NS multi tool
|
||||||
</description>
|
</description>
|
||||||
<inceptionYear>2019</inceptionYear>
|
<inceptionYear>2019.0.2.1</inceptionYear>
|
||||||
<organization>
|
<organization>
|
||||||
<name>Dmitry Isaenko</name>
|
<name>Dmitry Isaenko</name>
|
||||||
<url>https://developersu.blogspot.com/</url>
|
<url>https://developersu.blogspot.com/</url>
|
||||||
|
@ -61,28 +61,28 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>linux</classifier>
|
<classifier>linux</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-media</artifactId>
|
<artifactId>javafx-media</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>linux</classifier>
|
<classifier>linux</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>linux</classifier>
|
<classifier>linux</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-graphics</artifactId>
|
<artifactId>javafx-graphics</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>linux</classifier>
|
<classifier>linux</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -90,28 +90,28 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>win</classifier>
|
<classifier>win</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-media</artifactId>
|
<artifactId>javafx-media</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>win</classifier>
|
<classifier>win</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>win</classifier>
|
<classifier>win</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-graphics</artifactId>
|
<artifactId>javafx-graphics</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>win</classifier>
|
<classifier>win</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -119,28 +119,28 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac</classifier>
|
<classifier>mac</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-media</artifactId>
|
<artifactId>javafx-media</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac</classifier>
|
<classifier>mac</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac</classifier>
|
<classifier>mac</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-graphics</artifactId>
|
<artifactId>javafx-graphics</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac</classifier>
|
<classifier>mac</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -148,28 +148,28 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-controls</artifactId>
|
<artifactId>javafx-controls</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac-aarch64</classifier>
|
<classifier>mac-aarch64</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-media</artifactId>
|
<artifactId>javafx-media</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac-aarch64</classifier>
|
<classifier>mac-aarch64</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-fxml</artifactId>
|
<artifactId>javafx-fxml</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac-aarch64</classifier>
|
<classifier>mac-aarch64</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>org.openjfx</groupId>
|
||||||
<artifactId>javafx-graphics</artifactId>
|
<artifactId>javafx-graphics</artifactId>
|
||||||
<version>19</version>
|
<version>19.0.2.1</version>
|
||||||
<classifier>mac-aarch64</classifier>
|
<classifier>mac-aarch64</classifier>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -309,7 +309,7 @@
|
||||||
<fileVersion>1.0.0.0</fileVersion>
|
<fileVersion>1.0.0.0</fileVersion>
|
||||||
<txtFileVersion>${project.version}</txtFileVersion>
|
<txtFileVersion>${project.version}</txtFileVersion>
|
||||||
<fileDescription>NS multi tool</fileDescription>
|
<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>
|
<productVersion>1.0.0.0</productVersion>
|
||||||
<txtProductVersion>${project.version}</txtProductVersion>
|
<txtProductVersion>${project.version}</txtProductVersion>
|
||||||
<companyName>${project.organization.name}</companyName>
|
<companyName>${project.organization.name}</companyName>
|
||||||
|
|
|
@ -41,15 +41,17 @@ import nsusbloader.NSLDataTypes.EModule;
|
||||||
import nsusbloader.ServiceWindow;
|
import nsusbloader.ServiceWindow;
|
||||||
import nsusbloader.Utilities.patches.es.EsPatchMaker;
|
import nsusbloader.Utilities.patches.es.EsPatchMaker;
|
||||||
import nsusbloader.Utilities.patches.fs.FsPatchMaker;
|
import nsusbloader.Utilities.patches.fs.FsPatchMaker;
|
||||||
|
import nsusbloader.Utilities.patches.loader.LoaderPatchMaker;
|
||||||
|
|
||||||
// TODO: CLI SUPPORT
|
// TODO: CLI SUPPORT
|
||||||
public class PatchesController implements Initializable {
|
public class PatchesController implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
private VBox patchesToolPane;
|
private VBox patchesToolPane;
|
||||||
@FXML
|
@FXML
|
||||||
private Button selFwFolderBtn, selProdKeysBtn, makeEsBtn, makeFsBtn;
|
private Button makeEsBtn, makeFsBtn, makeLoaderBtn;
|
||||||
@FXML
|
@FXML
|
||||||
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl;
|
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl,
|
||||||
|
locationAtmosphereLbl, shortNameAtmoLbl;
|
||||||
private Thread workThread;
|
private Thread workThread;
|
||||||
|
|
||||||
private String previouslyOpenedPath;
|
private String previouslyOpenedPath;
|
||||||
|
@ -72,13 +74,14 @@ public class PatchesController implements Initializable {
|
||||||
locationKeysLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
locationKeysLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||||
shortNameKeysLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
shortNameKeysLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||||
|
|
||||||
convertRegionEs = new Region();
|
locationAtmosphereLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
|
||||||
convertRegionEs.getStyleClass().add("regionCake");
|
shortNameAtmoLbl.setText(updatedText.replaceAll(myRegexp, "")));
|
||||||
|
|
||||||
|
convertRegionEs = createCakeRegion();
|
||||||
makeEsBtn.setGraphic(convertRegionEs);
|
makeEsBtn.setGraphic(convertRegionEs);
|
||||||
|
|
||||||
Region cakeRegionFs = new Region();
|
makeFsBtn.setGraphic(createCakeRegion());
|
||||||
cakeRegionFs.getStyleClass().add("regionCake");
|
makeLoaderBtn.setGraphic(createCakeRegion());
|
||||||
makeFsBtn.setGraphic(cakeRegionFs);
|
|
||||||
|
|
||||||
AppPreferences preferences = AppPreferences.getInstance();
|
AppPreferences preferences = AppPreferences.getInstance();
|
||||||
String keysLocation = preferences.getKeysLocation();
|
String keysLocation = preferences.getKeysLocation();
|
||||||
|
@ -89,11 +92,23 @@ public class PatchesController implements Initializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
saveToLbl.setText(preferences.getPatchesSaveToLocation());
|
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());
|
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());
|
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)
|
if (firmware == null)
|
||||||
return;
|
return;
|
||||||
locationFirmwareLbl.setText(firmware.getAbsolutePath());
|
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
|
@FXML
|
||||||
private void selectSaveTo(){
|
private void selectSaveTo(){
|
||||||
|
@ -153,16 +180,17 @@ public class PatchesController implements Initializable {
|
||||||
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
|
||||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("keys", "*.dat", "*.keys"));
|
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("keys", "*.dat", "*.keys"));
|
||||||
File keys = fileChooser.showOpenDialog(patchesToolPane.getScene().getWindow());
|
File keys = fileChooser.showOpenDialog(patchesToolPane.getScene().getWindow());
|
||||||
|
if (keys == null || ! keys.exists())
|
||||||
|
return;
|
||||||
|
|
||||||
if (keys != null && keys.exists()) {
|
|
||||||
locationKeysLbl.setText(keys.getAbsolutePath());
|
locationKeysLbl.setText(keys.getAbsolutePath());
|
||||||
}
|
previouslyOpenedPath = keys.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void makeEs(){
|
private void makeEs(){
|
||||||
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
||||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||||
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
|
resourceBundle.getString("tabPatches_ServiceWindowMessageEsFs"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +214,7 @@ public class PatchesController implements Initializable {
|
||||||
private void makeFs(){
|
private void makeFs(){
|
||||||
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
|
||||||
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
|
||||||
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
|
resourceBundle.getString("tabPatches_ServiceWindowMessageEsFs"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +235,29 @@ public class PatchesController implements Initializable {
|
||||||
workThread.setDaemon(true);
|
workThread.setDaemon(true);
|
||||||
workThread.start();
|
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(){
|
private void interruptProcessOfPatchMaking(){
|
||||||
if (workThread == null || ! workThread.isAlive())
|
if (workThread == null || ! workThread.isAlive())
|
||||||
return;
|
return;
|
||||||
|
@ -222,6 +273,7 @@ public class PatchesController implements Initializable {
|
||||||
|
|
||||||
convertRegionEs.getStyleClass().clear();
|
convertRegionEs.getStyleClass().clear();
|
||||||
makeFsBtn.setVisible(! isActive);
|
makeFsBtn.setVisible(! isActive);
|
||||||
|
makeLoaderBtn.setVisible(! isActive);
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
MediatorControl.getInstance().getContoller().logArea.clear();
|
MediatorControl.getInstance().getContoller().logArea.clear();
|
||||||
|
@ -231,8 +283,8 @@ public class PatchesController implements Initializable {
|
||||||
makeEsBtn.setText(resourceBundle.getString("btn_Stop"));
|
makeEsBtn.setText(resourceBundle.getString("btn_Stop"));
|
||||||
makeEsBtn.getStyleClass().remove("buttonUp");
|
makeEsBtn.getStyleClass().remove("buttonUp");
|
||||||
makeEsBtn.getStyleClass().add("buttonStop");
|
makeEsBtn.getStyleClass().add("buttonStop");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
convertRegionEs.getStyleClass().add("regionCake");
|
convertRegionEs.getStyleClass().add("regionCake");
|
||||||
|
|
||||||
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
makeEsBtn.setOnAction(actionEvent -> makeEs());
|
||||||
|
@ -240,7 +292,6 @@ public class PatchesController implements Initializable {
|
||||||
makeEsBtn.getStyleClass().remove("buttonStop");
|
makeEsBtn.getStyleClass().remove("buttonStop");
|
||||||
makeEsBtn.getStyleClass().add("buttonUp");
|
makeEsBtn.getStyleClass().add("buttonUp");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void setOneLineStatus(boolean statusSuccess){
|
public void setOneLineStatus(boolean statusSuccess){
|
||||||
if (statusSuccess)
|
if (statusSuccess)
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class SettingsBlockTinfoilController implements Initializable {
|
||||||
|
|
||||||
final AppPreferences preferences = AppPreferences.getInstance();
|
final AppPreferences preferences = AppPreferences.getInstance();
|
||||||
|
|
||||||
networkExpertSettingsVBox.disableProperty().bind(networkExpertModeCB.selectedProperty().not());
|
networkExpertSettingsVBox.visibleProperty().bind(networkExpertModeCB.selectedProperty());
|
||||||
|
|
||||||
pcIpTF.disableProperty().bind(autoDetectIpCB.selectedProperty());
|
pcIpTF.disableProperty().bind(autoDetectIpCB.selectedProperty());
|
||||||
pcPortTF.disableProperty().bind(randomlySelectPortCB.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);
|
return printImTooLazy("LDP", instructionExpression, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ((instructionExpression >> 23 & 0xff)){
|
switch ((instructionExpression >> 23 & 0x1ff)){
|
||||||
case 0xA5:
|
case 0xA5:
|
||||||
return printMOVSimplified(instructionExpression, offset);
|
return printMOVSimplified(instructionExpression, offset);
|
||||||
case 0x22:
|
case 0x22:
|
||||||
|
@ -123,10 +123,10 @@ public class BinToAsmPrinter {
|
||||||
case 0xA2:
|
case 0xA2:
|
||||||
return printSUBSimplified(instructionExpression, offset);
|
return printSUBSimplified(instructionExpression, offset);
|
||||||
case 0xE2:
|
case 0xE2:
|
||||||
//case 0x1e2:
|
case 0x1e2:
|
||||||
return printCMPSimplified(instructionExpression, offset);
|
return printCMPSimplified(instructionExpression, offset);
|
||||||
case 0x24:
|
case 0x24:
|
||||||
//case 0x124:
|
case 0x124:
|
||||||
return printANDSimplified(instructionExpression, offset);
|
return printANDSimplified(instructionExpression, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,10 @@ public class BinToAsmPrinter {
|
||||||
return printTBZSimplified(instructionExpression, offset);
|
return printTBZSimplified(instructionExpression, offset);
|
||||||
case 0x54:
|
case 0x54:
|
||||||
return printBConditionalSimplified(instructionExpression, offset);
|
return printBConditionalSimplified(instructionExpression, offset);
|
||||||
|
case 0xeb:
|
||||||
|
case 0x6b:
|
||||||
|
if ((instructionExpression & 0x1f) == 0b11111)
|
||||||
|
return printCMPShiftedRegisterSimplified(instructionExpression, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (instructionExpression >> 26 & 0b111111) {
|
switch (instructionExpression >> 26 & 0b111111) {
|
||||||
|
@ -498,6 +502,37 @@ public class BinToAsmPrinter {
|
||||||
LSL);
|
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){
|
private static String printANDSimplified(int instructionExpression, int offset){
|
||||||
String sf = (instructionExpression >> 31 == 0) ? "W" : "X";
|
String sf = (instructionExpression >> 31 == 0) ? "W" : "X";
|
||||||
int Rn = instructionExpression & 0x1F;
|
int Rn = instructionExpression & 0x1F;
|
||||||
|
|
|
@ -31,7 +31,7 @@ import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class IniMaker {
|
public class FsIniMaker {
|
||||||
private static final String FILE_HEADER_TEXT = "# UTF-8\n" +
|
private static final String FILE_HEADER_TEXT = "# UTF-8\n" +
|
||||||
"# A KIP section is [kip1_name:sha256_hex_8bytes]\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" +
|
"# 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 patchSet1;
|
||||||
private String patchSet2;
|
private String patchSet2;
|
||||||
|
|
||||||
IniMaker(ILogPrinter logPrinter,
|
public FsIniMaker(ILogPrinter logPrinter,
|
||||||
String saveToLocation,
|
String saveToLocation,
|
||||||
byte[] _textSection,
|
byte[] _textSection,
|
||||||
int wizardOffset1,
|
int wizardOffset1,
|
|
@ -76,7 +76,7 @@ public class FsPatch {
|
||||||
findAllOffsets();
|
findAllOffsets();
|
||||||
mkDirs();
|
mkDirs();
|
||||||
writeFile();
|
writeFile();
|
||||||
new IniMaker(logPrinter,
|
new FsIniMaker(logPrinter,
|
||||||
saveToLocation,
|
saveToLocation,
|
||||||
_textSection,
|
_textSection,
|
||||||
wizard.getOffset1(),
|
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 minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Firmware" wrapText="true" />
|
||||||
<Label fx:id="shortNameFirmwareLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
|
<Label fx:id="shortNameFirmwareLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<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>
|
<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" />
|
<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>
|
</graphic>
|
||||||
|
@ -60,6 +60,23 @@
|
||||||
<Font name="System Italic" size="13.0" />
|
<Font name="System Italic" size="13.0" />
|
||||||
</font>
|
</font>
|
||||||
</Label>
|
</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>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
<Separator prefWidth="200.0" />
|
<Separator prefWidth="200.0" />
|
||||||
|
@ -70,7 +87,7 @@
|
||||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Keys" wrapText="true" />
|
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Keys" wrapText="true" />
|
||||||
<Label fx:id="shortNameKeysLbl" />
|
<Label fx:id="shortNameKeysLbl" />
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<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>
|
<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" />
|
<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>
|
</graphic>
|
||||||
|
@ -90,7 +107,7 @@
|
||||||
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabSplMrg_Lbl_SaveToLocation" wrapText="true" />
|
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabSplMrg_Lbl_SaveToLocation" wrapText="true" />
|
||||||
<Label fx:id="saveToLbl" />
|
<Label fx:id="saveToLbl" />
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<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>
|
<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" />
|
<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>
|
</graphic>
|
||||||
|
@ -114,6 +131,7 @@
|
||||||
<children>
|
<children>
|
||||||
<Button fx:id="makeEsBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeEs" />
|
<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="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>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
<padding>
|
<padding>
|
||||||
|
|
|
@ -87,6 +87,7 @@ tabPatches_Lbl_Title=Patches
|
||||||
tabPatches_Lbl_Keys=Keys:
|
tabPatches_Lbl_Keys=Keys:
|
||||||
tabPatches_Btn_MakeEs=Make ES
|
tabPatches_Btn_MakeEs=Make ES
|
||||||
tabPatches_Btn_MakeFs=Make FS
|
tabPatches_Btn_MakeFs=Make FS
|
||||||
tabPatches_Btn_MakeAtmo=Make Atmo
|
tabPatches_Btn_MakeAtmo=Make Loader (Atmosphere)
|
||||||
tabPatches_Btn_MakeAll=Make all
|
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_asZipFile=\u0432 \u0432\u0438\u0434\u0435 ZIP
|
||||||
tabPatches_Btn_fromFolder=\u0418\u0437 \u043F\u0430\u043F\u043A\u0438
|
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_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_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_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_Atmo=Atmosphere:
|
||||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0438
|
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0438
|
||||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\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_asZipFile=\u044F\u043A ZIP
|
||||||
tabPatches_Btn_fromFolder=\u0417 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0456\u0457
|
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_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_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_Btn_MakeFs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F FS
|
||||||
tabPatches_Lbl_Atmo=Atmosphere:
|
tabPatches_Lbl_Atmo=Atmosphere:
|
||||||
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
|
||||||
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0456
|
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0456
|
||||||
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
|
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