v0.6 GoldLeaf v0.6.1 support
This commit is contained in:
parent
d34d522f46
commit
cd73968306
20 changed files with 1076 additions and 597 deletions
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
|
@ -15,7 +15,7 @@ pipeline {
|
|||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'target/*-jar-with-dependencies.jar', onlyIfSuccessful: true
|
||||
archiveArtifacts artifacts: 'target/*.jar, target/*.exe', onlyIfSuccessful: true
|
||||
}
|
||||
}
|
||||
}
|
30
README.md
30
README.md
|
@ -2,6 +2,8 @@
|
|||
|
||||
![License](https://img.shields.io/badge/License-GPLv3-blue.svg) [![Releases](https://img.shields.io/github/downloads/developersu/ns-usbloader/total.svg)]() [![LatestVer](https://img.shields.io/github/release/developersu/ns-usbloader.svg)]()
|
||||
|
||||
[Support author](#support-this-app)
|
||||
|
||||
NS-USBloader is a PC-side **[Adubbz/TinFoil](https://github.com/Adubbz/Tinfoil/)** (version 0.2.1; USB and Network) and **GoldLeaf** (USB) NSP installer. Replacement for default **usb_install_pc.py**, **remote_install_pc.py** *(never ever use this. even if you brave. no idea why it works.)* and **GoldTree**.
|
||||
|
||||
[Click here for Android version ;)](https://github.com/developersu/ns-usbloader-mobile)
|
||||
|
@ -68,13 +70,15 @@ Set 'Security & Privacy' settings if needed.
|
|||
|
||||
#### And how to use it?
|
||||
|
||||
The first thing you should do it install TinFoil ([Adubbz](https://github.com/Adubbz/Tinfoil/)) or GoldLeaf ([XorTroll](https://github.com/XorTroll/Goldleaf)) on your NS. I recommend using TinFoil, but it ups to you. Take a look on app, find where is the option to install from USB and/or Network. Maybe [this article](https://developersu.blogspot.com/2019/02/ns-usbloader-en.html) will be helpful.
|
||||
The first thing you should do it install TinFoil ([Adubbz](https://github.com/Adubbz/Tinfoil/)) or GoldLeaf ([XorTroll](https://github.com/XorTroll/Goldleaf)) on your NS.
|
||||
|
||||
Here is the version of 'not perfect but anyway' [tinfoil I use](https://cloud.mail.ru/public/DwbX/H8d2p3aYR).
|
||||
Ok, I'm almost sure that this version has bugs. I don't remember where I downloaded it. But it works for me somehow.
|
||||
|
||||
Let's rephrase, if you have working version of TinFoil **DO NOT** use this one. Ok. let's begin.
|
||||
|
||||
Take a look on app, find where is the option to install from USB and/or Network. Maybe [this article](https://developersu.blogspot.com/2019/02/ns-usbloader-en.html) will be helpful.
|
||||
|
||||
There are three tabs. First one is main.
|
||||
|
||||
##### First tab.
|
||||
|
@ -85,13 +89,23 @@ Then you may drag-n-drop folder with NSPs OR files to application or use 'Select
|
|||
|
||||
Table.
|
||||
|
||||
There you can select checkbox for files that will be send to application (TF/GL). Since GoldLeaf allow you only one file transmission per time, only one file is available for selection. Also you can use space to select/un-select files and 'delete' button for deleting. By right-mouse-click you can see context menu where you can delete one OR all items from the table.
|
||||
There you can select checkbox for files that will be send to application (TF/GL). ~~Since GoldLeaf allow you only one file transmission per time, only one file is available for selection.~~
|
||||
|
||||
Also you can use space to select/un-select files and 'delete' button for deleting. By right-mouse-click you can see context menu where you can delete one OR all items from the table.
|
||||
|
||||
For GoldLeaf v0.6.1 and NS-USBloader v0.6 (and higher) you will have to use 'Explore content' -> 'Remote PC (via USB)' You will see two drives HOME:/ and VIRT:/. First drive is pointing to your home directory. Second one is reflection of what you've added to table (first application tab). Also VIRT:/ drive have limited functionality in comparison to HOME:/. E.g. you can't write files to this drive since it's not a drive. But don't worry, it won't make any impact on GoldLeaf or your NS if you try.
|
||||
|
||||
Also, for GoldLeaf write files (from NS to PC): You have to 'Stop execution' properly before accessing files transferred from GL. Usually you have to wait 5sec or less. It will guarantee that your files properly written to PC.
|
||||
|
||||
## NOTE: NS-USBloader v0.6 doesn't support writing files from NS to PC if file size is greater than 8mb
|
||||
|
||||
##### Second tab.
|
||||
|
||||
Here you can configure settings for network file transmission. Usually you shouldn't change anything. But it you're cool hacker, go ahead! The most interesting option here is 'Don't serve requests'. Architecture of the TinFoil's NET part is working interesting way. When you select in TF network NSP transfer, application will wait at port 2000 for the information about where should it take files from. Like '192.168.1.5:6060/my file.nsp'. Usually NS-USBloader serves requests by implementing simplified HTTP server and bringing it up and so on. But if this option selected, you can define path to remote location of the files. For example if you set in settings '192.168.4.2:80/ROMS/NS/' and add in table file 'my file.nsp' then NS-USBloader will simply tell TinFoil "Hey, go take files from '192.168.4.2:80/ROMS/NS/my%20file.nsp' ". Of course you have to bring '192.168.4.2' host up and make file accessible from such address (just go install nginx). As I said, this feature is interesting, but I guess won't be popular.
|
||||
|
||||
Also here you can check 'Auto-check for updates' or click button to verify if new version released or not.
|
||||
Also here you can:
|
||||
* Set 'Auto-check for updates' for checking for updates when application starts, or click button to verify if new version released immediately.
|
||||
* Set 'Show only *.nsp in GoldLeaf' to filter all files displayed at HOME:/ drive. So only NSP files will appear.
|
||||
|
||||
##### Third tab.
|
||||
|
||||
|
@ -102,7 +116,7 @@ Why when 'NET' once started it never ends?
|
|||
Because there is HTTP server inside of application. It can't determine the moment when all transmissions finishes (unless they failed). So you have to look on your NS screen and 'Interrupt' it once done.
|
||||
|
||||
### Known bugs
|
||||
* Unable to interrupt transmission when libusb awaiting for read event (when user sent NSP list but didn't select anything on NS). Sometimes this issue also appears when network transmission started and nothing received from NS.
|
||||
* Unable to interrupt transmission when using TinFoil (when user sent NSP list but didn't select anything on NS). Sometimes this issue also appears when network transmission started and nothing received from NS.
|
||||
|
||||
### Other notes
|
||||
'Status' = 'Uploaded' that appears in the table does not mean that file has been installed. It means that it has been sent to NS without any issues! That's what this app about.
|
||||
|
@ -112,9 +126,7 @@ usb4java since NS-USBloader-v0.2.3 switched to 1.2.0 instead of 1.3.0. This shou
|
|||
|
||||
### Translators!
|
||||
If you want to see this app translated to your language, go grab [this file](https://github.com/developersu/ns-usbloader/blob/master/src/main/resources/locale.properties) and translate it.
|
||||
Upload somewhere (pastebin? google drive? whatever else). [Create new issue](https://github.com/developersu/ns-usbloader/issues) and post a link. I'll grab it and add.
|
||||
|
||||
NOTE: actually it's not gonna work in real, because we should stay in touch and I'll need you when add something that should be translated =(
|
||||
Upload somewhere (create PR, use pastebin/google drive/whatever else). [Create new issue](https://github.com/developersu/ns-usbloader/issues) and post a link. I'll grab it and add.
|
||||
|
||||
#### TODO (maybe):
|
||||
- [x] [Android support](https://github.com/developersu/ns-usbloader-mobile)
|
||||
|
@ -122,11 +134,11 @@ NOTE: actually it's not gonna work in real, because we should stay in touch and
|
|||
- [ ] More deep file analyze before uploading.
|
||||
- [ ] XCI support
|
||||
|
||||
#### Support this app
|
||||
## Support this app
|
||||
|
||||
If you like this app, just give a star.
|
||||
|
||||
If you want to make a donation* (see below), refer to this page:
|
||||
Want to support development? Make a donation* (see below):
|
||||
|
||||
[Yandex.Money](https://money.yandex.ru/to/410014301951665)
|
||||
|
||||
|
|
BIN
appicon.ico
Normal file
BIN
appicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
50
pom.xml
50
pom.xml
|
@ -8,7 +8,7 @@
|
|||
<name>NS-USBloader</name>
|
||||
|
||||
<artifactId>ns-usbloader</artifactId>
|
||||
<version>0.5.3-SNAPSHOT</version>
|
||||
<version>0.6-SNAPSHOT</version>
|
||||
|
||||
<url>https://github.com/developersu/ns-usbloader/</url>
|
||||
<description>
|
||||
|
@ -22,8 +22,8 @@
|
|||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GPLv3</name>
|
||||
<url>LICENSE</url>
|
||||
<name>GNU General Public License v3</name>
|
||||
<url>http://www.gnu.org/licenses/gpl.txt</url>
|
||||
<distribution>manual</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
@ -140,7 +140,7 @@
|
|||
<dependency>
|
||||
<groupId>org.usb4java</groupId>
|
||||
<artifactId>usb4java</artifactId>
|
||||
<version>1.2.0</version>
|
||||
<version>1.3.0</version> <!-- Must be 1.2.0 for macOS lower than Mojave -->
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -191,6 +191,48 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Launch4j -->
|
||||
<plugin>
|
||||
<groupId>com.akathist.maven.plugins.launch4j</groupId>
|
||||
<version>1.7.25</version>
|
||||
<artifactId>launch4j-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>l4j-NS-USBloader</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>launch4j</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<headerType>gui</headerType>
|
||||
<icon>appicon.ico</icon>
|
||||
<outfile>target/NS-USBloader-${project.version}.exe</outfile>
|
||||
<jar>target/ns-usbloader-${project.version}-jar-with-dependencies.jar</jar>
|
||||
<errTitle>NS-USBloader</errTitle>
|
||||
<classPath>
|
||||
<mainClass>nsusbloader.Main</mainClass>
|
||||
<addDependencies>false</addDependencies>
|
||||
<preCp>anything</preCp>
|
||||
</classPath>
|
||||
<jre>
|
||||
<minVersion>1.8</minVersion>
|
||||
</jre>
|
||||
<versionInfo>
|
||||
<fileVersion>0.6.0.0</fileVersion>
|
||||
<txtFileVersion>${project.version}</txtFileVersion>
|
||||
<fileDescription>TinFoil and GoldLeaf installer for your NS</fileDescription>
|
||||
<copyright>GNU General Public License v3, 2019 ${organization.name}. Russia/LPR.</copyright>
|
||||
<productVersion>0.6.0.0</productVersion>
|
||||
<txtProductVersion>${project.version}</txtProductVersion>
|
||||
<companyName>${organization.name}</companyName>
|
||||
<productName>${project.name}</productName>
|
||||
<internalName>${project.name}</internalName>
|
||||
<originalFilename>${project.name}.exe</originalFilename>
|
||||
</versionInfo>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -25,7 +25,8 @@ public class AppPreferences {
|
|||
String HostPort,
|
||||
String HostExtra,
|
||||
boolean autoCheck4Updates,
|
||||
boolean tinfoilXciSupport
|
||||
boolean tinfoilXciSupport,
|
||||
boolean nspFileFilterForGl
|
||||
){
|
||||
setProtocol(Protocol);
|
||||
setRecent(PreviouslyOpened);
|
||||
|
@ -41,6 +42,7 @@ public class AppPreferences {
|
|||
setHostExtra(HostExtra);
|
||||
setAutoCheckUpdates(autoCheck4Updates);
|
||||
setTfXCI(tinfoilXciSupport);
|
||||
setNspFileFilterGL(nspFileFilterForGl);
|
||||
}
|
||||
public String getTheme(){
|
||||
String theme = preferences.get("THEME", "/res/app_dark.css"); // Don't let user to change settings manually
|
||||
|
@ -109,4 +111,7 @@ public class AppPreferences {
|
|||
|
||||
public String getLanguage(){return preferences.get("USR_LANG", Locale.getDefault().getISO3Language());}
|
||||
public void setLanguage(String langStr){preferences.put("USR_LANG", langStr);}
|
||||
|
||||
public boolean getNspFileFilterGL(){return preferences.getBoolean("GL_NSP_FILTER", false); }
|
||||
public void setNspFileFilterGL(boolean prop){preferences.putBoolean("GL_NSP_FILTER", prop);}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import javafx.scene.control.*;
|
|||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Region;
|
||||
import nsusbloader.AppPreferences;
|
||||
import nsusbloader.MediatorControl;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -49,6 +50,11 @@ public class FrontController implements Initializable {
|
|||
nsIpTextField.setVisible(true);
|
||||
}
|
||||
}
|
||||
// Really bad disable-enable upload button function
|
||||
if (tableFilesListController.isFilesForUploadListEmpty())
|
||||
MediatorControl.getInstance().getContoller().disableUploadStopBtn(true);
|
||||
else
|
||||
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
|
||||
}); // Add listener to notify tableView controller
|
||||
tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem()); // Notify tableView controller
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import nsusbloader.USB.UsbCommunications;
|
|||
import java.io.File;
|
||||
import java.net.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
@ -56,7 +57,10 @@ public class NSLMainController implements Initializable {
|
|||
|
||||
MediatorControl.getInstance().setController(this);
|
||||
|
||||
uploadStopBtn.setDisable(true);
|
||||
if (FrontTabController.getSelectedProtocol().equals("TinFoil"))
|
||||
uploadStopBtn.setDisable(true);
|
||||
else
|
||||
uploadStopBtn.setDisable(false);
|
||||
selectNspBtn.setOnAction(e->{ selectFilesBtnAction(); });
|
||||
uploadStopBtn.setOnAction(e->{ uploadBtnAction(); });
|
||||
|
||||
|
@ -128,23 +132,26 @@ public class NSLMainController implements Initializable {
|
|||
if ((workThread == null || !workThread.isAlive())){
|
||||
// Collect files
|
||||
List<File> nspToUpload;
|
||||
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) == null) {
|
||||
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) == null && FrontTabController.getSelectedProtocol().equals("TinFoil")) {
|
||||
logArea.setText(resourceBundle.getString("logsNoFolderFileSelected"));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
|
||||
for (File item: nspToUpload)
|
||||
logArea.appendText(" "+item.getAbsolutePath()+"\n");
|
||||
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) != null){
|
||||
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
|
||||
for (File item: nspToUpload)
|
||||
logArea.appendText(" "+item.getAbsolutePath()+"\n");
|
||||
}
|
||||
else {
|
||||
logArea.clear();
|
||||
nspToUpload = new LinkedList<>();
|
||||
}
|
||||
}
|
||||
// If USB selected
|
||||
if (FrontTabController.getSelectedProtocol().equals("GoldLeaf") ||
|
||||
(
|
||||
FrontTabController.getSelectedProtocol().equals("TinFoil")
|
||||
&& FrontTabController.getSelectedNetUsb().equals("USB")
|
||||
)
|
||||
( FrontTabController.getSelectedProtocol().equals("TinFoil") && FrontTabController.getSelectedNetUsb().equals("USB") )
|
||||
){
|
||||
usbNetCommunications = new UsbCommunications(nspToUpload, FrontTabController.getSelectedProtocol());
|
||||
usbNetCommunications = new UsbCommunications(nspToUpload, FrontTabController.getSelectedProtocol(), SettingsTabController.getNSPFileFilterForGL());
|
||||
workThread = new Thread(usbNetCommunications);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
|
@ -217,7 +224,10 @@ public class NSLMainController implements Initializable {
|
|||
* Crunch. Now you see that I'm not a programmer.. This function called from NSTableViewController
|
||||
* */
|
||||
public void disableUploadStopBtn(boolean disable){
|
||||
uploadStopBtn.setDisable(disable);
|
||||
if (FrontTabController.getSelectedProtocol().equals("TinFoil"))
|
||||
uploadStopBtn.setDisable(disable);
|
||||
else
|
||||
uploadStopBtn.setDisable(false);
|
||||
}
|
||||
/**
|
||||
* Drag-n-drop support (dragOver consumer)
|
||||
|
@ -285,7 +295,8 @@ public class NSLMainController implements Initializable {
|
|||
SettingsTabController.getHostPort(),
|
||||
SettingsTabController.getHostExtra(),
|
||||
SettingsTabController.getAutoCheckForUpdates(),
|
||||
SettingsTabController.getTfXCISupport()
|
||||
SettingsTabController.getTfXCISupport(),
|
||||
SettingsTabController.getNSPFileFilterForGL()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.io.File;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class NSTableViewController implements Initializable {
|
||||
|
@ -33,8 +32,6 @@ public class NSTableViewController implements Initializable {
|
|||
private TableView<NSLRowModel> table;
|
||||
private ObservableList<NSLRowModel> rowsObsLst;
|
||||
|
||||
private String protocol;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
rowsObsLst = FXCollections.observableArrayList();
|
||||
|
@ -55,7 +52,6 @@ public class NSTableViewController implements Initializable {
|
|||
} else if (keyEvent.getCode() == KeyCode.SPACE) {
|
||||
for (NSLRowModel item : table.getSelectionModel().getSelectedItems()) {
|
||||
item.setMarkForUpload(!item.isMarkForUpload());
|
||||
restrictSelection(item);
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
|
@ -107,7 +103,6 @@ public class NSTableViewController implements Initializable {
|
|||
@Override
|
||||
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) {
|
||||
model.setMarkForUpload(newValue);
|
||||
restrictSelection(model);
|
||||
}
|
||||
});
|
||||
return booleanProperty;
|
||||
|
@ -162,7 +157,7 @@ public class NSTableViewController implements Initializable {
|
|||
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
|
||||
NSLRowModel thisItem = row.getItem();
|
||||
thisItem.setMarkForUpload(!thisItem.isMarkForUpload());
|
||||
restrictSelection(thisItem);
|
||||
table.refresh();
|
||||
}
|
||||
mouseEvent.consume();
|
||||
}
|
||||
|
@ -174,18 +169,6 @@ public class NSTableViewController implements Initializable {
|
|||
table.setItems(rowsObsLst);
|
||||
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
|
||||
}
|
||||
/**
|
||||
* See uploadColumn callback. In case of GoldLeaf we have to restrict selection
|
||||
* */
|
||||
private void restrictSelection(NSLRowModel modelChecked){
|
||||
if (!protocol.equals("TinFoil") && rowsObsLst.size() > 1) { // Tinfoil doesn't need any restrictions. If only one file in list, also useless
|
||||
for (NSLRowModel model: rowsObsLst){
|
||||
if (model != modelChecked)
|
||||
model.setMarkForUpload(false);
|
||||
}
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Add files when user selected them
|
||||
* */
|
||||
|
@ -196,21 +179,15 @@ public class NSTableViewController implements Initializable {
|
|||
filesAlreayInList.add(model.getNspFileName());
|
||||
for (File file: newFiles)
|
||||
if (!filesAlreayInList.contains(file.getName())) {
|
||||
if (protocol.equals("TinFoil"))
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
else
|
||||
rowsObsLst.add(new NSLRowModel(file, false));
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (File file: newFiles)
|
||||
if (protocol.equals("TinFoil"))
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
else
|
||||
rowsObsLst.add(new NSLRowModel(file, false));
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
|
||||
}
|
||||
rowsObsLst.get(0).setMarkForUpload(true);
|
||||
//rowsObsLst.get(0).setMarkForUpload(true);
|
||||
table.refresh();
|
||||
}
|
||||
/**
|
||||
|
@ -237,14 +214,16 @@ public class NSTableViewController implements Initializable {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
public boolean isFilesForUploadListEmpty(){
|
||||
return rowsObsLst.isEmpty();
|
||||
}
|
||||
/**
|
||||
* Update files in case something is wrong. Requested from UsbCommunications
|
||||
* */
|
||||
public void setFileStatus(String fileName, EFileStatus status){
|
||||
for (NSLRowModel model: rowsObsLst){
|
||||
if (model.getNspFileName().equals(fileName)){
|
||||
if (model.getNspFileName().equals(fileName))
|
||||
model.setStatus(status);
|
||||
}
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
|
@ -252,25 +231,10 @@ public class NSTableViewController implements Initializable {
|
|||
* Called if selected different USB protocol
|
||||
* */
|
||||
public void setNewProtocol(String newProtocol){
|
||||
protocol = newProtocol;
|
||||
if (rowsObsLst.isEmpty())
|
||||
return;
|
||||
if (newProtocol.equals("TinFoil")){
|
||||
for (NSLRowModel model: rowsObsLst)
|
||||
model.setMarkForUpload(true);
|
||||
}
|
||||
else {
|
||||
ListIterator<NSLRowModel> iterator = rowsObsLst.listIterator();
|
||||
while (iterator.hasNext()){
|
||||
NSLRowModel current = iterator.next();
|
||||
if (current.getNspFileName().toLowerCase().endsWith("xci"))
|
||||
iterator.remove();
|
||||
else
|
||||
current.setMarkForUpload(false);
|
||||
}
|
||||
if (!rowsObsLst.isEmpty())
|
||||
rowsObsLst.get(0).setMarkForUpload(true);
|
||||
}
|
||||
if (! newProtocol.equals("TinFoil"))
|
||||
rowsObsLst.removeIf(current -> current.getNspFileName().toLowerCase().endsWith("xci"));
|
||||
table.refresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ import java.util.jar.JarEntry;
|
|||
import java.util.jar.JarFile;
|
||||
|
||||
public class SettingsController implements Initializable {
|
||||
|
||||
@FXML
|
||||
private CheckBox nspFilesFilterForGLCB;
|
||||
@FXML
|
||||
private CheckBox validateNSHostNameCb;
|
||||
@FXML
|
||||
|
@ -64,6 +65,8 @@ public class SettingsController implements Initializable {
|
|||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
nspFilesFilterForGLCB.setSelected(AppPreferences.getInstance().getNspFileFilterGL());
|
||||
|
||||
validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded());
|
||||
|
||||
expertSettingsVBox.setDisable(!AppPreferences.getInstance().getExpertMode());
|
||||
|
@ -243,7 +246,7 @@ public class SettingsController implements Initializable {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
public boolean getNSPFileFilterForGL(){return nspFilesFilterForGLCB.isSelected(); }
|
||||
public boolean getExpertModeSelected(){ return expertModeCb.isSelected(); }
|
||||
public boolean getAutoIpSelected(){ return autoDetectIpCb.isSelected(); }
|
||||
public boolean getRandPortSelected(){ return randPortCb.isSelected(); }
|
||||
|
|
|
@ -49,7 +49,7 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
}
|
||||
catch (UnsupportedEncodingException uee){
|
||||
isValid = false;
|
||||
logPrinter.print("NET: Unsupported encoding for 'URLEncoder'. Internal issue you can't fix. Please report. . Returned:\n\t"+uee.getMessage(), EMsgType.FAIL);
|
||||
logPrinter.print("NET: Unsupported encoding for 'URLEncoder'. Internal issue you can't fix. Please report. Returned:\n\t"+uee.getMessage(), EMsgType.FAIL);
|
||||
for (File nspFile : filesList)
|
||||
nspMap.put(nspFile.getName(), nspFile);
|
||||
close(EFileStatus.FAILED);
|
||||
|
|
|
@ -24,7 +24,7 @@ public class NETPacket {
|
|||
"Accept-Ranges: bytes\r\n"+
|
||||
"Content-Range: bytes %d-%d/%d\r\n"+
|
||||
"Content-Length: %d\r\n"+
|
||||
"Last-Modified: Mon, 18 Mar 2019 12:57:33 GMT\r\n\r\n";
|
||||
"Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT\r\n\r\n";
|
||||
private static final String CODE_400 =
|
||||
"HTTP/1.0 400 invalid range\r\n"+
|
||||
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||
|
|
|
@ -12,10 +12,9 @@ import java.util.Locale;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
public class NSLMain extends Application {
|
||||
public static final String appVersion = "v0.5.3";
|
||||
public static final String appVersion = "v0.6";
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception{
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
||||
|
||||
Locale userLocale = new Locale(AppPreferences.getInstance().getLanguage()); // NOTE: user locale based on ISO3 Language codes
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package nsusbloader.USB.PFS;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Data class to hold NCA, tik, xml etc. meta-information
|
||||
* */
|
||||
public class NCAFile {
|
||||
//private int ncaNumber;
|
||||
private byte[] ncaFileName;
|
||||
private long ncaOffset;
|
||||
private long ncaSize;
|
||||
|
||||
//public void setNcaNumber(int ncaNumber){ this.ncaNumber = ncaNumber; }
|
||||
public void setNcaFileName(byte[] ncaFileName) { this.ncaFileName = ncaFileName; }
|
||||
public void setNcaOffset(long ncaOffset) { this.ncaOffset = ncaOffset; }
|
||||
public void setNcaSize(long ncaSize) { this.ncaSize = ncaSize; }
|
||||
|
||||
//public int getNcaNumber() {return this.ncaNumber; }
|
||||
public byte[] getNcaFileName() { return ncaFileName; }
|
||||
public byte[] getNcaFileNameLength() { return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ncaFileName.length).array(); }
|
||||
public long getNcaOffset() { return ncaOffset; }
|
||||
public long getNcaSize() { return ncaSize; }
|
||||
}
|
|
@ -1,218 +0,0 @@
|
|||
package nsusbloader.USB.PFS;
|
||||
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.ServiceWindow;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Used in GoldLeaf USB protocol
|
||||
* */
|
||||
public class PFSProvider {
|
||||
private static final byte[] PFS0 = new byte[]{(byte)0x50, (byte)0x46, (byte)0x53, (byte)0x30}; // PFS0, and what did you think?
|
||||
|
||||
private LogPrinter logPrinter;
|
||||
private ResourceBundle rb;
|
||||
|
||||
private RandomAccessFile randAccessFile;
|
||||
private String nspFileName;
|
||||
private NCAFile[] ncaFiles;
|
||||
private long bodySize;
|
||||
private int ticketID = -1;
|
||||
|
||||
public PFSProvider(File nspFile, LogPrinter logPrinter){
|
||||
this.logPrinter = logPrinter;
|
||||
try {
|
||||
this.randAccessFile = new RandomAccessFile(nspFile, "r");
|
||||
nspFileName = nspFile.getName();
|
||||
}
|
||||
catch (FileNotFoundException fnfe){
|
||||
logPrinter.print("PFS File not founnd: \n "+fnfe.getMessage(), EMsgType.FAIL);
|
||||
nspFileName = null;
|
||||
}
|
||||
Locale userLocale = new Locale(Locale.getDefault().getISO3Language());
|
||||
rb = ResourceBundle.getBundle("locale", userLocale);
|
||||
}
|
||||
|
||||
public boolean init() {
|
||||
if (nspFileName == null)
|
||||
return false;
|
||||
|
||||
int filesCount;
|
||||
int header;
|
||||
|
||||
logPrinter.print("PFS Start NSP file analyze for ["+nspFileName+"]", EMsgType.INFO);
|
||||
try {
|
||||
byte[] fileStartingBytes = new byte[12];
|
||||
// Read PFS0, files count, header, padding (4 zero bytes)
|
||||
if (randAccessFile.read(fileStartingBytes) == 12)
|
||||
logPrinter.print("PFS Read file starting bytes.", EMsgType.PASS);
|
||||
else {
|
||||
logPrinter.print("PFS Read file starting bytes.", EMsgType.FAIL);
|
||||
randAccessFile.close();
|
||||
return false;
|
||||
}
|
||||
// Check PFS0
|
||||
if (Arrays.equals(PFS0, Arrays.copyOfRange(fileStartingBytes, 0, 4)))
|
||||
logPrinter.print("PFS Read 'PFS0'.", EMsgType.PASS);
|
||||
else {
|
||||
logPrinter.print("PFS Read 'PFS0'.", EMsgType.WARNING);
|
||||
if (!ServiceWindow.getConfirmationWindow(nspFileName+"\n"+rb.getString("windowTitleConfirmWrongPFS0"), rb.getString("windowBodyConfirmWrongPFS0"))) {
|
||||
randAccessFile.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Get files count
|
||||
filesCount = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 4, 8)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
if (filesCount > 0 ) {
|
||||
logPrinter.print("PFS Read files count [" + filesCount + "]", EMsgType.PASS);
|
||||
}
|
||||
else {
|
||||
logPrinter.print("PFS Read files count", EMsgType.FAIL);
|
||||
randAccessFile.close();
|
||||
return false;
|
||||
}
|
||||
// Get header
|
||||
header = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 8, 12)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
if (header > 0 )
|
||||
logPrinter.print("PFS Read header ["+header+"]", EMsgType.PASS);
|
||||
else {
|
||||
logPrinter.print("PFS Read header ", EMsgType.FAIL);
|
||||
randAccessFile.close();
|
||||
return false;
|
||||
}
|
||||
//*********************************************************************************************
|
||||
// Create NCA set
|
||||
this.ncaFiles = new NCAFile[filesCount];
|
||||
// Collect files from NSP
|
||||
byte[] ncaInfoArr = new byte[24]; // should be unsigned long, but.. java.. u know my pain man
|
||||
|
||||
HashMap<Integer, Long> ncaNameOffsets = new LinkedHashMap<>();
|
||||
|
||||
int offset;
|
||||
long nca_offset;
|
||||
long nca_size;
|
||||
long nca_name_offset;
|
||||
|
||||
for (int i=0; i<filesCount; i++){
|
||||
if (randAccessFile.read(ncaInfoArr) == 24) {
|
||||
logPrinter.print("PFS Read NCA inside NSP: " + i, EMsgType.PASS);
|
||||
}
|
||||
else {
|
||||
logPrinter.print("PFS Read NCA inside NSP: "+i, EMsgType.FAIL);
|
||||
randAccessFile.close();
|
||||
return false;
|
||||
}
|
||||
offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
nca_offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 4, 12)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||
nca_size = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 12, 20)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||
nca_name_offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 20, 24)).order(ByteOrder.LITTLE_ENDIAN).getInt(); // yes, cast from int to long.
|
||||
|
||||
logPrinter.print(" Padding check", offset == 0?EMsgType.PASS:EMsgType.WARNING);
|
||||
logPrinter.print(" NCA offset check: "+nca_offset, nca_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
|
||||
logPrinter.print(" NCA size check: "+nca_size, nca_size >= 0?EMsgType.PASS: EMsgType.WARNING);
|
||||
logPrinter.print(" NCA name offset check: "+nca_name_offset, nca_name_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
|
||||
|
||||
NCAFile ncaFile = new NCAFile();
|
||||
ncaFile.setNcaOffset(nca_offset);
|
||||
ncaFile.setNcaSize(nca_size);
|
||||
this.ncaFiles[i] = ncaFile;
|
||||
|
||||
ncaNameOffsets.put(i, nca_name_offset);
|
||||
}
|
||||
// Final offset
|
||||
byte[] bufForInt = new byte[4];
|
||||
if ((randAccessFile.read(bufForInt) == 4) && (Arrays.equals(bufForInt, new byte[4])))
|
||||
logPrinter.print("PFS Final padding check", EMsgType.PASS);
|
||||
else
|
||||
logPrinter.print("PFS Final padding check", EMsgType.WARNING);
|
||||
|
||||
// Calculate position including header for body size offset
|
||||
bodySize = randAccessFile.getFilePointer()+header;
|
||||
//*********************************************************************************************
|
||||
// Collect file names from NCAs
|
||||
logPrinter.print("PFS Collecting file names", EMsgType.INFO);
|
||||
List<Byte> ncaFN; // Temporary
|
||||
byte[] b = new byte[1]; // Temporary
|
||||
for (int i=0; i<filesCount; i++){
|
||||
ncaFN = new ArrayList<>();
|
||||
randAccessFile.seek(filesCount*24+16+ncaNameOffsets.get(i)); // Files cont * 24(bit for each meta-data) + 4 bytes goes after all of them + 12 bit what were in the beginning
|
||||
while ((randAccessFile.read(b)) != -1){
|
||||
if (b[0] == 0x00)
|
||||
break;
|
||||
else
|
||||
ncaFN.add(b[0]);
|
||||
}
|
||||
byte[] exchangeTempArray = new byte[ncaFN.size()];
|
||||
for (int j=0; j < ncaFN.size(); j++)
|
||||
exchangeTempArray[j] = ncaFN.get(j);
|
||||
// Find and store ticket (.tik)
|
||||
if (new String(exchangeTempArray, StandardCharsets.UTF_8).toLowerCase().endsWith(".tik"))
|
||||
this.ticketID = i;
|
||||
this.ncaFiles[i].setNcaFileName(Arrays.copyOf(exchangeTempArray, exchangeTempArray.length));
|
||||
}
|
||||
randAccessFile.close();
|
||||
}
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("PFS Failed NSP file analyze for ["+nspFileName+"]\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
logPrinter.print("PFS Finish NSP file analyze for ["+nspFileName+"]", EMsgType.PASS);
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Return file name as byte array
|
||||
* */
|
||||
public byte[] getBytesNspFileName(){
|
||||
return nspFileName.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
/**
|
||||
* Return file name as String
|
||||
* */
|
||||
public String getStringNspFileName(){
|
||||
return nspFileName;
|
||||
}
|
||||
/**
|
||||
* Return file name length as byte array
|
||||
* */
|
||||
public byte[] getBytesNspFileNameLength(){
|
||||
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(getBytesNspFileName().length).array();
|
||||
}
|
||||
/**
|
||||
* Return NCA count inside of file as byte array
|
||||
* */
|
||||
public byte[] getBytesCountOfNca(){
|
||||
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ncaFiles.length).array();
|
||||
}
|
||||
/**
|
||||
* Return NCA count inside of file as int
|
||||
* */
|
||||
public int getIntCountOfNca(){
|
||||
return ncaFiles.length;
|
||||
}
|
||||
/**
|
||||
* Return requested-by-number NCA file inside of file
|
||||
* */
|
||||
public NCAFile getNca(int ncaNumber){
|
||||
return ncaFiles[ncaNumber];
|
||||
}
|
||||
/**
|
||||
* Return bodySize
|
||||
* */
|
||||
public long getBodySize(){
|
||||
return bodySize;
|
||||
}
|
||||
/**
|
||||
* Return special NCA file: ticket
|
||||
* (sugar)
|
||||
* */
|
||||
public int getNcaTicketID(){
|
||||
return ticketID;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -13,9 +13,10 @@
|
|||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<ScrollPane fitToWidth="true" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SettingsController">
|
||||
<ScrollPane fitToWidth="true" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SettingsController">
|
||||
<VBox spacing="5.0">
|
||||
<children>
|
||||
<CheckBox fx:id="nspFilesFilterForGLCB" mnemonicParsing="false" text="%netTabGLshowNSPonly" />
|
||||
<CheckBox fx:id="validateNSHostNameCb" mnemonicParsing="false" text="%netTabValidateNSHostNameCb">
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
|
|
|
@ -45,3 +45,4 @@ netTabAllowXciCb=Allow XCI files selection for TinFoil
|
|||
netTabAllowXciTextField=Used by some third-party applications that support XCI and utilizes TinFoil transfer protocol. Don't change if not sure.
|
||||
netTabLanguage=Language
|
||||
windowBodyRestartToApplyLang=Please restart application to apply changes.
|
||||
netTabGLshowNSPonly=Show only *.nsp in GoldLeaf.
|
||||
|
|
|
@ -46,4 +46,5 @@ netTabAllowXciCb=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0432\u
|
|||
netTabAllowXciTextField=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u043C\u0438 \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0438\u043C\u0438 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u043C\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442 XCI \u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044E\u0442 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 TinFoil. \u041D\u0435 \u043C\u0435\u043D\u044F\u0439\u0442\u0435 \u0435\u0441\u043B\u0438 \u043D\u0435 \u0443\u0432\u0435\u0440\u0435\u043D\u044B.
|
||||
netTabLanguage=\u042F\u0437\u044B\u043A
|
||||
windowBodyRestartToApplyLang=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0447\u0442\u043E\u0431\u044B \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0432\u0441\u0442\u0443\u043F\u0438\u043B\u0438 \u0432 \u0441\u0438\u043B\u0443.
|
||||
netTabGLshowNSPonly=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C \u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0444\u0430\u0439\u043B\u044B *.nsp \u0432 GoldLeaf.
|
||||
|
||||
|
|
|
@ -44,4 +44,5 @@ windowBodyNewVersionUnknown=\u0429\u043E\u0441\u044C \u043F\u0456\u0448\u043B\u0
|
|||
netTabAllowXciCb=\u0414\u043E\u0437\u0432\u043E\u043B\u0438\u0442\u0438 \u0432\u0438\u0431\u0456\u0440 XCI \u0444\u0430\u0439\u043B\u0456\u0432 \u0434\u043B\u044F \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u0443 TinFoil
|
||||
netTabAllowXciTextField=\u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454\u0442\u044C\u0441\u044F \u0434\u0435\u044F\u043A\u0438\u043C\u0438 \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0456\u043C\u0438 \u0434\u043E\u0434\u0430\u0442\u043A\u0430\u043C\u0438, \u044F\u043A\u0456 \u043F\u0456\u0434\u0442\u0440\u0438\u043C\u0443\u044E\u0442\u044C XCI \u0456 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u044E\u0442\u044C \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0456 TinFoil. \u042F\u043A\u0449\u043E \u043D\u0435 \u0432\u043F\u0435\u0432\u043D\u0435\u043D\u0456 \u2014\u00A0\u043D\u0435 \u0437\u043C\u0456\u043D\u044E\u0439\u0442\u0435.
|
||||
netTabLanguage=\u041C\u043E\u0432\u0430
|
||||
windowBodyRestartToApplyLang=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0456\u0442\u044C \u0434\u043E\u0434\u0430\u0442\u043E\u043A \u0449\u043E\u0431 \u0437\u043C\u0456\u043D\u0438 \u0432\u0441\u0442\u0443\u043F\u0438\u043B\u0438 \u0432 \u0441\u0438\u043B\u0443.
|
||||
windowBodyRestartToApplyLang=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0456\u0442\u044C \u0434\u043E\u0434\u0430\u0442\u043E\u043A \u0449\u043E\u0431 \u0437\u043C\u0456\u043D\u0438 \u0432\u0441\u0442\u0443\u043F\u0438\u043B\u0438 \u0432 \u0441\u0438\u043B\u0443.
|
||||
netTabGLshowNSPonly=\u0412\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u0438 \u0432\u0438\u043A\u043B\u044E\u0447\u043D\u043E *.nsp \u0444\u0430\u0439\u043B\u0438 \u0443 GoldLeaf.
|
|
@ -262,6 +262,7 @@
|
|||
-fx-background-color: #71e016;
|
||||
}
|
||||
|
||||
.scroll-pane > .corner,
|
||||
.scroll-bar:horizontal,
|
||||
.scroll-bar:vertical {
|
||||
-fx-background-color: #2d2d2d;
|
||||
|
|
Loading…
Reference in a new issue