Merge pull request #5 from developersu/development
Development-to-master
This commit is contained in:
commit
dc5d051413
29 changed files with 1565 additions and 447 deletions
115
README.md
115
README.md
|
@ -1,81 +1,128 @@
|
||||||
# NS-USBloader
|
# NS-USBloader
|
||||||
|
|
||||||
NS-USBloader is a PC-side TinFoil and GoldLeaf NSP USB uploader. Replacement for default *usb_install_pc.py* and *GoldTree*.
|
NS-USBloader is a PC-side TinFoil (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**.
|
||||||
|
|
||||||
With GUI and cookies.
|
With GUI and cookies. Wokrs on Windows, macOS and Linux.
|
||||||
|
|
||||||
Read more: https://developersu.blogspot.com/2019/02/ns-usbloader-en.html
|
Sometimes I add new posts [on my home page](https://developersu.blogspot.com/search/label/NS-USBloader) about this project.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
![Screenshot](https://farm8.staticflickr.com/7834/47133893471_37fd9689c4_o.png)
|
![Screenshot](https://farm8.staticflickr.com/7834/47133893471_37fd9689c4_o.png)
|
||||||
|
|
||||||
## License
|
### License
|
||||||
|
|
||||||
Source code spreads under the GNU General Public License v.3. You can find it in LICENSE file.
|
Source code spreads under the GNU General Public License v.3. You can find it in LICENSE file.
|
||||||
|
|
||||||
## Used libraries
|
### Used libraries
|
||||||
* [OpenJFX](https://wiki.openjdk.java.net/display/OpenJFX/Main)
|
* [OpenJFX](https://wiki.openjdk.java.net/display/OpenJFX/Main)
|
||||||
* [usb4java](https://mvnrepository.com/artifact/org.usb4java/usb4java)
|
* [usb4java](https://mvnrepository.com/artifact/org.usb4java/usb4java)
|
||||||
* Few icons taken from: [materialdesignicons](http://materialdesignicons.com/)
|
* Few icons taken from: [materialdesignicons](http://materialdesignicons.com/)
|
||||||
|
|
||||||
## Requirements
|
### System requirements
|
||||||
|
|
||||||
JRE 8u60 or higher. See below.
|
JRE 8u60 or higher.
|
||||||
|
|
||||||
## Usage
|
### Usage
|
||||||
### Linux:
|
#### How to start it on..
|
||||||
|
##### Linux:
|
||||||
|
|
||||||
1. Install JRE/JDK 8u60 or higher (openJDK is good. Oracle's one is also good). JavaFX not needed, if you're interested (it's embedded).
|
1. Install JRE/JDK 8u60 or higher (openJDK is good. Oracle's one is also good). JavaFX not needed, if you're interested (it's embedded).
|
||||||
|
|
||||||
2. `root # java -jar /path/to/NS-USBloader.jar`
|
2. `root # java -jar /path/to/NS-USBloader.jar`
|
||||||
|
|
||||||
### macOS
|
##### macOS
|
||||||
|
|
||||||
See 'Linux' section.
|
Double-click on downloaded .jar file. Follow instructions. Or see 'Linux' section.
|
||||||
|
|
||||||
Set 'Security & Privacy' settings if needed.
|
Set 'Security & Privacy' settings if needed.
|
||||||
|
|
||||||
### Windows:
|
If you use different MacOS (not Mojave) - check release section for another JAR file.
|
||||||
|
|
||||||
* Download Zadig: https://zadig.akeo.ie/
|
##### Windows:
|
||||||
* Open tinfoil. Set 'Title Managment' -> 'Usb install NSP'
|
|
||||||
|
* Download Zadig: [https://zadig.akeo.ie/](https://zadig.akeo.ie/)
|
||||||
|
* Open TinFoil. Set 'Title Management' -> 'Usb install NSP'
|
||||||
* Connect NS to PC
|
* Connect NS to PC
|
||||||
* Open Zadig, select NS in dropdown, select 'libusbK (v3.0.7.0)' (version may vary), click 'Install WCID Driver'
|
* Open Zadig
|
||||||
|
* Click 'Options' and select 'List All Devices'
|
||||||
|
* Select NS in dropdown, select 'libusbK (v3.0.7.0)' (version may vary), click 'Install WCID Driver'
|
||||||
* Check that in device list of you system you have 'libusbK USB Devices' folder and your NS inside of it
|
* Check that in device list of you system you have 'libusbK USB Devices' folder and your NS inside of it
|
||||||
* Download and install Java JRE (8+)
|
* Download and install Java JRE (8+)
|
||||||
* Get this application (JAR file) double-click on on it (alternatively open 'cmd', go to place where jar located and execute via `java -jar thisAppName.jar`)
|
* Get this application (JAR file) double-click on on it (alternatively open 'cmd', go to place where jar located and execute via `java -jar thisAppName.jar`)
|
||||||
* Remember to have fun!
|
* Remember to have fun!
|
||||||
|
|
||||||
## Tips&tricks
|
#### And how to use it?
|
||||||
### Linux: Add user to udev rules to use NS not-from-root-account
|
|
||||||
`root # vim /etc/udev/rules.d/99-NS.rules`
|
|
||||||
|
|
||||||
`SUBSYSTEM=="usb", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="3000", GROUP="plugdev"`
|
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.
|
||||||
|
|
||||||
`root # udevadm control --reload-rules && udevadm trigger`
|
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.
|
||||||
|
|
||||||
## Known bugs
|
Let's rephrase, if you have working version of TinFoil **DO NOT** use this one. Ok. let's begin.
|
||||||
* Unable to interrupt transmission when libusb awaiting for read event (when user sent NSP list but didn't selected anything on NS).
|
|
||||||
|
|
||||||
## NOTES
|
There are three tabs. Firs one is main.
|
||||||
Table 'Status' = 'Uploaded' does not means that file installed. It means that it has been sent to NS without any issues! That's what this app about.
|
|
||||||
|
##### First tab.
|
||||||
|
|
||||||
|
At the top of you selecting from drop-down application and protocol that you're going to use. For GoldLeaf only USB is available. Lamp icon stands for switching themes (light or dark).
|
||||||
|
|
||||||
|
Then you may drag-n-drop folder with NSPs OR files to application or use 'Select NSP files' button. Multiple selection for files available. Click it again and select files from another folder it you want, it will be added into the table.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
##### 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 networking 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 'shared.lan:80/ROMS/NS/' and add in table file 'my file.nsp' then NS-USBloader will simply tell TinFoil "Hey, go take files from 'shared.lan:80/ROMS/NS/my+file.nsp' ". Of course you have to bring 'shared.lan' host up and make file accessible from such address. All this requires more investigation. BTW, the issue could be that NS-USBloader encodes 'space' char as '+' and some web-servers understand 'space' as '%20D'. It could be fixed in later versions of NS-USBloader if I go deeper in it or you leave me feedback with information/request. As I said, this feature is interesting, but I guess won't be popular.
|
||||||
|
|
||||||
|
##### Third tab.
|
||||||
|
|
||||||
|
That's where all logs dropped. Verbose information about transmissions comes here.
|
||||||
|
|
||||||
|
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 finished (unless they failed). So you have to look on your NS screen and 'Interrupt' is once done.
|
||||||
|
|
||||||
|
### Tips&tricks
|
||||||
|
#### Linux: Add user to 'udev' rules to use NS not-from-root-account
|
||||||
|
```
|
||||||
|
root # vim /etc/udev/rules.d/99-NS.rules
|
||||||
|
SUBSYSTEM=="usb", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="3000", GROUP="plugdev"
|
||||||
|
root # udevadm control --reload-rules && udevadm trigger
|
||||||
|
```
|
||||||
|
|
||||||
|
### Known bugs
|
||||||
|
* Unable to interrupt transmission when libusb awaiting for read event (when user sent NSP list but didn't selected anything on NS). Also, sometimes, when network transmission started and nothing received from NS.
|
||||||
|
|
||||||
|
#### NOTES
|
||||||
|
Table 'Status' = 'Uploaded' does not mean that file installed. It means that it has been sent to NS without any issues! That's what this app about.
|
||||||
Handling successful/failed installation is a purpose of the other side application (TinFoil/GoldLeaf). (And they don't provide any feedback interfaces so I can't detect success/failure.)
|
Handling successful/failed installation is a purpose of the other side application (TinFoil/GoldLeaf). (And they don't provide any feedback interfaces so I can't detect success/failure.)
|
||||||
|
|
||||||
## TODO:
|
usb4java since NS-USBloader-v0.2.3 switched to 1.2.0 instead of 1.3.0. This shouldn't impact anyone except users of macOS High Sierra (and Sierra?) where previous versions of NS-USBloader didn't work.
|
||||||
- [x] macOS QA v0.1
|
|
||||||
- [ ] macOS QA v0.2 (partly)
|
### Translators! Traductores! Übersetzer! Թարգմանիչներ!
|
||||||
|
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.
|
||||||
|
|
||||||
|
#### Thanks for great work done by our translater~~s team~~!
|
||||||
|
|
||||||
|
Français by [Stephane Meden (JackFromNice)](https://github.com/JackFromNice)
|
||||||
|
|
||||||
|
|
||||||
|
#### TODO (maybe):
|
||||||
|
- [x] macOS QA v0.1 (Mojave)
|
||||||
|
- [x] macOS QA v0.2.2 (Mojave)
|
||||||
|
- [x] macOS QA v0.2.3-DEV (High Sierra)
|
||||||
|
- [ ] macOS QA v0.3 (Mojave, High Sierra)
|
||||||
- [x] Windows support
|
- [x] Windows support
|
||||||
- [ ] code refactoring (almost. todo: printLog() )
|
- [x] code refactoring
|
||||||
- [x] GoldLeaf support
|
- [x] GoldLeaf support
|
||||||
- [ ] XCI support
|
- [ ] XCI support
|
||||||
- [ ] File order sort (non-critical)
|
- [ ] File order sort (non-critical)
|
||||||
- [ ] More deep file analyze before uploading.
|
- [ ] More deep file analyze before uploading.
|
||||||
|
- [x] Network mode support for TinFoil
|
||||||
|
|
||||||
## Thanks
|
#### Thanks
|
||||||
Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened.
|
Appreciate assistance and support of both Vitaliy and Konstantin. Without you all this magic would not have happened.
|
||||||
|
|
||||||
[Konstanin Kelemen](https://github.com/konstantin-kelemen)
|
[Konstanin Kelemen](https://github.com/konstantin-kelemen)
|
||||||
|
|
18
pom.xml
18
pom.xml
|
@ -8,11 +8,11 @@
|
||||||
<name>NS-USBloader</name>
|
<name>NS-USBloader</name>
|
||||||
|
|
||||||
<artifactId>ns-usbloader</artifactId>
|
<artifactId>ns-usbloader</artifactId>
|
||||||
<version>0.2.2-SNAPSHOT</version>
|
<version>0.3-SNAPSHOT</version>
|
||||||
|
|
||||||
<url>https://github.com/developersu/ns-usbloader/</url>
|
<url>https://github.com/developersu/ns-usbloader/</url>
|
||||||
<description>
|
<description>
|
||||||
NSP USB loader for TinFoil and GoldLeaf
|
NSP USB loader for TinFoil (USB and Network) and GoldLeaf
|
||||||
</description>
|
</description>
|
||||||
<inceptionYear>2019</inceptionYear>
|
<inceptionYear>2019</inceptionYear>
|
||||||
<organization>
|
<organization>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.usb4java</groupId>
|
<groupId>org.usb4java</groupId>
|
||||||
<artifactId>usb4java</artifactId>
|
<artifactId>usb4java</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>1.2.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -155,6 +155,18 @@
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- Don't generate default JAR without dependencies -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>default-jar</id>
|
||||||
|
<phase>none</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<!-- Generate JAR with dependencies -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
|
|
@ -10,6 +10,33 @@ public class AppPreferences {
|
||||||
|
|
||||||
private AppPreferences(){ preferences = Preferences.userRoot().node("NS-USBloader"); }
|
private AppPreferences(){ preferences = Preferences.userRoot().node("NS-USBloader"); }
|
||||||
|
|
||||||
|
public void setAll(
|
||||||
|
String Protocol,
|
||||||
|
String PreviouslyOpened,
|
||||||
|
String NetUsb,
|
||||||
|
String NsIp,
|
||||||
|
boolean NsIpValidate,
|
||||||
|
boolean ExpertMode,
|
||||||
|
boolean AutoIp,
|
||||||
|
boolean RandPort,
|
||||||
|
boolean NotServe,
|
||||||
|
String HostIp,
|
||||||
|
String HostPort,
|
||||||
|
String HostExtra
|
||||||
|
){
|
||||||
|
setProtocol(Protocol);
|
||||||
|
setRecent(PreviouslyOpened);
|
||||||
|
setNetUsb(NetUsb);
|
||||||
|
setNsIp(NsIp);
|
||||||
|
setNsIpValidationNeeded(NsIpValidate);
|
||||||
|
setExpertMode(ExpertMode);
|
||||||
|
setAutoDetectIp(AutoIp);
|
||||||
|
setRandPort(RandPort);
|
||||||
|
setNotServeRequests(NotServe);
|
||||||
|
setHostIp(HostIp);
|
||||||
|
setHostPort(HostPort);
|
||||||
|
setHostExtra(HostExtra);
|
||||||
|
}
|
||||||
public String getTheme(){
|
public String getTheme(){
|
||||||
String theme = preferences.get("THEME", "/res/app_dark.css"); // Don't let user to change settings manually
|
String theme = preferences.get("THEME", "/res/app_dark.css"); // Don't let user to change settings manually
|
||||||
if (!theme.matches("(^/res/app_dark.css$)|(^/res/app_light.css$)"))
|
if (!theme.matches("(^/res/app_dark.css$)|(^/res/app_light.css$)"))
|
||||||
|
@ -22,10 +49,50 @@ public class AppPreferences {
|
||||||
protocol = "TinFoil";
|
protocol = "TinFoil";
|
||||||
return protocol;
|
return protocol;
|
||||||
}
|
}
|
||||||
|
public String getNetUsb(){
|
||||||
|
String netUsb = preferences.get("NETUSB", "USB"); // Don't let user to change settings manually
|
||||||
|
if (!netUsb.matches("(^USB$)|(^NET$)"))
|
||||||
|
netUsb = "USB";
|
||||||
|
return netUsb;
|
||||||
|
}
|
||||||
public void setTheme(String theme){ preferences.put("THEME", theme); }
|
public void setTheme(String theme){ preferences.put("THEME", theme); }
|
||||||
public void setProtocol(String protocol){ preferences.put("PROTOCOL", protocol); }
|
public void setProtocol(String protocol){ preferences.put("PROTOCOL", protocol); }
|
||||||
|
public void setNetUsb(String netUsb){ preferences.put("NETUSB", netUsb); }
|
||||||
|
|
||||||
|
public void setNsIp(String ip){preferences.put("NSIP", ip);}
|
||||||
|
public String getNsIp(){return preferences.get("NSIP", "192.168.1.42");}
|
||||||
|
|
||||||
public String getRecent(){ return preferences.get("RECENT", System.getProperty("user.home")); }
|
public String getRecent(){ return preferences.get("RECENT", System.getProperty("user.home")); }
|
||||||
public void setRecent(String path){ preferences.put("RECENT", path); }
|
public void setRecent(String path){ preferences.put("RECENT", path); }
|
||||||
|
//------------ SETTINGS ------------------//
|
||||||
|
public boolean getNsIpValidationNeeded() {return preferences.getBoolean("NSIPVALIDATION", true);}
|
||||||
|
public void setNsIpValidationNeeded(boolean need){preferences.putBoolean("NSIPVALIDATION", need);}
|
||||||
|
|
||||||
|
public boolean getExpertMode(){return preferences.getBoolean("EXPERTMODE", false);}
|
||||||
|
public void setExpertMode(boolean mode){preferences.putBoolean("EXPERTMODE", mode);}
|
||||||
|
|
||||||
|
public boolean getAutoDetectIp(){return preferences.getBoolean("AUTOHOSTIP", true);}
|
||||||
|
public void setAutoDetectIp(boolean mode){preferences.putBoolean("AUTOHOSTIP", mode);}
|
||||||
|
|
||||||
|
public boolean getRandPort(){return preferences.getBoolean("RANDHOSTPORT", true);}
|
||||||
|
public void setRandPort(boolean mode){preferences.putBoolean("RANDHOSTPORT", mode);}
|
||||||
|
|
||||||
|
public boolean getNotServeRequests(){return preferences.getBoolean("DONTSERVEREQ", false);}
|
||||||
|
public void setNotServeRequests(boolean mode){preferences.putBoolean("DONTSERVEREQ", mode);}
|
||||||
|
|
||||||
|
public String getHostIp(){ return preferences.get("HOSTIP", "0.0.0.0").replaceAll("(\\s)|(\t)", "");} // who the hell said 'paranoid'?
|
||||||
|
public void setHostIp(String ip){preferences.put("HOSTIP", ip);}
|
||||||
|
|
||||||
|
public String getHostPort(){
|
||||||
|
String value = preferences.get("HOSTPORT", "6042");
|
||||||
|
if (!value.matches("^[0-9]{1,5}$"))
|
||||||
|
return "6042";
|
||||||
|
if ((Integer.parseInt(value) > 65535) || (Integer.parseInt(value) < 1))
|
||||||
|
return "6042";
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public void setHostPort(String port){preferences.put("HOSTPORT", port);}
|
||||||
|
|
||||||
|
public String getHostExtra(){ return preferences.get("HOSTEXTRA", "").replaceAll("(\\s)|(\t)", "");} // oh just shut up...
|
||||||
|
public void setHostExtra(String postfix){preferences.put("HOSTEXTRA", postfix);}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,25 @@ package nsusbloader.Controllers;
|
||||||
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.input.DragEvent;
|
||||||
|
import javafx.scene.input.TransferMode;
|
||||||
import javafx.scene.layout.Pane;
|
import javafx.scene.layout.Pane;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import nsusbloader.AppPreferences;
|
import nsusbloader.AppPreferences;
|
||||||
import nsusbloader.MediatorControl;
|
import nsusbloader.MediatorControl;
|
||||||
|
import nsusbloader.NET.NETCommunications;
|
||||||
import nsusbloader.NSLMain;
|
import nsusbloader.NSLMain;
|
||||||
import nsusbloader.UsbCommunications;
|
import nsusbloader.ServiceWindow;
|
||||||
|
import nsusbloader.USB.UsbCommunications;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
@ -32,7 +38,7 @@ public class NSLMainController implements Initializable {
|
||||||
@FXML
|
@FXML
|
||||||
public ProgressBar progressBar; // Accessible from Mediator
|
public ProgressBar progressBar; // Accessible from Mediator
|
||||||
@FXML
|
@FXML
|
||||||
private ChoiceBox<String> choiceProtocol;
|
private ChoiceBox<String> choiceProtocol, choiceNetUsb;
|
||||||
@FXML
|
@FXML
|
||||||
private Button switchThemeBtn;
|
private Button switchThemeBtn;
|
||||||
|
|
||||||
|
@ -41,9 +47,15 @@ public class NSLMainController implements Initializable {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public NSTableViewController tableFilesListController; // Accessible from Mediator
|
public NSTableViewController tableFilesListController; // Accessible from Mediator
|
||||||
|
@FXML
|
||||||
|
private SettingsController SettingsTabController;
|
||||||
|
@FXML
|
||||||
|
private TextField nsIpTextField;
|
||||||
|
@FXML
|
||||||
|
private Label nsIpLbl;
|
||||||
|
|
||||||
private UsbCommunications usbCommunications;
|
private Task<Void> usbNetCommunications;
|
||||||
private Thread usbThread;
|
private Thread workThread;
|
||||||
|
|
||||||
private String previouslyOpenedPath;
|
private String previouslyOpenedPath;
|
||||||
|
|
||||||
|
@ -75,10 +87,51 @@ public class NSLMainController implements Initializable {
|
||||||
|
|
||||||
ObservableList<String> choiceProtocolList = FXCollections.observableArrayList("TinFoil", "GoldLeaf");
|
ObservableList<String> choiceProtocolList = FXCollections.observableArrayList("TinFoil", "GoldLeaf");
|
||||||
choiceProtocol.setItems(choiceProtocolList);
|
choiceProtocol.setItems(choiceProtocolList);
|
||||||
choiceProtocol.getSelectionModel().select(AppPreferences.getInstance().getProtocol()); // TODO: shared settings
|
choiceProtocol.getSelectionModel().select(AppPreferences.getInstance().getProtocol());
|
||||||
choiceProtocol.setOnAction(e->tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem())); // Add listener to notify tableView controller
|
choiceProtocol.setOnAction(e-> {
|
||||||
|
tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem());
|
||||||
|
if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf")) {
|
||||||
|
choiceNetUsb.setDisable(true);
|
||||||
|
nsIpLbl.setVisible(false);
|
||||||
|
nsIpTextField.setVisible(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
choiceNetUsb.setDisable(false);
|
||||||
|
if (choiceNetUsb.getSelectionModel().getSelectedItem().equals("NET")) {
|
||||||
|
nsIpLbl.setVisible(true);
|
||||||
|
nsIpTextField.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}); // Add listener to notify tableView controller
|
||||||
tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem()); // Notify tableView controller
|
tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem()); // Notify tableView controller
|
||||||
|
|
||||||
|
ObservableList<String> choiceNetUsbList = FXCollections.observableArrayList("USB", "NET");
|
||||||
|
choiceNetUsb.setItems(choiceNetUsbList);
|
||||||
|
choiceNetUsb.getSelectionModel().select(AppPreferences.getInstance().getNetUsb());
|
||||||
|
if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf")) {
|
||||||
|
choiceNetUsb.setDisable(true);
|
||||||
|
}
|
||||||
|
choiceNetUsb.setOnAction(e->{
|
||||||
|
if (choiceNetUsb.getSelectionModel().getSelectedItem().equals("NET")){
|
||||||
|
nsIpLbl.setVisible(true);
|
||||||
|
nsIpTextField.setVisible(true);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
nsIpLbl.setVisible(false);
|
||||||
|
nsIpTextField.setVisible(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nsIpTextField.setText(AppPreferences.getInstance().getNsIp());
|
||||||
|
if (choiceProtocol.getSelectionModel().getSelectedItem().equals("TinFoil") && choiceNetUsb.getSelectionModel().getSelectedItem().equals("NET")){
|
||||||
|
nsIpLbl.setVisible(true);
|
||||||
|
nsIpTextField.setVisible(true);
|
||||||
|
}
|
||||||
|
nsIpTextField.setTextFormatter(new TextFormatter<>(change -> {
|
||||||
|
if (change.getControlNewText().contains(" ") | change.getControlNewText().contains("\t"))
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return change;
|
||||||
|
}));
|
||||||
this.previouslyOpenedPath = null;
|
this.previouslyOpenedPath = null;
|
||||||
|
|
||||||
Region btnSwitchImage = new Region();
|
Region btnSwitchImage = new Region();
|
||||||
|
@ -125,37 +178,67 @@ public class NSLMainController implements Initializable {
|
||||||
uploadStopBtn.setDisable(false);
|
uploadStopBtn.setDisable(false);
|
||||||
previouslyOpenedPath = filesList.get(0).getParent();
|
previouslyOpenedPath = filesList.get(0).getParent();
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
tableFilesListController.setFiles(null);
|
|
||||||
uploadStopBtn.setDisable(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* It's button listener when no transmission executes
|
* It's button listener when no transmission executes
|
||||||
* */
|
* */
|
||||||
private void uploadBtnAction(){
|
private void uploadBtnAction(){
|
||||||
if (usbThread == null || !usbThread.isAlive()){
|
if ((workThread == null || !workThread.isAlive())){
|
||||||
|
// Collect files
|
||||||
List<File> nspToUpload;
|
List<File> nspToUpload;
|
||||||
if ((nspToUpload = tableFilesListController.getFiles()) == null) {
|
if ((nspToUpload = tableFilesListController.getFilesForUpload()) == null) {
|
||||||
resourceBundle.getString("logsNoFolderFileSelected");
|
logArea.setText(resourceBundle.getString("logsNoFolderFileSelected"));
|
||||||
return;
|
return;
|
||||||
}else {
|
}
|
||||||
|
else {
|
||||||
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
|
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
|
||||||
for (File item: nspToUpload)
|
for (File item: nspToUpload)
|
||||||
logArea.appendText(" "+item.getAbsolutePath()+"\n");
|
logArea.appendText(" "+item.getAbsolutePath()+"\n");
|
||||||
}
|
}
|
||||||
usbCommunications = new UsbCommunications(nspToUpload, choiceProtocol.getSelectionModel().getSelectedItem());
|
// If USB selected
|
||||||
usbThread = new Thread(usbCommunications);
|
if (choiceProtocol.getSelectionModel().getSelectedItem().equals("GoldLeaf") ||
|
||||||
usbThread.setDaemon(true);
|
(
|
||||||
usbThread.start();
|
choiceProtocol.getSelectionModel().getSelectedItem().equals("TinFoil")
|
||||||
|
&& choiceNetUsb.getSelectionModel().getSelectedItem().equals("USB")
|
||||||
|
)
|
||||||
|
){
|
||||||
|
usbNetCommunications = new UsbCommunications(nspToUpload, choiceProtocol.getSelectionModel().getSelectedItem());
|
||||||
|
workThread = new Thread(usbNetCommunications);
|
||||||
|
workThread.setDaemon(true);
|
||||||
|
workThread.start();
|
||||||
|
}
|
||||||
|
else { // NET INSTALL OVER TINFOIL
|
||||||
|
if (SettingsTabController.isNsIpValidate() && !nsIpTextField.getText().matches("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"))
|
||||||
|
if (!ServiceWindow.getConfirmationWindow(resourceBundle.getString("windowTitleBadIp"),resourceBundle.getString("windowBodyBadIp")))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String nsIP = nsIpTextField.getText();
|
||||||
|
|
||||||
|
if (!SettingsTabController.getExpertModeSelected())
|
||||||
|
usbNetCommunications = new NETCommunications(nspToUpload, nsIP, false, "", "", "");
|
||||||
|
else {
|
||||||
|
usbNetCommunications = new NETCommunications(
|
||||||
|
nspToUpload,
|
||||||
|
nsIP,
|
||||||
|
SettingsTabController.getNotServeSelected(),
|
||||||
|
SettingsTabController.getAutoIpSelected()?"":SettingsTabController.getHostIp(),
|
||||||
|
SettingsTabController.getRandPortSelected()?"":SettingsTabController.getHostPort(),
|
||||||
|
SettingsTabController.getNotServeSelected()?SettingsTabController.getHostExtra():""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
workThread = new Thread(usbNetCommunications);
|
||||||
|
workThread.setDaemon(true);
|
||||||
|
workThread.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* It's button listener when transmission in progress
|
* It's button listener when transmission in progress
|
||||||
* */
|
* */
|
||||||
private void stopBtnAction(){
|
private void stopBtnAction(){
|
||||||
if (usbThread != null && usbThread.isAlive()){
|
if (workThread != null && workThread.isAlive()){
|
||||||
usbCommunications.cancel(false);
|
usbNetCommunications.cancel(false); // TODO: add something abstract to use also for network
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -188,11 +271,65 @@ public class NSLMainController implements Initializable {
|
||||||
uploadStopBtn.getStyleClass().add("buttonUp");
|
uploadStopBtn.getStyleClass().add("buttonUp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Crunch. Now you see that I'm not a programmer.. This function called from NSTableViewController
|
||||||
|
* */
|
||||||
|
public void disableUploadStopBtn(boolean disable){
|
||||||
|
uploadStopBtn.setDisable(disable);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Drag-n-drop support (dragOver consumer)
|
||||||
|
* */
|
||||||
|
@FXML
|
||||||
|
private void handleDragOver(DragEvent event){
|
||||||
|
if (event.getDragboard().hasFiles())
|
||||||
|
event.acceptTransferModes(TransferMode.ANY);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Drag-n-drop support (drop consumer)
|
||||||
|
* */
|
||||||
|
@FXML
|
||||||
|
private void handleDrop(DragEvent event){
|
||||||
|
if (MediatorControl.getInstance().getTransferActive()) {
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<File> filesDropped = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
for (File fileOrDir : event.getDragboard().getFiles()) {
|
||||||
|
if (fileOrDir.getName().toLowerCase().endsWith(".nsp"))
|
||||||
|
filesDropped.add(fileOrDir);
|
||||||
|
else if (fileOrDir.isDirectory())
|
||||||
|
for (File file : fileOrDir.listFiles())
|
||||||
|
if (file.getName().toLowerCase().endsWith(".nsp"))
|
||||||
|
filesDropped.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SecurityException se){
|
||||||
|
se.printStackTrace();
|
||||||
|
}
|
||||||
|
if (!filesDropped.isEmpty())
|
||||||
|
tableFilesListController.setFiles(filesDropped);
|
||||||
|
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Save preferences before exit
|
* Save preferences before exit
|
||||||
* */
|
* */
|
||||||
public void exit(){
|
public void exit(){ // TODO: add method to set all in AppPreferences
|
||||||
AppPreferences.getInstance().setProtocol(choiceProtocol.getSelectionModel().getSelectedItem());
|
AppPreferences.getInstance().setAll(
|
||||||
AppPreferences.getInstance().setRecent(previouslyOpenedPath);
|
choiceProtocol.getSelectionModel().getSelectedItem(),
|
||||||
|
previouslyOpenedPath,
|
||||||
|
choiceNetUsb.getSelectionModel().getSelectedItem(),
|
||||||
|
nsIpTextField.getText().trim(),
|
||||||
|
SettingsTabController.isNsIpValidate(),
|
||||||
|
SettingsTabController.getExpertModeSelected(),
|
||||||
|
SettingsTabController.getAutoIpSelected(),
|
||||||
|
SettingsTabController.getRandPortSelected(),
|
||||||
|
SettingsTabController.getNotServeSelected(),
|
||||||
|
SettingsTabController.getHostIp(),
|
||||||
|
SettingsTabController.getHostPort(),
|
||||||
|
SettingsTabController.getHostExtra()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,12 @@ public class NSLRowModel {
|
||||||
this.nspFile = nspFile;
|
this.nspFile = nspFile;
|
||||||
this.markForUpload = checkBoxValue;
|
this.markForUpload = checkBoxValue;
|
||||||
this.nspFileName = nspFile.getName();
|
this.nspFileName = nspFile.getName();
|
||||||
this.nspFileSize = String.format("%.2f", nspFile.length()/1024.0/1024.0);
|
if (nspFile.length()/1024.0/1024.0/1024.0 > 1)
|
||||||
|
this.nspFileSize = String.format("%.2f", nspFile.length()/1024.0/1024.0/1024.0)+" GB";
|
||||||
|
else if (nspFile.length()/1024.0/1024.0 > 1)
|
||||||
|
this.nspFileSize = String.format("%.2f", nspFile.length()/1024.0/1024.0)+" MB";
|
||||||
|
else
|
||||||
|
this.nspFileSize = String.format("%.2f", nspFile.length()/1024.0)+" kB";
|
||||||
this.status = "";
|
this.status = "";
|
||||||
}
|
}
|
||||||
// Model methods start
|
// Model methods start
|
||||||
|
@ -45,11 +50,14 @@ public class NSLRowModel {
|
||||||
case FAILED:
|
case FAILED:
|
||||||
this.status = "Failed";
|
this.status = "Failed";
|
||||||
break;
|
break;
|
||||||
case UNKNOWN:
|
case INDETERMINATE:
|
||||||
this.status = "...";
|
this.status = "...";
|
||||||
break;
|
break;
|
||||||
|
case UNKNOWN:
|
||||||
|
this.status = "Unknown";
|
||||||
|
break;
|
||||||
case INCORRECT_FILE_FAILED:
|
case INCORRECT_FILE_FAILED:
|
||||||
this.status = "Failed: Incorrect file";
|
this.status = "Failed: Bad file";
|
||||||
markForUpload = false;
|
markForUpload = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
package nsusbloader.Controllers;
|
package nsusbloader.Controllers;
|
||||||
|
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.TableCell;
|
|
||||||
import javafx.scene.control.TableColumn;
|
|
||||||
import javafx.scene.control.TableView;
|
|
||||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||||
import javafx.scene.control.cell.PropertyValueFactory;
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.input.MouseButton;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
|
import nsusbloader.MediatorControl;
|
||||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -32,13 +37,42 @@ public class NSTableViewController implements Initializable {
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
rowsObsLst = FXCollections.observableArrayList();
|
rowsObsLst = FXCollections.observableArrayList();
|
||||||
|
|
||||||
table.setPlaceholder(new Label());
|
table.setPlaceholder(new Label());
|
||||||
|
table.setEditable(false); // At least with hacks it works as expected. Otherwise - null pointer exception
|
||||||
|
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
table.setOnKeyPressed(new EventHandler<KeyEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(KeyEvent keyEvent) {
|
||||||
|
if (!rowsObsLst.isEmpty()) {
|
||||||
|
if (keyEvent.getCode() == KeyCode.DELETE && !MediatorControl.getInstance().getTransferActive()) {
|
||||||
|
rowsObsLst.removeAll(table.getSelectionModel().getSelectedItems());
|
||||||
|
if (rowsObsLst.isEmpty())
|
||||||
|
MediatorControl.getInstance().getContoller().disableUploadStopBtn(true); // TODO: change to something better
|
||||||
|
table.refresh();
|
||||||
|
} else if (keyEvent.getCode() == KeyCode.SPACE) {
|
||||||
|
for (NSLRowModel item : table.getSelectionModel().getSelectedItems()) {
|
||||||
|
item.setMarkForUpload(!item.isMarkForUpload());
|
||||||
|
restrictSelection(item);
|
||||||
|
}
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyEvent.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
TableColumn<NSLRowModel, String> statusColumn = new TableColumn<>(resourceBundle.getString("tableStatusLbl"));
|
TableColumn<NSLRowModel, String> statusColumn = new TableColumn<>(resourceBundle.getString("tableStatusLbl"));
|
||||||
TableColumn<NSLRowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
TableColumn<NSLRowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||||
TableColumn<NSLRowModel, String> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
TableColumn<NSLRowModel, String> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||||
TableColumn<NSLRowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
TableColumn<NSLRowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||||
|
|
||||||
|
statusColumn.setEditable(false);
|
||||||
|
fileNameColumn.setEditable(false);
|
||||||
|
fileSizeColumn.setEditable(false);
|
||||||
|
uploadColumn.setEditable(true);
|
||||||
|
|
||||||
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||||
statusColumn.setMinWidth(100.0);
|
statusColumn.setMinWidth(100.0);
|
||||||
statusColumn.setPrefWidth(100.0);
|
statusColumn.setPrefWidth(100.0);
|
||||||
|
@ -75,7 +109,6 @@ public class NSTableViewController implements Initializable {
|
||||||
restrictSelection(model);
|
restrictSelection(model);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return booleanProperty;
|
return booleanProperty;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -87,7 +120,56 @@ public class NSTableViewController implements Initializable {
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
||||||
|
new Callback<TableView<NSLRowModel>, TableRow<NSLRowModel>>() {
|
||||||
|
@Override
|
||||||
|
public TableRow<NSLRowModel> call(TableView<NSLRowModel> nslRowModelTableView) {
|
||||||
|
final TableRow<NSLRowModel> row = new TableRow<>();
|
||||||
|
ContextMenu contextMenu = new ContextMenu();
|
||||||
|
MenuItem deleteMenuItem = new MenuItem(resourceBundle.getString("contextMenuBtnDelete"));
|
||||||
|
deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
rowsObsLst.remove(row.getItem());
|
||||||
|
if (rowsObsLst.isEmpty())
|
||||||
|
MediatorControl.getInstance().getContoller().disableUploadStopBtn(true); // TODO: change to something better
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
MenuItem deleteAllMenuItem = new MenuItem(resourceBundle.getString("contextMenuBtnDeleteAll"));
|
||||||
|
deleteAllMenuItem.setOnAction(new EventHandler<ActionEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
rowsObsLst.clear();
|
||||||
|
MediatorControl.getInstance().getContoller().disableUploadStopBtn(true); // TODO: change to something better
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
contextMenu.getItems().addAll(deleteMenuItem, deleteAllMenuItem);
|
||||||
|
|
||||||
|
row.setContextMenu(contextMenu);
|
||||||
|
row.contextMenuProperty().bind(
|
||||||
|
Bindings.when(
|
||||||
|
Bindings.isNotNull(
|
||||||
|
row.itemProperty()))
|
||||||
|
.then(MediatorControl.getInstance().getTransferActive()?(ContextMenu)null:contextMenu)
|
||||||
|
.otherwise((ContextMenu) null)
|
||||||
|
);
|
||||||
|
row.setOnMouseClicked(new EventHandler<MouseEvent>() { // Just.. don't ask..
|
||||||
|
@Override
|
||||||
|
public void handle(MouseEvent mouseEvent) {
|
||||||
|
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
|
||||||
|
NSLRowModel thisItem = row.getItem();
|
||||||
|
thisItem.setMarkForUpload(!thisItem.isMarkForUpload());
|
||||||
|
restrictSelection(thisItem);
|
||||||
|
}
|
||||||
|
mouseEvent.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
table.setItems(rowsObsLst);
|
table.setItems(rowsObsLst);
|
||||||
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
|
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
|
||||||
}
|
}
|
||||||
|
@ -100,36 +182,42 @@ public class NSTableViewController implements Initializable {
|
||||||
if (model != modelChecked)
|
if (model != modelChecked)
|
||||||
model.setMarkForUpload(false);
|
model.setMarkForUpload(false);
|
||||||
}
|
}
|
||||||
table.refresh();
|
|
||||||
}
|
}
|
||||||
|
table.refresh();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add files when user selected them
|
* Add files when user selected them
|
||||||
* */
|
* */
|
||||||
public void setFiles(List<File> files){
|
public void setFiles(List<File> newFiles){
|
||||||
rowsObsLst.clear(); // TODO: consider table refresh
|
if (!rowsObsLst.isEmpty()){
|
||||||
if (files == null) {
|
List<String> filesAlreayInList = new ArrayList<>();
|
||||||
return;
|
for (NSLRowModel model : rowsObsLst)
|
||||||
}
|
filesAlreayInList.add(model.getNspFileName());
|
||||||
if (protocol.equals("TinFoil")){
|
for (File file: newFiles)
|
||||||
for (File nspFile: files){
|
if (!filesAlreayInList.contains(file.getName())) {
|
||||||
rowsObsLst.add(new NSLRowModel(nspFile, true));
|
if (protocol.equals("TinFoil"))
|
||||||
}
|
rowsObsLst.add(new NSLRowModel(file, true));
|
||||||
|
else
|
||||||
|
rowsObsLst.add(new NSLRowModel(file, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rowsObsLst.clear();
|
for (File file: newFiles)
|
||||||
for (File nspFile: files){
|
if (protocol.equals("TinFoil"))
|
||||||
rowsObsLst.add(new NSLRowModel(nspFile, false));
|
rowsObsLst.add(new NSLRowModel(file, true));
|
||||||
}
|
else
|
||||||
rowsObsLst.get(0).setMarkForUpload(true);
|
rowsObsLst.add(new NSLRowModel(file, false));
|
||||||
|
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
|
||||||
}
|
}
|
||||||
|
rowsObsLst.get(0).setMarkForUpload(true);
|
||||||
|
table.refresh();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||||
* @return null if no files marked for upload
|
* @return null if no files marked for upload
|
||||||
* List<File> if there are files
|
* List<File> if there are files
|
||||||
* */
|
* */
|
||||||
public List<File> getFiles(){
|
public List<File> getFilesForUpload(){
|
||||||
List<File> files = new ArrayList<>();
|
List<File> files = new ArrayList<>();
|
||||||
if (rowsObsLst.isEmpty())
|
if (rowsObsLst.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
@ -137,7 +225,7 @@ public class NSTableViewController implements Initializable {
|
||||||
for (NSLRowModel model: rowsObsLst){
|
for (NSLRowModel model: rowsObsLst){
|
||||||
if (model.isMarkForUpload()){
|
if (model.isMarkForUpload()){
|
||||||
files.add(model.getNspFile());
|
files.add(model.getNspFile());
|
||||||
model.setStatus(EFileStatus.UNKNOWN);
|
model.setStatus(EFileStatus.INDETERMINATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!files.isEmpty()) {
|
if (!files.isEmpty()) {
|
||||||
|
|
146
src/main/java/nsusbloader/Controllers/SettingsController.java
Normal file
146
src/main/java/nsusbloader/Controllers/SettingsController.java
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
package nsusbloader.Controllers;
|
||||||
|
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.CheckBox;
|
||||||
|
import javafx.scene.control.TextField;
|
||||||
|
import javafx.scene.control.TextFormatter;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import nsusbloader.AppPreferences;
|
||||||
|
import nsusbloader.ServiceWindow;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
public class SettingsController implements Initializable {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private CheckBox validateNSHostNameCb;
|
||||||
|
@FXML
|
||||||
|
private CheckBox expertModeCb;
|
||||||
|
@FXML
|
||||||
|
private CheckBox autoDetectIpCb;
|
||||||
|
@FXML
|
||||||
|
private CheckBox randPortCb;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextField pcIpTextField;
|
||||||
|
@FXML
|
||||||
|
private TextField pcPortTextField;
|
||||||
|
@FXML
|
||||||
|
private TextField pcExtraTextField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private CheckBox dontServeCb;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private VBox expertSettingsVBox;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
|
validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded());
|
||||||
|
|
||||||
|
expertSettingsVBox.setDisable(!AppPreferences.getInstance().getExpertMode());
|
||||||
|
|
||||||
|
expertModeCb.setSelected(AppPreferences.getInstance().getExpertMode());
|
||||||
|
expertModeCb.setOnAction(e->{
|
||||||
|
expertSettingsVBox.setDisable(!expertModeCb.isSelected());
|
||||||
|
});
|
||||||
|
|
||||||
|
autoDetectIpCb.setSelected(AppPreferences.getInstance().getAutoDetectIp());
|
||||||
|
pcIpTextField.setDisable(AppPreferences.getInstance().getAutoDetectIp());
|
||||||
|
autoDetectIpCb.setOnAction(e->{
|
||||||
|
pcIpTextField.setDisable(autoDetectIpCb.isSelected());
|
||||||
|
if (!autoDetectIpCb.isSelected())
|
||||||
|
pcIpTextField.requestFocus();
|
||||||
|
});
|
||||||
|
|
||||||
|
randPortCb.setSelected(AppPreferences.getInstance().getRandPort());
|
||||||
|
pcPortTextField.setDisable(AppPreferences.getInstance().getRandPort());
|
||||||
|
randPortCb.setOnAction(e->{
|
||||||
|
pcPortTextField.setDisable(randPortCb.isSelected());
|
||||||
|
if (!randPortCb.isSelected())
|
||||||
|
pcPortTextField.requestFocus();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (AppPreferences.getInstance().getNotServeRequests()){
|
||||||
|
dontServeCb.setSelected(true);
|
||||||
|
|
||||||
|
autoDetectIpCb.setSelected(false);
|
||||||
|
autoDetectIpCb.setDisable(true);
|
||||||
|
pcIpTextField.setDisable(false);
|
||||||
|
|
||||||
|
randPortCb.setSelected(false);
|
||||||
|
randPortCb.setDisable(true);
|
||||||
|
pcPortTextField.setDisable(false);
|
||||||
|
}
|
||||||
|
pcExtraTextField.setDisable(!AppPreferences.getInstance().getNotServeRequests());
|
||||||
|
|
||||||
|
dontServeCb.setOnAction(e->{
|
||||||
|
if (dontServeCb.isSelected()){
|
||||||
|
autoDetectIpCb.setSelected(false);
|
||||||
|
autoDetectIpCb.setDisable(true);
|
||||||
|
pcIpTextField.setDisable(false);
|
||||||
|
|
||||||
|
randPortCb.setSelected(false);
|
||||||
|
randPortCb.setDisable(true);
|
||||||
|
pcPortTextField.setDisable(false);
|
||||||
|
|
||||||
|
pcExtraTextField.setDisable(false);
|
||||||
|
pcIpTextField.requestFocus();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
autoDetectIpCb.setDisable(false);
|
||||||
|
autoDetectIpCb.setSelected(true);
|
||||||
|
pcIpTextField.setDisable(true);
|
||||||
|
|
||||||
|
randPortCb.setDisable(false);
|
||||||
|
randPortCb.setSelected(true);
|
||||||
|
pcPortTextField.setDisable(true);
|
||||||
|
|
||||||
|
pcExtraTextField.setDisable(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pcIpTextField.setText(AppPreferences.getInstance().getHostIp());
|
||||||
|
pcPortTextField.setText(AppPreferences.getInstance().getHostPort());
|
||||||
|
pcExtraTextField.setText(AppPreferences.getInstance().getHostExtra());
|
||||||
|
|
||||||
|
pcIpTextField.setTextFormatter(new TextFormatter<>(change -> {
|
||||||
|
if (change.getControlNewText().contains(" ") | change.getControlNewText().contains("\t"))
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return change;
|
||||||
|
}));
|
||||||
|
pcPortTextField.setTextFormatter(new TextFormatter<Object>(change -> {
|
||||||
|
if (change.getControlNewText().matches("^[0-9]{0,5}$")) {
|
||||||
|
if (!change.getControlNewText().isEmpty()
|
||||||
|
&& ((Integer.parseInt(change.getControlNewText()) > 65535) || (Integer.parseInt(change.getControlNewText()) == 0))
|
||||||
|
) {
|
||||||
|
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleErrorPort"), resourceBundle.getString("windowBodyErrorPort"));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
pcExtraTextField.setTextFormatter(new TextFormatter<>(change -> {
|
||||||
|
if (change.getControlNewText().contains(" ") | change.getControlNewText().contains("\t"))
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return change;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getExpertModeSelected(){ return expertModeCb.isSelected(); }
|
||||||
|
public boolean getAutoIpSelected(){ return autoDetectIpCb.isSelected(); }
|
||||||
|
public boolean getRandPortSelected(){ return randPortCb.isSelected(); }
|
||||||
|
public boolean getNotServeSelected(){ return dontServeCb.isSelected(); }
|
||||||
|
|
||||||
|
public boolean isNsIpValidate(){ return validateNSHostNameCb.isSelected(); }
|
||||||
|
|
||||||
|
public String getHostIp(){ return pcIpTextField.getText(); }
|
||||||
|
public String getHostPort(){ return pcPortTextField.getText(); }
|
||||||
|
public String getHostExtra(){ return pcExtraTextField.getText(); }
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ public class MediatorControl {
|
||||||
public void setController(NSLMainController controller){
|
public void setController(NSLMainController controller){
|
||||||
this.applicationController = controller;
|
this.applicationController = controller;
|
||||||
}
|
}
|
||||||
NSLMainController getContoller(){ return this.applicationController; }
|
public NSLMainController getContoller(){ return this.applicationController; }
|
||||||
|
|
||||||
public synchronized void setTransferActive(boolean state) {
|
public synchronized void setTransferActive(boolean state) {
|
||||||
isTransferActive.set(state);
|
isTransferActive.set(state);
|
||||||
|
|
74
src/main/java/nsusbloader/ModelControllers/LogPrinter.java
Normal file
74
src/main/java/nsusbloader/ModelControllers/LogPrinter.java
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package nsusbloader.ModelControllers;
|
||||||
|
|
||||||
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
import nsusbloader.NSLDataTypes.EMsgType;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
public class LogPrinter {
|
||||||
|
private MessagesConsumer msgConsumer;
|
||||||
|
private BlockingQueue<String> msgQueue;
|
||||||
|
private BlockingQueue<Double> progressQueue;
|
||||||
|
private HashMap<String, EFileStatus> statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap
|
||||||
|
|
||||||
|
public LogPrinter(){
|
||||||
|
this.msgQueue = new LinkedBlockingQueue<>();
|
||||||
|
this.progressQueue = new LinkedBlockingQueue<>();
|
||||||
|
this.statusMap = new HashMap<>();
|
||||||
|
this.msgConsumer = new MessagesConsumer(this.msgQueue, this.progressQueue, this.statusMap);
|
||||||
|
this.msgConsumer.start();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This is what will print to textArea of the application.
|
||||||
|
* */
|
||||||
|
public void print(String message, EMsgType type){
|
||||||
|
try {
|
||||||
|
switch (type){
|
||||||
|
case PASS:
|
||||||
|
msgQueue.put("[ PASS ] "+message+"\n");
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
msgQueue.put("[ FAIL ] "+message+"\n");
|
||||||
|
break;
|
||||||
|
case INFO:
|
||||||
|
msgQueue.put("[ INFO ] "+message+"\n");
|
||||||
|
break;
|
||||||
|
case WARNING:
|
||||||
|
msgQueue.put("[ WARN ] "+message+"\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msgQueue.put(message);
|
||||||
|
}
|
||||||
|
}catch (InterruptedException ie){
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Update progress for progress bar
|
||||||
|
* */
|
||||||
|
public void updateProgress(Double value) throws InterruptedException{
|
||||||
|
progressQueue.put(value);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* When we're done - update status
|
||||||
|
* */
|
||||||
|
public void update(HashMap<String, File> nspMap, EFileStatus status){
|
||||||
|
for (File file: nspMap.values())
|
||||||
|
statusMap.putIfAbsent(file.getName(), status);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* When we're done - update status
|
||||||
|
* */
|
||||||
|
public void update(File file, EFileStatus status){
|
||||||
|
statusMap.putIfAbsent(file.getName(), status);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* When we're done - close it
|
||||||
|
* */
|
||||||
|
public void close(){
|
||||||
|
msgConsumer.interrupt();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package nsusbloader;
|
package nsusbloader.ModelControllers;
|
||||||
|
|
||||||
import javafx.animation.AnimationTimer;
|
import javafx.animation.AnimationTimer;
|
||||||
import javafx.scene.control.ProgressBar;
|
import javafx.scene.control.ProgressBar;
|
||||||
import javafx.scene.control.ProgressIndicator;
|
import javafx.scene.control.ProgressIndicator;
|
||||||
import javafx.scene.control.TextArea;
|
import javafx.scene.control.TextArea;
|
||||||
import nsusbloader.Controllers.NSTableViewController;
|
import nsusbloader.Controllers.NSTableViewController;
|
||||||
|
import nsusbloader.MediatorControl;
|
||||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -69,7 +70,7 @@ public class MessagesConsumer extends AnimationTimer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interrupt(){
|
public void interrupt(){
|
||||||
this.isInterrupted = true;
|
this.isInterrupted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
356
src/main/java/nsusbloader/NET/NETCommunications.java
Normal file
356
src/main/java/nsusbloader/NET/NETCommunications.java
Normal file
|
@ -0,0 +1,356 @@
|
||||||
|
package nsusbloader.NET;
|
||||||
|
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
import nsusbloader.ModelControllers.LogPrinter;
|
||||||
|
import nsusbloader.NSLDataTypes.EMsgType;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
||||||
|
|
||||||
|
private LogPrinter logPrinter;
|
||||||
|
|
||||||
|
private String hostIP;
|
||||||
|
private int hostPort;
|
||||||
|
private String extras;
|
||||||
|
|
||||||
|
private String switchIP;
|
||||||
|
|
||||||
|
private HashMap<String, File> nspMap;
|
||||||
|
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
|
||||||
|
private boolean isValid;
|
||||||
|
private boolean doNotServeRequests;
|
||||||
|
|
||||||
|
private OutputStream currSockOS;
|
||||||
|
private PrintWriter currSockPW;
|
||||||
|
/**
|
||||||
|
* Simple constructor that everybody uses
|
||||||
|
* */
|
||||||
|
public NETCommunications(List<File> filesList, String switchIP, boolean doNotServeRequests, String hostIPaddr, String hostPortNum, String extras){
|
||||||
|
this.doNotServeRequests = doNotServeRequests;
|
||||||
|
if (doNotServeRequests)
|
||||||
|
this.extras = extras;
|
||||||
|
else
|
||||||
|
this.extras = "";
|
||||||
|
this.switchIP = switchIP;
|
||||||
|
this.logPrinter = new LogPrinter();
|
||||||
|
this.nspMap = new HashMap<>();
|
||||||
|
// Collect and encode NSP files list
|
||||||
|
try {
|
||||||
|
for (File nspFile : filesList)
|
||||||
|
nspMap.put(URLEncoder.encode(nspFile.getName(), "UTF-8"), nspFile);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
for (File nspFile : filesList)
|
||||||
|
nspMap.put(nspFile.getName(), nspFile);
|
||||||
|
close(EFileStatus.FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Resolve IP
|
||||||
|
if (hostIPaddr.isEmpty()) {
|
||||||
|
DatagramSocket socket;
|
||||||
|
try { // todo: check other method if internet unavaliable
|
||||||
|
socket = new DatagramSocket();
|
||||||
|
socket.connect(InetAddress.getByName("8.8.8.8"), 10002); // Google
|
||||||
|
hostIP = socket.getLocalAddress().getHostAddress();
|
||||||
|
socket.close();
|
||||||
|
} catch (SocketException | UnknownHostException e) {
|
||||||
|
logPrinter.print("NET: Can't get your computer IP using Google DNS server. Returned:\n\t"+e.getMessage(), EMsgType.INFO);
|
||||||
|
try {
|
||||||
|
socket = new DatagramSocket();
|
||||||
|
socket.connect(InetAddress.getByName("193.0.14.129"), 10002); // RIPE NCC
|
||||||
|
hostIP = socket.getLocalAddress().getHostAddress();
|
||||||
|
socket.close();
|
||||||
|
} catch (SocketException | UnknownHostException e1) {
|
||||||
|
logPrinter.print("NET: Can't get your computer IP using RIPE NCC root server. Returned:\n\t"+e1.getMessage(), EMsgType.INFO);
|
||||||
|
try {
|
||||||
|
socket = new DatagramSocket();
|
||||||
|
socket.connect(InetAddress.getByName("people.com.cn"), 10002); // Renmin Ribao
|
||||||
|
hostIP = socket.getLocalAddress().getHostAddress();
|
||||||
|
socket.close();
|
||||||
|
} catch (SocketException | UnknownHostException e2) {
|
||||||
|
logPrinter.print("NET: Can't get your computer IP using Renmin Ribao server. Returned:\n\t"+e2.getMessage(), EMsgType.FAIL);
|
||||||
|
logPrinter.print("Try using 'Expert mode' and set IP manually.", EMsgType.INFO);
|
||||||
|
try {
|
||||||
|
Enumeration enumeration = NetworkInterface.getNetworkInterfaces();
|
||||||
|
while (enumeration.hasMoreElements()) {
|
||||||
|
NetworkInterface n = (NetworkInterface) enumeration.nextElement();
|
||||||
|
Enumeration enumeration1 = n.getInetAddresses();
|
||||||
|
while (enumeration1.hasMoreElements()) {
|
||||||
|
InetAddress i = (InetAddress) enumeration1.nextElement();
|
||||||
|
logPrinter.print("Check for: " + i.getHostAddress(), EMsgType.INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SocketException socketException) { // Good block.
|
||||||
|
logPrinter.print("Can't determine possible variants. Returned:\n\t"+socketException.getMessage(), EMsgType.FAIL);
|
||||||
|
}
|
||||||
|
isValid = false;
|
||||||
|
close(EFileStatus.FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logPrinter.print("NET: Your IP detected as: " + hostIP, EMsgType.PASS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.hostIP = hostIPaddr;
|
||||||
|
logPrinter.print("NET: Your IP defined as: " + hostIP, EMsgType.PASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get port
|
||||||
|
if (hostPortNum.isEmpty()) {
|
||||||
|
Random portRandomizer = new Random();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
try {
|
||||||
|
this.hostPort = portRandomizer.nextInt(999) + 6000;
|
||||||
|
serverSocket = new ServerSocket(hostPort); //System.out.println(serverSocket.getInetAddress()); 0.0.0.0
|
||||||
|
logPrinter.print("NET: Your port detected as: " + hostPort, EMsgType.PASS);
|
||||||
|
break;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
if (i == 4) {
|
||||||
|
logPrinter.print("NET: Can't find good port", EMsgType.FAIL);
|
||||||
|
logPrinter.print("Try using 'Expert mode' and set port by yourself.", EMsgType.INFO);
|
||||||
|
isValid = false;
|
||||||
|
close(EFileStatus.FAILED);
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
logPrinter.print("NET: Can't use port " + hostPort + "\nLooking for another one.", EMsgType.WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
this.hostPort = Integer.parseInt(hostPortNum);
|
||||||
|
serverSocket = new ServerSocket(hostPort);
|
||||||
|
logPrinter.print("NET: Using defined port number: " + hostPort, EMsgType.PASS);
|
||||||
|
}
|
||||||
|
catch (NumberFormatException | IOException exeption){ // Literally never happens.
|
||||||
|
logPrinter.print("NET: Can't use port defined in settings: " + hostPortNum + "\nIt's not a valid number!", EMsgType.WARNING);
|
||||||
|
isValid = false;
|
||||||
|
close(EFileStatus.FAILED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Override cancel block to close connection by ourselves
|
||||||
|
* */
|
||||||
|
@Override
|
||||||
|
protected void cancelled() {
|
||||||
|
this.close(EFileStatus.UNKNOWN);
|
||||||
|
super.cancelled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void call() {
|
||||||
|
if (!isValid | isCancelled())
|
||||||
|
return null;
|
||||||
|
logPrinter.print("\tStart chain", EMsgType.INFO);
|
||||||
|
// Create string that we'll send to TF and which initiates chain
|
||||||
|
StringBuilder myStrBuilder;
|
||||||
|
|
||||||
|
myStrBuilder = new StringBuilder();
|
||||||
|
for (String fileNameEncoded : nspMap.keySet()) {
|
||||||
|
myStrBuilder.append(hostIP);
|
||||||
|
myStrBuilder.append(':');
|
||||||
|
myStrBuilder.append(hostPort);
|
||||||
|
myStrBuilder.append('/');
|
||||||
|
myStrBuilder.append(extras);
|
||||||
|
myStrBuilder.append(fileNameEncoded);
|
||||||
|
myStrBuilder.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] nspListNames = myStrBuilder.toString().getBytes(StandardCharsets.UTF_8); // Follow the
|
||||||
|
byte[] nspListSize = ByteBuffer.allocate(Integer.BYTES).putInt(nspListNames.length).array(); // defining order
|
||||||
|
|
||||||
|
try {
|
||||||
|
Socket handShakeSocket = new Socket(InetAddress.getByName(switchIP), 2000);
|
||||||
|
OutputStream os = handShakeSocket.getOutputStream();
|
||||||
|
|
||||||
|
os.write(nspListSize);
|
||||||
|
os.write(nspListNames);
|
||||||
|
os.flush();
|
||||||
|
|
||||||
|
handShakeSocket.close();
|
||||||
|
}
|
||||||
|
catch (IOException uhe){
|
||||||
|
logPrinter.print("NET: Unable to connect to NS and send files list. Returned:\n\t"+uhe.getMessage(), EMsgType.FAIL);
|
||||||
|
close(EFileStatus.UNKNOWN);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Check if we should serve requests
|
||||||
|
if (this.doNotServeRequests){
|
||||||
|
logPrinter.print("NET: List of files transferred. Replies won't be served.", EMsgType.PASS);
|
||||||
|
close(EFileStatus.UNKNOWN);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
logPrinter.print("NET: Initiation files list has been sent to NS.", EMsgType.PASS);
|
||||||
|
|
||||||
|
// Go transfer
|
||||||
|
Socket clientSocket;
|
||||||
|
work_routine:
|
||||||
|
while (true){
|
||||||
|
try {
|
||||||
|
clientSocket = serverSocket.accept();
|
||||||
|
BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(clientSocket.getInputStream())
|
||||||
|
);
|
||||||
|
|
||||||
|
currSockOS = clientSocket.getOutputStream();
|
||||||
|
currSockPW = new PrintWriter(new OutputStreamWriter(currSockOS));
|
||||||
|
|
||||||
|
String line;
|
||||||
|
LinkedList<String> tcpPacket = new LinkedList<>();
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
//System.out.println(line); // TODO: remove DBG
|
||||||
|
if (line.trim().isEmpty()) { // If TCP packet is ended
|
||||||
|
if (handleRequest(tcpPacket)) // Proceed required things
|
||||||
|
break work_routine;
|
||||||
|
tcpPacket.clear(); // Clear data and wait for next TCP packet
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tcpPacket.add(line); // Otherwise collect data
|
||||||
|
}
|
||||||
|
// and reopen client sock
|
||||||
|
clientSocket.close();
|
||||||
|
}
|
||||||
|
catch (IOException ioe){ // If server socket closed, then client socket also closed.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isCancelled())
|
||||||
|
close(EFileStatus.UNKNOWN);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 200 206 400 (inv range) 404 416 (Range Not Satisfiable )
|
||||||
|
/**
|
||||||
|
* Handle requests
|
||||||
|
* @return true if failed
|
||||||
|
* */
|
||||||
|
private boolean handleRequest(LinkedList<String> packet){
|
||||||
|
//private boolean handleRequest(LinkedList<String> packet, OutputStreamWriter pw){
|
||||||
|
File requestedFile;
|
||||||
|
requestedFile = nspMap.get(packet.get(0).replaceAll("(^[A-z\\s]+/)|(\\s+?.*$)", ""));
|
||||||
|
if (!requestedFile.exists() || requestedFile.length() == 0){ // well.. tell 404 if file exists with 0 length is against standard, but saves time
|
||||||
|
currSockPW.write(NETPacket.getCode404());
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: File "+requestedFile.getName()+" doesn't exists or have 0 size. Returning 404", EMsgType.FAIL);
|
||||||
|
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (packet.get(0).startsWith("HEAD")){
|
||||||
|
currSockPW.write(NETPacket.getCode200(requestedFile.length()));
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: Replying for requested file: "+requestedFile.getName(), EMsgType.INFO);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (packet.get(0).startsWith("GET")) {
|
||||||
|
for (String line: packet) {
|
||||||
|
if (line.toLowerCase().startsWith("range")) { //todo: fix
|
||||||
|
try {
|
||||||
|
String[] rangeStr = line.toLowerCase().replaceAll("^range:\\s+?bytes=", "").split("-", 2);
|
||||||
|
if (!rangeStr[0].isEmpty() && !rangeStr[1].isEmpty()) { // If both ranges defined: Read requested
|
||||||
|
if (Long.parseLong(rangeStr[0]) > Long.parseLong(rangeStr[1])){ // If start bytes greater then end bytes
|
||||||
|
currSockPW.write(NETPacket.getCode400());
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: Requested range for "+requestedFile.getName()+" is incorrect. Returning 400", EMsgType.FAIL);
|
||||||
|
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (writeToSocket(requestedFile, Long.parseLong(rangeStr[0]), Long.parseLong(rangeStr[1]))) // DO WRITE
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (!rangeStr[0].isEmpty()) { // If only START defined: Read all
|
||||||
|
if (writeToSocket(requestedFile, Long.parseLong(rangeStr[0]), requestedFile.length())) // DO WRITE
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (!rangeStr[1].isEmpty()) { // If only END defined: Try to read last 500 bytes
|
||||||
|
if (requestedFile.length() > 500){
|
||||||
|
if (writeToSocket(requestedFile, requestedFile.length()-500, requestedFile.length())) // DO WRITE
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else { // If file smaller than 500 bytes
|
||||||
|
currSockPW.write(NETPacket.getCode416());
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: File size requested for "+requestedFile.getName()+" while actual size of it: "+requestedFile.length()+". Returning 416", EMsgType.FAIL);
|
||||||
|
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currSockPW.write(NETPacket.getCode400()); // If Range not defined: like "Range: bytes=-"
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: Requested range for "+requestedFile.getName()+" is incorrect (empty start & end). Returning 400", EMsgType.FAIL);
|
||||||
|
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (NumberFormatException nfe){
|
||||||
|
currSockPW.write(NETPacket.getCode400());
|
||||||
|
currSockPW.flush();
|
||||||
|
logPrinter.print("NET: Requested range for "+requestedFile.getName()+" has incorrect format. Returning 400\n\t"+nfe.getMessage(), EMsgType.FAIL);
|
||||||
|
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send files.
|
||||||
|
* */
|
||||||
|
private boolean writeToSocket(File file, long start, long end){
|
||||||
|
currSockPW.write(NETPacket.getCode206(file.length(), start, end));
|
||||||
|
currSockPW.flush();
|
||||||
|
try{
|
||||||
|
long count = end - start;
|
||||||
|
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||||
|
raf.seek(start);
|
||||||
|
for (int i=0; i <= count; i++)
|
||||||
|
currSockOS.write(raf.read());
|
||||||
|
currSockOS.flush();
|
||||||
|
raf.close();
|
||||||
|
}
|
||||||
|
catch (IOException ioe){
|
||||||
|
logPrinter.print("IO Exception:\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||||
|
ioe.printStackTrace();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Close when done
|
||||||
|
* */
|
||||||
|
private void close(EFileStatus status){
|
||||||
|
if (isCancelled())
|
||||||
|
logPrinter.print("NET: Interrupted by user.", EMsgType.INFO);
|
||||||
|
try {
|
||||||
|
serverSocket.close();
|
||||||
|
logPrinter.print("NET: Closing server socket.", EMsgType.PASS);
|
||||||
|
}
|
||||||
|
catch (IOException | NullPointerException ioe){
|
||||||
|
logPrinter.print("NET: Closing server socket failed. Sometimes it's not an issue.", EMsgType.WARNING);
|
||||||
|
}
|
||||||
|
if (status != null) {
|
||||||
|
logPrinter.update(nspMap, status);
|
||||||
|
}
|
||||||
|
logPrinter.print("\tEnd chain", EMsgType.INFO);
|
||||||
|
logPrinter.close();
|
||||||
|
}
|
||||||
|
}
|
64
src/main/java/nsusbloader/NET/NETPacket.java
Normal file
64
src/main/java/nsusbloader/NET/NETPacket.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package nsusbloader.NET;
|
||||||
|
|
||||||
|
import nsusbloader.NSLMain;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public class NETPacket {
|
||||||
|
private static final String CODE_200 =
|
||||||
|
"HTTP/1.0 200 OK\r\n" +
|
||||||
|
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||||
|
"Date: %s\r\n" +
|
||||||
|
"Content-type: application/octet-stream\r\n" +
|
||||||
|
"Accept-Ranges: bytes\r\n" +
|
||||||
|
"Content-Range: bytes 0-%d/%d\r\n" +
|
||||||
|
"Content-Length: %d\r\n" +
|
||||||
|
"Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT\r\n\r\n";
|
||||||
|
private static final String CODE_206 =
|
||||||
|
"HTTP/1.0 206 Partial Content\r\n"+
|
||||||
|
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||||
|
"Date: %s\r\n" +
|
||||||
|
"Content-type: application/octet-stream\r\n"+
|
||||||
|
"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";
|
||||||
|
private static final String CODE_400 =
|
||||||
|
"HTTP/1.0 400 invalid range\r\n"+
|
||||||
|
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||||
|
"Date: %s\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Content-Type: text/html;charset=utf-8\r\n"+
|
||||||
|
"Content-Length: 0\r\n\r\n";
|
||||||
|
private static final String CODE_404 =
|
||||||
|
"HTTP/1.0 404 Not Found\r\n"+
|
||||||
|
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||||
|
"Date: %s\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Content-Type: text/html;charset=utf-8\r\n"+
|
||||||
|
"Content-Length: 0\r\n\r\n";
|
||||||
|
private static final String CODE_416 =
|
||||||
|
"HTTP/1.0 416 Requested Range Not Satisfiable\r\n"+
|
||||||
|
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +
|
||||||
|
"Date: %s\r\n" +
|
||||||
|
"Connection: close\r\n"+
|
||||||
|
"Content-Type: text/html;charset=utf-8\r\n"+
|
||||||
|
"Content-Length: 0\r\n\r\n";
|
||||||
|
public static String getCode200(long nspFileSize){
|
||||||
|
return String.format(CODE_200, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME), nspFileSize-1, nspFileSize, nspFileSize);
|
||||||
|
}
|
||||||
|
public static String getCode206(long nspFileSize, long startPos, long endPos){
|
||||||
|
return String.format(CODE_206, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME), startPos, endPos, nspFileSize, endPos-startPos+1);
|
||||||
|
}
|
||||||
|
public static String getCode404(){
|
||||||
|
return String.format(CODE_404, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||||
|
}
|
||||||
|
public static String getCode416(){
|
||||||
|
return String.format(CODE_416, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||||
|
}
|
||||||
|
public static String getCode400(){
|
||||||
|
return String.format(CODE_400, ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
package nsusbloader.NSLDataTypes;
|
package nsusbloader.NSLDataTypes;
|
||||||
|
|
||||||
public enum EFileStatus {
|
public enum EFileStatus {
|
||||||
UPLOADED, INCORRECT_FILE_FAILED, FAILED, UNKNOWN
|
UPLOADED, INCORRECT_FILE_FAILED, FAILED, INDETERMINATE, UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,14 @@ import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class NSLMain extends Application {
|
public class NSLMain extends Application {
|
||||||
public static final String appVersion = "v0.2.2";
|
public static final String appVersion = "v0.3";
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception{
|
public void start(Stage primaryStage) throws Exception{
|
||||||
|
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
||||||
|
|
||||||
ResourceBundle rb;
|
Locale userLocale = new Locale(Locale.getDefault().getISO3Language()); // NOTE: user locale based on ISO3 Language codes
|
||||||
if (Locale.getDefault().getISO3Language().equals("rus"))
|
ResourceBundle rb = ResourceBundle.getBundle("locale", userLocale);
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("ru"));
|
|
||||||
else
|
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("en"));
|
|
||||||
|
|
||||||
loader.setResources(rb);
|
loader.setResources(rb);
|
||||||
Parent root = loader.load();
|
Parent root = loader.load();
|
||||||
|
|
|
@ -10,7 +10,6 @@ public class ServiceWindow {
|
||||||
/**
|
/**
|
||||||
* Create window with notification
|
* Create window with notification
|
||||||
* */
|
* */
|
||||||
/* // not used
|
|
||||||
public static void getErrorNotification(String title, String body){
|
public static void getErrorNotification(String title, String body){
|
||||||
Alert alertBox = new Alert(Alert.AlertType.ERROR);
|
Alert alertBox = new Alert(Alert.AlertType.ERROR);
|
||||||
alertBox.setTitle(title);
|
alertBox.setTitle(title);
|
||||||
|
@ -20,10 +19,9 @@ public class ServiceWindow {
|
||||||
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
alertBox.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||||
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
alertBox.setResizable(true); // Java bug workaround for JDR11/OpenJFX. TODO: nothing. really.
|
||||||
alertBox.setResizable(false);
|
alertBox.setResizable(false);
|
||||||
alertBox.getDialogPane().getStylesheets().add("/res/app.css");
|
alertBox.getDialogPane().getStylesheets().add(AppPreferences.getInstance().getTheme());
|
||||||
alertBox.show();
|
alertBox.show();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Create notification window with confirm/deny
|
* Create notification window with confirm/deny
|
||||||
* */
|
* */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package nsusbloader.PFS;
|
package nsusbloader.USB.PFS;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
|
@ -1,5 +1,6 @@
|
||||||
package nsusbloader.PFS;
|
package nsusbloader.USB.PFS;
|
||||||
|
|
||||||
|
import nsusbloader.ModelControllers.LogPrinter;
|
||||||
import nsusbloader.NSLDataTypes.EMsgType;
|
import nsusbloader.NSLDataTypes.EMsgType;
|
||||||
import nsusbloader.ServiceWindow;
|
import nsusbloader.ServiceWindow;
|
||||||
|
|
||||||
|
@ -8,7 +9,6 @@ import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in GoldLeaf USB protocol
|
* Used in GoldLeaf USB protocol
|
||||||
|
@ -16,7 +16,7 @@ import java.util.concurrent.BlockingQueue;
|
||||||
public class PFSProvider {
|
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 static final byte[] PFS0 = new byte[]{(byte)0x50, (byte)0x46, (byte)0x53, (byte)0x30}; // PFS0, and what did you think?
|
||||||
|
|
||||||
private BlockingQueue<String> msgQueue;
|
private LogPrinter logPrinter;
|
||||||
private ResourceBundle rb;
|
private ResourceBundle rb;
|
||||||
|
|
||||||
private RandomAccessFile randAccessFile;
|
private RandomAccessFile randAccessFile;
|
||||||
|
@ -25,20 +25,18 @@ public class PFSProvider {
|
||||||
private long bodySize;
|
private long bodySize;
|
||||||
private int ticketID = -1;
|
private int ticketID = -1;
|
||||||
|
|
||||||
public PFSProvider(File nspFile, BlockingQueue msgQueue){
|
public PFSProvider(File nspFile, LogPrinter logPrinter){
|
||||||
this.msgQueue = msgQueue;
|
this.logPrinter = logPrinter;
|
||||||
try {
|
try {
|
||||||
this.randAccessFile = new RandomAccessFile(nspFile, "r");
|
this.randAccessFile = new RandomAccessFile(nspFile, "r");
|
||||||
nspFileName = nspFile.getName();
|
nspFileName = nspFile.getName();
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException fnfe){
|
catch (FileNotFoundException fnfe){
|
||||||
printLog("PFS File not founnd: \n "+fnfe.getMessage(), EMsgType.FAIL);
|
logPrinter.print("PFS File not founnd: \n "+fnfe.getMessage(), EMsgType.FAIL);
|
||||||
nspFileName = null;
|
nspFileName = null;
|
||||||
}
|
}
|
||||||
if (Locale.getDefault().getISO3Language().equals("rus"))
|
Locale userLocale = new Locale(Locale.getDefault().getISO3Language());
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("ru"));
|
rb = ResourceBundle.getBundle("locale", userLocale);
|
||||||
else
|
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("en"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean init() {
|
public boolean init() {
|
||||||
|
@ -48,22 +46,22 @@ public class PFSProvider {
|
||||||
int filesCount;
|
int filesCount;
|
||||||
int header;
|
int header;
|
||||||
|
|
||||||
printLog("PFS Start NSP file analyze for ["+nspFileName+"]", EMsgType.INFO);
|
logPrinter.print("PFS Start NSP file analyze for ["+nspFileName+"]", EMsgType.INFO);
|
||||||
try {
|
try {
|
||||||
byte[] fileStartingBytes = new byte[12];
|
byte[] fileStartingBytes = new byte[12];
|
||||||
// Read PFS0, files count, header, padding (4 zero bytes)
|
// Read PFS0, files count, header, padding (4 zero bytes)
|
||||||
if (randAccessFile.read(fileStartingBytes) == 12)
|
if (randAccessFile.read(fileStartingBytes) == 12)
|
||||||
printLog("PFS Read file starting bytes.", EMsgType.PASS);
|
logPrinter.print("PFS Read file starting bytes.", EMsgType.PASS);
|
||||||
else {
|
else {
|
||||||
printLog("PFS Read file starting bytes.", EMsgType.FAIL);
|
logPrinter.print("PFS Read file starting bytes.", EMsgType.FAIL);
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check PFS0
|
// Check PFS0
|
||||||
if (Arrays.equals(PFS0, Arrays.copyOfRange(fileStartingBytes, 0, 4)))
|
if (Arrays.equals(PFS0, Arrays.copyOfRange(fileStartingBytes, 0, 4)))
|
||||||
printLog("PFS Read 'PFS0'.", EMsgType.PASS);
|
logPrinter.print("PFS Read 'PFS0'.", EMsgType.PASS);
|
||||||
else {
|
else {
|
||||||
printLog("PFS Read 'PFS0'.", EMsgType.WARNING);
|
logPrinter.print("PFS Read 'PFS0'.", EMsgType.WARNING);
|
||||||
if (!ServiceWindow.getConfirmationWindow(nspFileName+"\n"+rb.getString("windowTitleConfirmWrongPFS0"), rb.getString("windowBodyConfirmWrongPFS0"))) {
|
if (!ServiceWindow.getConfirmationWindow(nspFileName+"\n"+rb.getString("windowTitleConfirmWrongPFS0"), rb.getString("windowBodyConfirmWrongPFS0"))) {
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,19 +70,19 @@ public class PFSProvider {
|
||||||
// Get files count
|
// Get files count
|
||||||
filesCount = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 4, 8)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
filesCount = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 4, 8)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||||
if (filesCount > 0 ) {
|
if (filesCount > 0 ) {
|
||||||
printLog("PFS Read files count [" + filesCount + "]", EMsgType.PASS);
|
logPrinter.print("PFS Read files count [" + filesCount + "]", EMsgType.PASS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("PFS Read files count", EMsgType.FAIL);
|
logPrinter.print("PFS Read files count", EMsgType.FAIL);
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Get header
|
// Get header
|
||||||
header = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 8, 12)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
header = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 8, 12)).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||||
if (header > 0 )
|
if (header > 0 )
|
||||||
printLog("PFS Read header ["+header+"]", EMsgType.PASS);
|
logPrinter.print("PFS Read header ["+header+"]", EMsgType.PASS);
|
||||||
else {
|
else {
|
||||||
printLog("PFS Read header ", EMsgType.FAIL);
|
logPrinter.print("PFS Read header ", EMsgType.FAIL);
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -103,10 +101,10 @@ public class PFSProvider {
|
||||||
|
|
||||||
for (int i=0; i<filesCount; i++){
|
for (int i=0; i<filesCount; i++){
|
||||||
if (randAccessFile.read(ncaInfoArr) == 24) {
|
if (randAccessFile.read(ncaInfoArr) == 24) {
|
||||||
printLog("PFS Read NCA inside NSP: " + i, EMsgType.PASS);
|
logPrinter.print("PFS Read NCA inside NSP: " + i, EMsgType.PASS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("PFS Read NCA inside NSP: "+i, EMsgType.FAIL);
|
logPrinter.print("PFS Read NCA inside NSP: "+i, EMsgType.FAIL);
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -115,10 +113,10 @@ public class PFSProvider {
|
||||||
nca_size = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 12, 20)).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.
|
nca_name_offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 20, 24)).order(ByteOrder.LITTLE_ENDIAN).getInt(); // yes, cast from int to long.
|
||||||
|
|
||||||
printLog(" Padding check", offset == 0?EMsgType.PASS:EMsgType.WARNING);
|
logPrinter.print(" Padding check", offset == 0?EMsgType.PASS:EMsgType.WARNING);
|
||||||
printLog(" NCA offset check: "+nca_offset, nca_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
|
logPrinter.print(" NCA offset check: "+nca_offset, nca_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
|
||||||
printLog(" NCA size check: "+nca_size, nca_size >= 0?EMsgType.PASS: EMsgType.WARNING);
|
logPrinter.print(" NCA size check: "+nca_size, nca_size >= 0?EMsgType.PASS: EMsgType.WARNING);
|
||||||
printLog(" NCA name offset check: "+nca_name_offset, nca_name_offset >= 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 ncaFile = new NCAFile();
|
||||||
ncaFile.setNcaOffset(nca_offset);
|
ncaFile.setNcaOffset(nca_offset);
|
||||||
|
@ -130,15 +128,15 @@ public class PFSProvider {
|
||||||
// Final offset
|
// Final offset
|
||||||
byte[] bufForInt = new byte[4];
|
byte[] bufForInt = new byte[4];
|
||||||
if ((randAccessFile.read(bufForInt) == 4) && (Arrays.equals(bufForInt, new byte[4])))
|
if ((randAccessFile.read(bufForInt) == 4) && (Arrays.equals(bufForInt, new byte[4])))
|
||||||
printLog("PFS Final padding check", EMsgType.PASS);
|
logPrinter.print("PFS Final padding check", EMsgType.PASS);
|
||||||
else
|
else
|
||||||
printLog("PFS Final padding check", EMsgType.WARNING);
|
logPrinter.print("PFS Final padding check", EMsgType.WARNING);
|
||||||
|
|
||||||
// Calculate position including header for body size offset
|
// Calculate position including header for body size offset
|
||||||
bodySize = randAccessFile.getFilePointer()+header;
|
bodySize = randAccessFile.getFilePointer()+header;
|
||||||
//*********************************************************************************************
|
//*********************************************************************************************
|
||||||
// Collect file names from NCAs
|
// Collect file names from NCAs
|
||||||
printLog("PFS Collecting file names", EMsgType.INFO);
|
logPrinter.print("PFS Collecting file names", EMsgType.INFO);
|
||||||
List<Byte> ncaFN; // Temporary
|
List<Byte> ncaFN; // Temporary
|
||||||
byte[] b = new byte[1]; // Temporary
|
byte[] b = new byte[1]; // Temporary
|
||||||
for (int i=0; i<filesCount; i++){
|
for (int i=0; i<filesCount; i++){
|
||||||
|
@ -161,10 +159,10 @@ public class PFSProvider {
|
||||||
randAccessFile.close();
|
randAccessFile.close();
|
||||||
}
|
}
|
||||||
catch (IOException ioe){
|
catch (IOException ioe){
|
||||||
printLog("PFS Failed NSP file analyze for ["+nspFileName+"]\n "+ioe.getMessage(), EMsgType.FAIL);
|
logPrinter.print("PFS Failed NSP file analyze for ["+nspFileName+"]\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||||
ioe.printStackTrace();
|
ioe.printStackTrace();
|
||||||
}
|
}
|
||||||
printLog("PFS Finish NSP file analyze for ["+nspFileName+"]", EMsgType.PASS);
|
logPrinter.print("PFS Finish NSP file analyze for ["+nspFileName+"]", EMsgType.PASS);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -217,27 +215,4 @@ public class PFSProvider {
|
||||||
public int getNcaTicketID(){
|
public int getNcaTicketID(){
|
||||||
return ticketID;
|
return ticketID;
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* This is what will print to textArea of the application.
|
|
||||||
**/
|
|
||||||
private void printLog(String message, EMsgType type){
|
|
||||||
try {
|
|
||||||
switch (type){
|
|
||||||
case PASS:
|
|
||||||
msgQueue.put("[ PASS ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
msgQueue.put("[ FAIL ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case INFO:
|
|
||||||
msgQueue.put("[ INFO ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case WARNING:
|
|
||||||
msgQueue.put("[ WARN ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}catch (InterruptedException ie){
|
|
||||||
ie.printStackTrace(); //TODO: ???
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
package nsusbloader;
|
package nsusbloader.USB;
|
||||||
|
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
|
import nsusbloader.ModelControllers.LogPrinter;
|
||||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
import nsusbloader.NSLDataTypes.EMsgType;
|
import nsusbloader.NSLDataTypes.EMsgType;
|
||||||
import nsusbloader.PFS.PFSProvider;
|
import nsusbloader.USB.PFS.PFSProvider;
|
||||||
import org.usb4java.*;
|
import org.usb4java.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -15,21 +16,13 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
|
|
||||||
import static nsusbloader.RainbowHexDump.hexDumpUTF8;
|
|
||||||
|
|
||||||
public class UsbCommunications extends Task<Void> {
|
public class UsbCommunications extends Task<Void> {
|
||||||
private final int DEFAULT_INTERFACE = 0;
|
private final int DEFAULT_INTERFACE = 0;
|
||||||
|
|
||||||
private BlockingQueue<String> msgQueue;
|
private LogPrinter logPrinter;
|
||||||
private BlockingQueue<Double> progressQueue;
|
|
||||||
private HashMap<String, EFileStatus> statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap
|
|
||||||
private EFileStatus status = EFileStatus.FAILED;
|
private EFileStatus status = EFileStatus.FAILED;
|
||||||
|
|
||||||
private MessagesConsumer msgConsumer;
|
|
||||||
|
|
||||||
private HashMap<String, File> nspMap;
|
private HashMap<String, File> nspMap;
|
||||||
|
|
||||||
private Context contextNS;
|
private Context contextNS;
|
||||||
|
@ -52,39 +45,35 @@ public class UsbCommunications extends Task<Void> {
|
||||||
this.nspMap = new HashMap<>();
|
this.nspMap = new HashMap<>();
|
||||||
for (File f: nspList)
|
for (File f: nspList)
|
||||||
nspMap.put(f.getName(), f);
|
nspMap.put(f.getName(), f);
|
||||||
this.msgQueue = new LinkedBlockingQueue<>();
|
this.logPrinter = new LogPrinter();
|
||||||
this.progressQueue = new LinkedBlockingQueue<>();
|
|
||||||
this.statusMap = new HashMap<>();
|
|
||||||
this.msgConsumer = new MessagesConsumer(this.msgQueue, this.progressQueue, this.statusMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void call() {
|
protected Void call() {
|
||||||
this.msgConsumer.start();
|
|
||||||
int result = -9999;
|
int result = -9999;
|
||||||
|
|
||||||
printLog("\tStart chain", EMsgType.INFO);
|
logPrinter.print("\tStart chain", EMsgType.INFO);
|
||||||
// Creating Context required by libusb. Optional. TODO: Consider removing.
|
// Creating Context required by libusb. Optional. TODO: Consider removing.
|
||||||
contextNS = new Context();
|
contextNS = new Context();
|
||||||
result = LibUsb.init(contextNS);
|
result = LibUsb.init(contextNS);
|
||||||
if (result != LibUsb.SUCCESS) {
|
if (result != LibUsb.SUCCESS) {
|
||||||
printLog("libusb initialization\n Returned: "+result, EMsgType.FAIL);
|
logPrinter.print("libusb initialization\n Returned: "+result, EMsgType.FAIL);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printLog("libusb initialization", EMsgType.PASS);
|
logPrinter.print("libusb initialization", EMsgType.PASS);
|
||||||
|
|
||||||
// Searching for NS in devices: obtain list of all devices
|
// Searching for NS in devices: obtain list of all devices
|
||||||
DeviceList deviceList = new DeviceList();
|
DeviceList deviceList = new DeviceList();
|
||||||
result = LibUsb.getDeviceList(contextNS, deviceList);
|
result = LibUsb.getDeviceList(contextNS, deviceList);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
printLog("Get device list\n Returned: "+result, EMsgType.FAIL);
|
logPrinter.print("Get device list\n Returned: "+result, EMsgType.FAIL);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("Get device list", EMsgType.PASS);
|
logPrinter.print("Get device list", EMsgType.PASS);
|
||||||
}
|
}
|
||||||
// Searching for NS in devices: looking for NS
|
// Searching for NS in devices: looking for NS
|
||||||
DeviceDescriptor descriptor;
|
DeviceDescriptor descriptor;
|
||||||
|
@ -93,14 +82,14 @@ public class UsbCommunications extends Task<Void> {
|
||||||
descriptor = new DeviceDescriptor(); // mmm.. leave it as is.
|
descriptor = new DeviceDescriptor(); // mmm.. leave it as is.
|
||||||
result = LibUsb.getDeviceDescriptor(device, descriptor);
|
result = LibUsb.getDeviceDescriptor(device, descriptor);
|
||||||
if (result != LibUsb.SUCCESS){
|
if (result != LibUsb.SUCCESS){
|
||||||
printLog("Read file descriptors for USB devices\n Returned: "+result, EMsgType.FAIL);
|
logPrinter.print("Read file descriptors for USB devices\n Returned: "+result, EMsgType.FAIL);
|
||||||
LibUsb.freeDeviceList(deviceList, true);
|
LibUsb.freeDeviceList(deviceList, true);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ((descriptor.idVendor() == 0x057E) && descriptor.idProduct() == 0x3000){
|
if ((descriptor.idVendor() == 0x057E) && descriptor.idProduct() == 0x3000){
|
||||||
deviceNS = device;
|
deviceNS = device;
|
||||||
printLog("Read file descriptors for USB devices", EMsgType.PASS);
|
logPrinter.print("Read file descriptors for USB devices", EMsgType.PASS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,19 +103,17 @@ public class UsbCommunications extends Task<Void> {
|
||||||
|
|
||||||
switch (result){
|
switch (result){
|
||||||
case 0:
|
case 0:
|
||||||
System.out.println("SUCCES");
|
logPrinter.print("DBG: getActiveConfigDescriptor\n"+configDescriptor.dump(), EMsgType.PASS);
|
||||||
System.out.println("\n"+configDescriptor.dump());
|
|
||||||
break;
|
break;
|
||||||
case LibUsb.ERROR_NOT_FOUND:
|
case LibUsb.ERROR_NOT_FOUND:
|
||||||
System.out.println("ERROR_NOT_FOUND "+result);
|
logPrinter.print("DBG: getActiveConfigDescriptor: ERROR_NOT_FOUND", EMsgType.FAIL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.out.println("UNKNOWN "+result);
|
logPrinter.print("DBG: getActiveConfigDescriptor: "+result, EMsgType.FAIL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
System.out.println();
|
|
||||||
|
|
||||||
//LibUsb.freeConfigDescriptor(configDescriptor);
|
LibUsb.freeConfigDescriptor(configDescriptor);
|
||||||
//*/
|
//*/
|
||||||
/*
|
/*
|
||||||
* So what did we learn?
|
* So what did we learn?
|
||||||
|
@ -143,10 +130,10 @@ public class UsbCommunications extends Task<Void> {
|
||||||
////////////////////////////////////////// DEBUG INFORMATION END /////////////////////////////////////////////
|
////////////////////////////////////////// DEBUG INFORMATION END /////////////////////////////////////////////
|
||||||
|
|
||||||
if (deviceNS != null){
|
if (deviceNS != null){
|
||||||
printLog("NS in connected USB devices found", EMsgType.PASS);
|
logPrinter.print("NS in connected USB devices found", EMsgType.PASS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("NS in connected USB devices not found", EMsgType.FAIL);
|
logPrinter.print("NS in connected USB devices not found", EMsgType.FAIL);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -154,27 +141,16 @@ public class UsbCommunications extends Task<Void> {
|
||||||
handlerNS = new DeviceHandle();
|
handlerNS = new DeviceHandle();
|
||||||
result = LibUsb.open(deviceNS, handlerNS);
|
result = LibUsb.open(deviceNS, handlerNS);
|
||||||
if (result != LibUsb.SUCCESS) {
|
if (result != LibUsb.SUCCESS) {
|
||||||
switch (result){
|
logPrinter.print("Open NS USB device\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
case LibUsb.ERROR_ACCESS:
|
if (result == LibUsb.ERROR_ACCESS)
|
||||||
printLog("Open NS USB device\n Returned: ERROR_ACCESS", EMsgType.FAIL);
|
logPrinter.print("Double check that you have administrator privileges (you're 'root') or check 'udev' rules set for this user (linux only)!", EMsgType.INFO);
|
||||||
printLog("Double check that you have administrator privileges (you're 'root') or check 'udev' rules set for this user (linux only)!", EMsgType.INFO);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_MEM:
|
|
||||||
printLog("Open NS USB device\n Returned: ERROR_NO_MEM", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Open NS USB device\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Open NS USB device\n Returned:" + result, EMsgType.FAIL);
|
|
||||||
}
|
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printLog("Open NS USB device", EMsgType.PASS);
|
logPrinter.print("Open NS USB device", EMsgType.PASS);
|
||||||
|
|
||||||
printLog("Free device list", EMsgType.INFO);
|
logPrinter.print("Free device list", EMsgType.INFO);
|
||||||
LibUsb.freeDeviceList(deviceList, true);
|
LibUsb.freeDeviceList(deviceList, true);
|
||||||
|
|
||||||
// DO some stuff to connected NS
|
// DO some stuff to connected NS
|
||||||
|
@ -182,90 +158,55 @@ public class UsbCommunications extends Task<Void> {
|
||||||
boolean canDetach = LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER); // if cant, it's windows ot old lib
|
boolean canDetach = LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER); // if cant, it's windows ot old lib
|
||||||
if (canDetach){
|
if (canDetach){
|
||||||
int usedByKernel = LibUsb.kernelDriverActive(handlerNS, DEFAULT_INTERFACE);
|
int usedByKernel = LibUsb.kernelDriverActive(handlerNS, DEFAULT_INTERFACE);
|
||||||
if (usedByKernel == LibUsb.SUCCESS){
|
if (usedByKernel == LibUsb.SUCCESS){
|
||||||
printLog("Can proceed with libusb driver", EMsgType.PASS); // we're good
|
logPrinter.print("Can proceed with libusb driver", EMsgType.PASS); // we're good
|
||||||
}
|
}
|
||||||
else {
|
else if (usedByKernel == 1) { // used by kernel
|
||||||
switch (usedByKernel){
|
result = LibUsb.detachKernelDriver(handlerNS, DEFAULT_INTERFACE);
|
||||||
case 1: // used by kernel
|
logPrinter.print("Detach kernel required", EMsgType.INFO);
|
||||||
result = LibUsb.detachKernelDriver(handlerNS, DEFAULT_INTERFACE);
|
if (result != 0) {
|
||||||
printLog("Detach kernel required", EMsgType.INFO);
|
logPrinter.print("Detach kernel\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
if (result != 0) {
|
close();
|
||||||
switch (result){
|
return null;
|
||||||
case LibUsb.ERROR_NOT_FOUND:
|
} else
|
||||||
printLog("Detach kernel\n Returned: ERROR_NOT_FOUND", EMsgType.FAIL);
|
logPrinter.print("Detach kernel", EMsgType.PASS);
|
||||||
break;
|
}
|
||||||
case LibUsb.ERROR_INVALID_PARAM:
|
else
|
||||||
printLog("Detach kernel\n Returned: ERROR_INVALID_PARAM", EMsgType.FAIL);
|
logPrinter.print("Can't proceed with libusb driver\n Returned: "+UsbErrorCodes.getErrCode(usedByKernel), EMsgType.FAIL);
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Detach kernel\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NOT_SUPPORTED: // Should never appear only if libusb buggy
|
|
||||||
printLog("Detach kernel\n Returned: ERROR_NOT_SUPPORTED", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Detach kernel\n Returned: " + result, EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
close();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printLog("Detach kernel", EMsgType.PASS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Can't proceed with libusb driver\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NOT_SUPPORTED:
|
|
||||||
printLog("Can't proceed with libusb driver\n Returned: ERROR_NOT_SUPPORTED", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Can't proceed with libusb driver\n Returned: "+result, EMsgType.FAIL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printLog("libusb doesn't supports function 'CAP_SUPPORTS_DETACH_KERNEL_DRIVER'. Proceeding.", EMsgType.WARNING);
|
logPrinter.print("libusb doesn't support function 'CAP_SUPPORTS_DETACH_KERNEL_DRIVER'. It's normal. Proceeding.", EMsgType.WARNING);
|
||||||
|
/*
|
||||||
|
// Reset device
|
||||||
|
result = LibUsb.resetDevice(handlerNS);
|
||||||
|
if (result == 0)
|
||||||
|
logPrinter.print("Reset device", EMsgType.PASS);
|
||||||
|
else {
|
||||||
|
logPrinter.print("Reset device returned: " + result, EMsgType.FAIL);
|
||||||
|
updateAndClose();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
*/
|
||||||
// Set configuration (soft reset if needed)
|
// Set configuration (soft reset if needed)
|
||||||
result = LibUsb.setConfiguration(handlerNS, 1); // 1 - configuration all we need
|
result = LibUsb.setConfiguration(handlerNS, 1); // 1 - configuration all we need
|
||||||
if (result != LibUsb.SUCCESS){
|
if (result != LibUsb.SUCCESS){
|
||||||
switch (result){
|
logPrinter.print("Set active configuration to device\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
case LibUsb.ERROR_NOT_FOUND:
|
|
||||||
printLog("Set active configuration to device\n Returned: ERROR_NOT_FOUND", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_BUSY:
|
|
||||||
printLog("Set active configuration to device\n Returned: ERROR_BUSY", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Set active configuration to device\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_INVALID_PARAM:
|
|
||||||
printLog("Set active configuration to device\n Returned: ERROR_INVALID_PARAM", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Set active configuration to device\n Returned: "+result, EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("Set active configuration to device.", EMsgType.PASS);
|
logPrinter.print("Set active configuration to device.", EMsgType.PASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Claim interface
|
// Claim interface
|
||||||
result = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE);
|
result = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE);
|
||||||
if (result != LibUsb.SUCCESS) {
|
if (result != LibUsb.SUCCESS) {
|
||||||
printLog("Claim interface\n Returned: "+result, EMsgType.FAIL);
|
logPrinter.print("Claim interface\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
close();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printLog("Claim interface", EMsgType.PASS);
|
logPrinter.print("Claim interface", EMsgType.PASS);
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------
|
||||||
if (protocol.equals("TinFoil")) {
|
if (protocol.equals("TinFoil")) {
|
||||||
|
@ -275,7 +216,6 @@ public class UsbCommunications extends Task<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
printLog("\tEnd chain", EMsgType.INFO);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -297,11 +237,11 @@ public class UsbCommunications extends Task<Void> {
|
||||||
// Send list of NSP files:
|
// Send list of NSP files:
|
||||||
// Proceed "TUL0"
|
// Proceed "TUL0"
|
||||||
if (!writeToUsb("TUL0".getBytes(StandardCharsets.US_ASCII))) { // new byte[]{(byte) 0x54, (byte) 0x55, (byte) 0x76, (byte) 0x30}
|
if (!writeToUsb("TUL0".getBytes(StandardCharsets.US_ASCII))) { // new byte[]{(byte) 0x54, (byte) 0x55, (byte) 0x76, (byte) 0x30}
|
||||||
printLog("TF Send list of files: handshake", EMsgType.FAIL);
|
logPrinter.print("TF Send list of files: handshake", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printLog("TF Send list of files: handshake", EMsgType.PASS);
|
logPrinter.print("TF Send list of files: handshake", EMsgType.PASS);
|
||||||
//Collect file names
|
//Collect file names
|
||||||
StringBuilder nspListNamesBuilder = new StringBuilder(); // Add every title to one stringBuilder
|
StringBuilder nspListNamesBuilder = new StringBuilder(); // Add every title to one stringBuilder
|
||||||
for(String nspFileName: nspMap.keySet()) {
|
for(String nspFileName: nspMap.keySet()) {
|
||||||
|
@ -316,24 +256,24 @@ public class UsbCommunications extends Task<Void> {
|
||||||
//byteBuffer.reset();
|
//byteBuffer.reset();
|
||||||
|
|
||||||
// Sending NSP list
|
// Sending NSP list
|
||||||
printLog("TF Send list of files", EMsgType.INFO);
|
logPrinter.print("TF Send list of files", EMsgType.INFO);
|
||||||
if (!writeToUsb(nspListSize)) { // size of the list we're going to transfer goes...
|
if (!writeToUsb(nspListSize)) { // size of the list we're going to transfer goes...
|
||||||
printLog(" [send list length]", EMsgType.FAIL);
|
logPrinter.print(" [send list length]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [send list length]", EMsgType.PASS);
|
logPrinter.print(" [send list length]", EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(new byte[8])) { // 8 zero bytes goes...
|
if (!writeToUsb(new byte[8])) { // 8 zero bytes goes...
|
||||||
printLog(" [send padding]", EMsgType.FAIL);
|
logPrinter.print(" [send padding]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [send padding]", EMsgType.PASS);
|
logPrinter.print(" [send padding]", EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(nspListNames)) { // list of the names goes...
|
if (!writeToUsb(nspListNames)) { // list of the names goes...
|
||||||
printLog(" [send list itself]", EMsgType.FAIL);
|
logPrinter.print(" [send list itself]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [send list itself]", EMsgType.PASS);
|
logPrinter.print(" [send list itself]", EMsgType.PASS);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +281,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
* After we sent commands to NS, this chain starts
|
* After we sent commands to NS, this chain starts
|
||||||
* */
|
* */
|
||||||
private boolean proceedCommands(){
|
private boolean proceedCommands(){
|
||||||
printLog("TF Awaiting for NS commands.", EMsgType.INFO);
|
logPrinter.print("TF Awaiting for NS commands.", EMsgType.INFO);
|
||||||
|
|
||||||
/* byte[] magic = new byte[4];
|
/* byte[] magic = new byte[4];
|
||||||
ByteBuffer bb = StandardCharsets.UTF_8.encode("TUC0").rewind().get(magic);
|
ByteBuffer bb = StandardCharsets.UTF_8.encode("TUC0").rewind().get(magic);
|
||||||
|
@ -363,11 +303,11 @@ public class UsbCommunications extends Task<Void> {
|
||||||
// 8th to 12th(explicits) bytes in returned data stands for command ID as unsigned integer (Little-endian). Actually, we have to compare arrays here, but in real world it can't be greater then 0/1/2, thus:
|
// 8th to 12th(explicits) bytes in returned data stands for command ID as unsigned integer (Little-endian). Actually, we have to compare arrays here, but in real world it can't be greater then 0/1/2, thus:
|
||||||
// BTW also protocol specifies 4th byte to be 0x00 kinda indicating that that this command is valid. But, as you may see, never happens other situation when it's not = 0.
|
// BTW also protocol specifies 4th byte to be 0x00 kinda indicating that that this command is valid. But, as you may see, never happens other situation when it's not = 0.
|
||||||
if (receivedArray[8] == 0x00){ //0x00 - exit
|
if (receivedArray[8] == 0x00){ //0x00 - exit
|
||||||
printLog("TF Received EXIT command. Terminating.", EMsgType.PASS);
|
logPrinter.print("TF Received EXIT command. Terminating.", EMsgType.PASS);
|
||||||
return true; // All interaction with USB device should be ended (expected);
|
return true; // All interaction with USB device should be ended (expected);
|
||||||
}
|
}
|
||||||
else if ((receivedArray[8] == 0x01) || (receivedArray[8] == 0x02)){ //0x01 - file range; 0x02 unknown bug on backend side (dirty hack).
|
else if ((receivedArray[8] == 0x01) || (receivedArray[8] == 0x02)){ //0x01 - file range; 0x02 unknown bug on backend side (dirty hack).
|
||||||
printLog("TF Received FILE_RANGE command. Proceeding: [0x0"+receivedArray[8]+"]", EMsgType.PASS);
|
logPrinter.print("TF Received FILE_RANGE command. Proceeding: [0x0"+receivedArray[8]+"]", EMsgType.PASS);
|
||||||
/*// We can get in this pocket a length of file name (+32). Why +32? I dunno man.. Do we need this? Definitely not. This app can live without it.
|
/*// We can get in this pocket a length of file name (+32). Why +32? I dunno man.. Do we need this? Definitely not. This app can live without it.
|
||||||
long receivedSize = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 12,20)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
long receivedSize = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 12,20)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||||
logsArea.appendText("[V] Received FILE_RANGE command. Size: "+Long.toUnsignedString(receivedSize)+"\n"); // this shit returns string that will be chosen next '+32'. And, BTW, can't be greater then 512
|
logsArea.appendText("[V] Received FILE_RANGE command. Size: "+Long.toUnsignedString(receivedSize)+"\n"); // this shit returns string that will be chosen next '+32'. And, BTW, can't be greater then 512
|
||||||
|
@ -407,7 +347,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
String receivedRequestedNSP = new String(receivedArray, StandardCharsets.UTF_8);
|
String receivedRequestedNSP = new String(receivedArray, StandardCharsets.UTF_8);
|
||||||
printLog("TF Reply to requested file: "+receivedRequestedNSP
|
logPrinter.print("TF Reply to requested file: "+receivedRequestedNSP
|
||||||
+"\n Range Size: "+receivedRangeSize
|
+"\n Range Size: "+receivedRangeSize
|
||||||
+"\n Range Offset: "+receivedRangeOffset, EMsgType.INFO);
|
+"\n Range Offset: "+receivedRangeOffset, EMsgType.INFO);
|
||||||
|
|
||||||
|
@ -421,7 +361,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
byte[] bufferCurrent ;//= new byte[1048576]; // eq. Allocate 1mb
|
byte[] bufferCurrent ;//= new byte[1048576]; // eq. Allocate 1mb
|
||||||
int bufferLength;
|
int bufferLength;
|
||||||
if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset){
|
if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset){
|
||||||
printLog("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,11 +379,11 @@ public class UsbCommunications extends Task<Void> {
|
||||||
if (isProgessBarInitiated){
|
if (isProgessBarInitiated){
|
||||||
try {
|
try {
|
||||||
if (currentOffset+readPice == receivedRangeOffset){
|
if (currentOffset+readPice == receivedRangeOffset){
|
||||||
progressQueue.put(1.0);
|
logPrinter.updateProgress(1.0);
|
||||||
isProgessBarInitiated = false;
|
isProgessBarInitiated = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
progressQueue.put((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0);
|
logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0);
|
||||||
}catch (InterruptedException ie){
|
}catch (InterruptedException ie){
|
||||||
getException().printStackTrace(); // TODO: Do something with this
|
getException().printStackTrace(); // TODO: Do something with this
|
||||||
}
|
}
|
||||||
|
@ -461,28 +401,28 @@ public class UsbCommunications extends Task<Void> {
|
||||||
if (bufferLength != -1){
|
if (bufferLength != -1){
|
||||||
//write to USB
|
//write to USB
|
||||||
if (!writeToUsb(bufferCurrent)) {
|
if (!writeToUsb(bufferCurrent)) {
|
||||||
printLog("TF Failure during NSP transmission.", EMsgType.FAIL);
|
logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
currentOffset += readPice;
|
currentOffset += readPice;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printLog("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
bufferedInStream.close();
|
bufferedInStream.close();
|
||||||
} catch (FileNotFoundException fnfe){
|
} catch (FileNotFoundException fnfe){
|
||||||
printLog("TF FileNotFoundException:\n "+fnfe.getMessage(), EMsgType.FAIL);
|
logPrinter.print("TF FileNotFoundException:\n "+fnfe.getMessage(), EMsgType.FAIL);
|
||||||
fnfe.printStackTrace();
|
fnfe.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
} catch (IOException ioe){
|
} catch (IOException ioe){
|
||||||
printLog("TF IOException:\n "+ioe.getMessage(), EMsgType.FAIL);
|
logPrinter.print("TF IOException:\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||||
ioe.printStackTrace();
|
ioe.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
} catch (ArithmeticException ae){
|
} catch (ArithmeticException ae){
|
||||||
printLog("TF ArithmeticException (can't cast end offset minus current to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL);
|
logPrinter.print("TF ArithmeticException (can't cast end offset minus current to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL);
|
||||||
ae.printStackTrace();
|
ae.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -495,26 +435,26 @@ public class UsbCommunications extends Task<Void> {
|
||||||
* false if failed
|
* false if failed
|
||||||
* */
|
* */
|
||||||
private boolean sendResponse(byte[] rangeSize){ // This method as separate function itself for application needed as a cookie in the middle of desert.
|
private boolean sendResponse(byte[] rangeSize){ // This method as separate function itself for application needed as a cookie in the middle of desert.
|
||||||
printLog("TF Sending response", EMsgType.INFO);
|
logPrinter.print("TF Sending response", EMsgType.INFO);
|
||||||
if (!writeToUsb(new byte[] { (byte) 0x54, (byte) 0x55, (byte) 0x43, (byte) 0x30, // 'TUC0'
|
if (!writeToUsb(new byte[] { (byte) 0x54, (byte) 0x55, (byte) 0x43, (byte) 0x30, // 'TUC0'
|
||||||
(byte) 0x01, // CMD_TYPE_RESPONSE = 1
|
(byte) 0x01, // CMD_TYPE_RESPONSE = 1
|
||||||
(byte) 0x00, (byte) 0x00, (byte) 0x00, // kinda padding. Guys, didn't you want to use integer value for CMD semantic?
|
(byte) 0x00, (byte) 0x00, (byte) 0x00, // kinda padding. Guys, didn't you want to use integer value for CMD semantic?
|
||||||
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00} ) // Send integer value of '1' in Little-endian format.
|
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00} ) // Send integer value of '1' in Little-endian format.
|
||||||
){
|
){
|
||||||
printLog(" [1/3]", EMsgType.FAIL);
|
logPrinter.print(" [1/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [1/3]", EMsgType.PASS);
|
logPrinter.print(" [1/3]", EMsgType.PASS);
|
||||||
if(!writeToUsb(rangeSize)) { // Send EXACTLY what has been received
|
if(!writeToUsb(rangeSize)) { // Send EXACTLY what has been received
|
||||||
printLog(" [2/3]", EMsgType.FAIL);
|
logPrinter.print(" [2/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [2/3]", EMsgType.PASS);
|
logPrinter.print(" [2/3]", EMsgType.PASS);
|
||||||
if(!writeToUsb(new byte[12])) { // kinda another one padding
|
if(!writeToUsb(new byte[12])) { // kinda another one padding
|
||||||
printLog(" [3/3]", EMsgType.FAIL);
|
logPrinter.print(" [3/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [3/3]", EMsgType.PASS);
|
logPrinter.print(" [3/3]", EMsgType.PASS);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,14 +475,14 @@ public class UsbCommunications extends Task<Void> {
|
||||||
private final byte[] CMD_Finish = new byte[]{0x47, 0x4c, 0x55, 0x43, 0x07, 0x00, 0x00, 0x00};
|
private final byte[] CMD_Finish = new byte[]{0x47, 0x4c, 0x55, 0x43, 0x07, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
GoldLeaf(){
|
GoldLeaf(){
|
||||||
printLog("===========================================================================", EMsgType.INFO);
|
logPrinter.print("===========================================================================", EMsgType.INFO);
|
||||||
PFSProvider pfsElement = new PFSProvider(nspMap.get(nspMap.keySet().toArray()[0]), msgQueue);
|
PFSProvider pfsElement = new PFSProvider(nspMap.get(nspMap.keySet().toArray()[0]), logPrinter);
|
||||||
if (!pfsElement.init()) {
|
if (!pfsElement.init()) {
|
||||||
printLog("GL File provided have incorrect structure and won't be uploaded", EMsgType.FAIL);
|
logPrinter.print("GL File provided have incorrect structure and won't be uploaded", EMsgType.FAIL);
|
||||||
status = EFileStatus.INCORRECT_FILE_FAILED;
|
status = EFileStatus.INCORRECT_FILE_FAILED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printLog("GL File structure validated and it will be uploaded", EMsgType.PASS);
|
logPrinter.print("GL File structure validated and it will be uploaded", EMsgType.PASS);
|
||||||
|
|
||||||
if (initGoldLeafProtocol(pfsElement))
|
if (initGoldLeafProtocol(pfsElement))
|
||||||
status = EFileStatus.UPLOADED; // else - no change status that is already set to FAILED
|
status = EFileStatus.UPLOADED; // else - no change status that is already set to FAILED
|
||||||
|
@ -553,9 +493,9 @@ public class UsbCommunications extends Task<Void> {
|
||||||
|
|
||||||
// Go connect to GoldLeaf
|
// Go connect to GoldLeaf
|
||||||
if (writeToUsb(CMD_ConnectionRequest))
|
if (writeToUsb(CMD_ConnectionRequest))
|
||||||
printLog("GL Initiating GoldLeaf connection", EMsgType.PASS);
|
logPrinter.print("GL Initiating GoldLeaf connection", EMsgType.PASS);
|
||||||
else {
|
else {
|
||||||
printLog("GL Initiating GoldLeaf connection", EMsgType.FAIL);
|
logPrinter.print("GL Initiating GoldLeaf connection", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -588,7 +528,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Arrays.equals(readByte, CMD_Finish)) {
|
if (Arrays.equals(readByte, CMD_Finish)) {
|
||||||
printLog("GL Closing GoldLeaf connection: Transfer successful.", EMsgType.PASS);
|
logPrinter.print("GL Closing GoldLeaf connection: Transfer successful.", EMsgType.PASS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -598,24 +538,24 @@ public class UsbCommunications extends Task<Void> {
|
||||||
* ConnectionResponse command handler
|
* ConnectionResponse command handler
|
||||||
* */
|
* */
|
||||||
private boolean handleConnectionResponse(PFSProvider pfsElement){
|
private boolean handleConnectionResponse(PFSProvider pfsElement){
|
||||||
printLog("GL 'ConnectionResonse' command:", EMsgType.INFO);
|
logPrinter.print("GL 'ConnectionResponse' command:", EMsgType.INFO);
|
||||||
if (!writeToUsb(CMD_NSPName)) {
|
if (!writeToUsb(CMD_NSPName)) {
|
||||||
printLog(" [1/3]", EMsgType.FAIL);
|
logPrinter.print(" [1/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [1/3]", EMsgType.PASS);
|
logPrinter.print(" [1/3]", EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(pfsElement.getBytesNspFileNameLength())) {
|
if (!writeToUsb(pfsElement.getBytesNspFileNameLength())) {
|
||||||
printLog(" [2/3]", EMsgType.FAIL);
|
logPrinter.print(" [2/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [2/3]", EMsgType.PASS);
|
logPrinter.print(" [2/3]", EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(pfsElement.getBytesNspFileName())) {
|
if (!writeToUsb(pfsElement.getBytesNspFileName())) {
|
||||||
printLog(" [3/3]", EMsgType.FAIL);
|
logPrinter.print(" [3/3]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [3/3]", EMsgType.PASS);
|
logPrinter.print(" [3/3]", EMsgType.PASS);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -623,43 +563,43 @@ public class UsbCommunications extends Task<Void> {
|
||||||
* Start command handler
|
* Start command handler
|
||||||
* */
|
* */
|
||||||
private boolean handleStart(PFSProvider pfsElement){
|
private boolean handleStart(PFSProvider pfsElement){
|
||||||
printLog("GL Handle 'Start' command:", EMsgType.INFO);
|
logPrinter.print("GL Handle 'Start' command:", EMsgType.INFO);
|
||||||
if (!writeToUsb(CMD_NSPData)) {
|
if (!writeToUsb(CMD_NSPData)) {
|
||||||
printLog(" [Send command]", EMsgType.FAIL);
|
logPrinter.print(" [Send command]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [Send command]", EMsgType.PASS);
|
logPrinter.print(" [Send command]", EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(pfsElement.getBytesCountOfNca())) {
|
if (!writeToUsb(pfsElement.getBytesCountOfNca())) {
|
||||||
printLog(" [Send length]", EMsgType.FAIL);
|
logPrinter.print(" [Send length]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [Send length]", EMsgType.PASS);
|
logPrinter.print(" [Send length]", EMsgType.PASS);
|
||||||
|
|
||||||
int ncaCount = pfsElement.getIntCountOfNca();
|
int ncaCount = pfsElement.getIntCountOfNca();
|
||||||
printLog(" [Send information for "+ncaCount+" files]", EMsgType.INFO);
|
logPrinter.print(" [Send information for "+ncaCount+" files]", EMsgType.INFO);
|
||||||
for (int i = 0; i < ncaCount; i++){
|
for (int i = 0; i < ncaCount; i++){
|
||||||
if (!writeToUsb(pfsElement.getNca(i).getNcaFileNameLength())) {
|
if (!writeToUsb(pfsElement.getNca(i).getNcaFileNameLength())) {
|
||||||
printLog(" [1/4] File #"+i, EMsgType.FAIL);
|
logPrinter.print(" [1/4] File #"+i, EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [1/4] File #"+i, EMsgType.PASS);
|
logPrinter.print(" [1/4] File #"+i, EMsgType.PASS);
|
||||||
|
|
||||||
if (!writeToUsb(pfsElement.getNca(i).getNcaFileName())) {
|
if (!writeToUsb(pfsElement.getNca(i).getNcaFileName())) {
|
||||||
printLog(" [2/4] File #"+i, EMsgType.FAIL);
|
logPrinter.print(" [2/4] File #"+i, EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [2/4] File #"+i, EMsgType.PASS);
|
logPrinter.print(" [2/4] File #"+i, EMsgType.PASS);
|
||||||
if (!writeToUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getBodySize()+pfsElement.getNca(i).getNcaOffset()).array())) { // offset. real.
|
if (!writeToUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getBodySize()+pfsElement.getNca(i).getNcaOffset()).array())) { // offset. real.
|
||||||
printLog(" [2/4] File #"+i, EMsgType.FAIL);
|
logPrinter.print(" [2/4] File #"+i, EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [3/4] File #"+i, EMsgType.PASS);
|
logPrinter.print(" [3/4] File #"+i, EMsgType.PASS);
|
||||||
if (!writeToUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getNca(i).getNcaSize()).array())) { // size
|
if (!writeToUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getNca(i).getNcaSize()).array())) { // size
|
||||||
printLog(" [4/4] File #"+i, EMsgType.FAIL);
|
logPrinter.print(" [4/4] File #"+i, EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog(" [4/4] File #"+i, EMsgType.PASS);
|
logPrinter.print(" [4/4] File #"+i, EMsgType.PASS);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -672,18 +612,18 @@ public class UsbCommunications extends Task<Void> {
|
||||||
int requestedNcaID;
|
int requestedNcaID;
|
||||||
boolean isProgessBarInitiated = false;
|
boolean isProgessBarInitiated = false;
|
||||||
if (isItRawRequest) {
|
if (isItRawRequest) {
|
||||||
printLog("GL Handle 'Content' command", EMsgType.INFO);
|
logPrinter.print("GL Handle 'Content' command", EMsgType.INFO);
|
||||||
byte[] readByte = readFromUsb();
|
byte[] readByte = readFromUsb();
|
||||||
if (readByte == null || readByte.length != 4) {
|
if (readByte == null || readByte.length != 4) {
|
||||||
printLog(" [Read requested ID]", EMsgType.FAIL);
|
logPrinter.print(" [Read requested ID]", EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
requestedNcaID = ByteBuffer.wrap(readByte).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
requestedNcaID = ByteBuffer.wrap(readByte).order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||||
printLog(" [Read requested ID = "+requestedNcaID+" ]", EMsgType.PASS);
|
logPrinter.print(" [Read requested ID = "+requestedNcaID+" ]", EMsgType.PASS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
requestedNcaID = pfsElement.getNcaTicketID();
|
requestedNcaID = pfsElement.getNcaTicketID();
|
||||||
printLog("GL Handle 'Ticket' command (ID = "+requestedNcaID+" )", EMsgType.INFO);
|
logPrinter.print("GL Handle 'Ticket' command (ID = "+requestedNcaID+" )", EMsgType.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
long realNcaOffset = pfsElement.getNca(requestedNcaID).getNcaOffset()+pfsElement.getBodySize();
|
long realNcaOffset = pfsElement.getNca(requestedNcaID).getNcaOffset()+pfsElement.getBodySize();
|
||||||
|
@ -716,11 +656,11 @@ public class UsbCommunications extends Task<Void> {
|
||||||
if (isProgessBarInitiated){
|
if (isProgessBarInitiated){
|
||||||
try {
|
try {
|
||||||
if (readFrom+readPice == realNcaSize){
|
if (readFrom+readPice == realNcaSize){
|
||||||
progressQueue.put(1.0);
|
logPrinter.updateProgress(1.0);
|
||||||
isProgessBarInitiated = false;
|
isProgessBarInitiated = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
progressQueue.put((readFrom+readPice)/(realNcaSize/100.0) / 100.0);
|
logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0);
|
||||||
}catch (InterruptedException ie){
|
}catch (InterruptedException ie){
|
||||||
getException().printStackTrace(); // TODO: Do something with this
|
getException().printStackTrace(); // TODO: Do something with this
|
||||||
}
|
}
|
||||||
|
@ -735,7 +675,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
bufferedInStream.close();
|
bufferedInStream.close();
|
||||||
}
|
}
|
||||||
catch (IOException ioe){
|
catch (IOException ioe){
|
||||||
printLog(" Failed to read NCA ID "+requestedNcaID+". IO Exception:\n "+ioe.getMessage(), EMsgType.FAIL);
|
logPrinter.print(" Failed to read NCA ID "+requestedNcaID+". IO Exception:\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||||
ioe.printStackTrace();
|
ioe.printStackTrace();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -747,30 +687,29 @@ public class UsbCommunications extends Task<Void> {
|
||||||
* Correct exit
|
* Correct exit
|
||||||
* */
|
* */
|
||||||
private void close(){
|
private void close(){
|
||||||
// close handler in the end
|
// Close handler in the end
|
||||||
if (handlerNS != null) {
|
if (handlerNS != null) {
|
||||||
// Try to release interface
|
// Try to release interface
|
||||||
int result = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE);
|
int result = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE);
|
||||||
|
|
||||||
if (result != LibUsb.SUCCESS)
|
if (result != LibUsb.SUCCESS)
|
||||||
printLog("Release interface\n Returned: "+result+" (sometimes it's not an issue)", EMsgType.WARNING);
|
logPrinter.print("Release interface\n Returned: "+result+" (sometimes it's not an issue)", EMsgType.WARNING);
|
||||||
else
|
else
|
||||||
printLog("Release interface", EMsgType.PASS);
|
logPrinter.print("Release interface", EMsgType.PASS);
|
||||||
|
|
||||||
LibUsb.close(handlerNS);
|
LibUsb.close(handlerNS);
|
||||||
printLog("Requested handler close", EMsgType.INFO);
|
logPrinter.print("Requested handler updateAndClose", EMsgType.INFO);
|
||||||
}
|
}
|
||||||
// close context in the end
|
// Close context in the end
|
||||||
if (contextNS != null) {
|
if (contextNS != null) {
|
||||||
LibUsb.exit(contextNS);
|
LibUsb.exit(contextNS);
|
||||||
printLog("Requested context close", EMsgType.INFO);
|
logPrinter.print("Requested context updateAndClose", EMsgType.INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report status
|
// Report status and close
|
||||||
for (String fileName: nspMap.keySet())
|
logPrinter.update(nspMap, status);
|
||||||
statusMap.put(fileName, status);
|
logPrinter.print("\tEnd chain", EMsgType.INFO);
|
||||||
|
logPrinter.close();
|
||||||
msgConsumer.interrupt();
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sending any byte array to USB device
|
* Sending any byte array to USB device
|
||||||
|
@ -785,27 +724,12 @@ public class UsbCommunications extends Task<Void> {
|
||||||
int result;
|
int result;
|
||||||
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 0); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01
|
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 0); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01
|
||||||
if (result != LibUsb.SUCCESS){
|
if (result != LibUsb.SUCCESS){
|
||||||
switch (result){
|
logPrinter.print("Data transfer (write) issue\n Returned: "+ UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
case LibUsb.ERROR_TIMEOUT:
|
logPrinter.print("Execution stopped", EMsgType.FAIL);
|
||||||
printLog("Data transfer (write) issue\n Returned: ERROR_TIMEOUT", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_PIPE: //WUT?? I dunno man looks overkill in here..
|
|
||||||
printLog("Data transfer (write) issue\n Returned: ERROR_PIPE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_OVERFLOW:
|
|
||||||
printLog("Data transfer (write) issue\n Returned: ERROR_OVERFLOW", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Data transfer (write) issue\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Data transfer (write) issue\n Returned: "+result, EMsgType.FAIL);
|
|
||||||
}
|
|
||||||
printLog("Execution stopped", EMsgType.FAIL);
|
|
||||||
return false;
|
return false;
|
||||||
}else {
|
}else {
|
||||||
if (writeBufTransferred.get() != message.length){
|
if (writeBufTransferred.get() != message.length){
|
||||||
printLog("Data transfer (write) issue\n Requested: "+message.length+"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
|
logPrinter.print("Data transfer (write) issue\n Requested: "+message.length+"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -827,26 +751,8 @@ public class UsbCommunications extends Task<Void> {
|
||||||
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 0); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
|
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 0); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
|
||||||
|
|
||||||
if (result != LibUsb.SUCCESS){
|
if (result != LibUsb.SUCCESS){
|
||||||
switch (result){
|
logPrinter.print("Data transfer (read) issue\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
case LibUsb.ERROR_TIMEOUT:
|
logPrinter.print("Execution stopped", EMsgType.FAIL);
|
||||||
printLog("Data transfer (read) issue\n Returned: ERROR_TIMEOUT", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_PIPE: //WUT?? I dunno man looks overkill in here..
|
|
||||||
printLog("Data transfer (read) issue\n Returned: ERROR_PIPE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_OVERFLOW:
|
|
||||||
printLog("Data transfer (read) issue\n Returned: ERROR_OVERFLOW", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_NO_DEVICE:
|
|
||||||
printLog("Data transfer (read) issue\n Returned: ERROR_NO_DEVICE", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_IO:
|
|
||||||
printLog("Data transfer (read) issue\n Returned: ERROR_IO", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printLog("Data transfer (read) issue\n Returned: "+result, EMsgType.FAIL);
|
|
||||||
}
|
|
||||||
printLog("Execution stopped", EMsgType.FAIL);
|
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
int trans = readBufTransferred.get();
|
int trans = readBufTransferred.get();
|
||||||
|
@ -858,30 +764,4 @@ public class UsbCommunications extends Task<Void> {
|
||||||
return receivedBytes;
|
return receivedBytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is what will print to textArea of the application.
|
|
||||||
* */
|
|
||||||
private void printLog(String message, EMsgType type){
|
|
||||||
try {
|
|
||||||
switch (type){
|
|
||||||
case PASS:
|
|
||||||
msgQueue.put("[ PASS ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
msgQueue.put("[ FAIL ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case INFO:
|
|
||||||
msgQueue.put("[ INFO ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
case WARNING:
|
|
||||||
msgQueue.put("[ WARN ] "+message+"\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
msgQueue.put(message);
|
|
||||||
}
|
|
||||||
}catch (InterruptedException ie){
|
|
||||||
ie.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
38
src/main/java/nsusbloader/USB/UsbErrorCodes.java
Normal file
38
src/main/java/nsusbloader/USB/UsbErrorCodes.java
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package nsusbloader.USB;
|
||||||
|
|
||||||
|
import org.usb4java.LibUsb;
|
||||||
|
|
||||||
|
class UsbErrorCodes {
|
||||||
|
static String getErrCode(int value){
|
||||||
|
switch (value){
|
||||||
|
case LibUsb.ERROR_ACCESS:
|
||||||
|
return "ERROR_ACCESS";
|
||||||
|
case LibUsb.ERROR_BUSY:
|
||||||
|
return "ERROR_BUSY";
|
||||||
|
case LibUsb.ERROR_INTERRUPTED:
|
||||||
|
return "ERROR_INTERRUPTED";
|
||||||
|
case LibUsb.ERROR_INVALID_PARAM:
|
||||||
|
return "ERROR_INVALID_PARAM";
|
||||||
|
case LibUsb.ERROR_IO:
|
||||||
|
return "ERROR_IO";
|
||||||
|
case LibUsb.ERROR_NO_DEVICE:
|
||||||
|
return "ERROR_NO_DEVICE";
|
||||||
|
case LibUsb.ERROR_NO_MEM:
|
||||||
|
return "ERROR_NO_MEM";
|
||||||
|
case LibUsb.ERROR_NOT_FOUND:
|
||||||
|
return "ERROR_NOT_FOUND";
|
||||||
|
case LibUsb.ERROR_NOT_SUPPORTED:
|
||||||
|
return "ERROR_NOT_SUPPORTED";
|
||||||
|
case LibUsb.ERROR_OTHER:
|
||||||
|
return "ERROR_OTHER";
|
||||||
|
case LibUsb.ERROR_OVERFLOW:
|
||||||
|
return "ERROR_OVERFLOW";
|
||||||
|
case LibUsb.ERROR_PIPE:
|
||||||
|
return "ERROR_PIPE";
|
||||||
|
case LibUsb.ERROR_TIMEOUT:
|
||||||
|
return "ERROR_TIMEOUT";
|
||||||
|
default:
|
||||||
|
return Integer.toString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,12 @@
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.ChoiceBox?>
|
<?import javafx.scene.control.ChoiceBox?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.ProgressBar?>
|
<?import javafx.scene.control.ProgressBar?>
|
||||||
<?import javafx.scene.control.Tab?>
|
<?import javafx.scene.control.Tab?>
|
||||||
<?import javafx.scene.control.TabPane?>
|
<?import javafx.scene.control.TabPane?>
|
||||||
<?import javafx.scene.control.TextArea?>
|
<?import javafx.scene.control.TextArea?>
|
||||||
|
<?import javafx.scene.control.TextField?>
|
||||||
<?import javafx.scene.control.ToolBar?>
|
<?import javafx.scene.control.ToolBar?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
<?import javafx.scene.layout.ColumnConstraints?>
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
@ -17,7 +19,7 @@
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.shape.SVGPath?>
|
<?import javafx.scene.shape.SVGPath?>
|
||||||
|
|
||||||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="nsusbloader.Controllers.NSLMainController">
|
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onDragDropped="#handleDrop" onDragOver="#handleDragOver" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
|
||||||
<children>
|
<children>
|
||||||
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
<children>
|
<children>
|
||||||
|
@ -30,6 +32,9 @@
|
||||||
<ToolBar>
|
<ToolBar>
|
||||||
<items>
|
<items>
|
||||||
<ChoiceBox fx:id="choiceProtocol" prefWidth="120.0" />
|
<ChoiceBox fx:id="choiceProtocol" prefWidth="120.0" />
|
||||||
|
<ChoiceBox fx:id="choiceNetUsb" prefWidth="75.0" />
|
||||||
|
<Label fx:id="nsIpLbl" text="%NSIPlable" visible="false" />
|
||||||
|
<TextField fx:id="nsIpTextField" prefWidth="135.0" promptText="XXX.XXX.XXX.XXX" visible="false" />
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<Pane HBox.hgrow="ALWAYS" />
|
||||||
<Button fx:id="switchThemeBtn" mnemonicParsing="false" />
|
<Button fx:id="switchThemeBtn" mnemonicParsing="false" />
|
||||||
</items>
|
</items>
|
||||||
|
@ -58,6 +63,14 @@
|
||||||
<SVGPath content="M21,19V17H8V19H21M21,13V11H8V13H21M8,7H21V5H8V7M4,5V7H6V5H4M3,5A1,1 0 0,1 4,4H6A1,1 0 0,1 7,5V7A1,1 0 0,1 6,8H4A1,1 0 0,1 3,7V5M4,11V13H6V11H4M3,11A1,1 0 0,1 4,10H6A1,1 0 0,1 7,11V13A1,1 0 0,1 6,14H4A1,1 0 0,1 3,13V11M4,17V19H6V17H4M3,17A1,1 0 0,1 4,16H6A1,1 0 0,1 7,17V19A1,1 0 0,1 6,20H4A1,1 0 0,1 3,19V17Z" />
|
<SVGPath content="M21,19V17H8V19H21M21,13V11H8V13H21M8,7H21V5H8V7M4,5V7H6V5H4M3,5A1,1 0 0,1 4,4H6A1,1 0 0,1 7,5V7A1,1 0 0,1 6,8H4A1,1 0 0,1 3,7V5M4,11V13H6V11H4M3,11A1,1 0 0,1 4,10H6A1,1 0 0,1 7,11V13A1,1 0 0,1 6,14H4A1,1 0 0,1 3,13V11M4,17V19H6V17H4M3,17A1,1 0 0,1 4,16H6A1,1 0 0,1 7,17V19A1,1 0 0,1 6,20H4A1,1 0 0,1 3,19V17Z" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
<Tab closable="false">
|
||||||
|
<content>
|
||||||
|
<fx:include fx:id="SettingsTab" source="SettingsTab.fxml" VBox.vgrow="ALWAYS" />
|
||||||
|
</content>
|
||||||
|
<graphic>
|
||||||
|
<SVGPath content="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" />
|
||||||
|
</graphic>
|
||||||
|
</Tab>
|
||||||
<Tab closable="false">
|
<Tab closable="false">
|
||||||
<content>
|
<content>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0">
|
<VBox prefHeight="200.0" prefWidth="100.0">
|
||||||
|
@ -71,7 +84,7 @@
|
||||||
</VBox>
|
</VBox>
|
||||||
</content>
|
</content>
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M19,3H14.82C14.4,1.84 13.3,1 12,1C10.7,1 9.6,1.84 9.18,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M12,3A1,1 0 0,1 13,4A1,1 0 0,1 12,5A1,1 0 0,1 11,4A1,1 0 0,1 12,3M7,7H17V5H19V19H5V5H7V7Z" />
|
<SVGPath content="M9,22A1,1 0 0,1 8,21V18H4A2,2 0 0,1 2,16V4C2,2.89 2.9,2 4,2H20A2,2 0 0,1 22,4V16A2,2 0 0,1 20,18H13.9L10.2,21.71C10,21.9 9.75,22 9.5,22V22H9M10,16V19.08L13.08,16H20V4H4V16H10M17,11H15V9H17V11M13,11H11V9H13V11M9,11H7V9H9V11Z" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Tab>
|
</Tab>
|
||||||
</tabs>
|
</tabs>
|
||||||
|
|
78
src/main/resources/SettingsTab.fxml
Normal file
78
src/main/resources/SettingsTab.fxml
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.CheckBox?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.control.Separator?>
|
||||||
|
<?import javafx.scene.control.TextField?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
|
||||||
|
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SettingsController">
|
||||||
|
<children>
|
||||||
|
<VBox spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<children>
|
||||||
|
<CheckBox fx:id="validateNSHostNameCb" mnemonicParsing="false" text="%netTabValidateNSHostNameCb">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox fx:id="expertModeCb" mnemonicParsing="false" text="%netTabExpertModeCb" />
|
||||||
|
<VBox fx:id="expertSettingsVBox" spacing="5.0">
|
||||||
|
<children>
|
||||||
|
<CheckBox fx:id="autoDetectIpCb" mnemonicParsing="false" text="%netTabAutoDetectIpCb">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox fx:id="randPortCb" mnemonicParsing="false" text="%netTabRandSelectPortCb">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
</CheckBox>
|
||||||
|
<HBox>
|
||||||
|
<children>
|
||||||
|
<Label text="%netTabHostIPLbl" />
|
||||||
|
<Label text=":" />
|
||||||
|
<Label text="%netTabHostPortLbl" />
|
||||||
|
<Label text="/" />
|
||||||
|
<Label text="%netTabHostExtraLbl" />
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
<HBox>
|
||||||
|
<children>
|
||||||
|
<TextField fx:id="pcIpTextField" promptText="XXX.XXX.XXX.XXX" />
|
||||||
|
<Label text=":" />
|
||||||
|
<TextField fx:id="pcPortTextField" promptText="0-65535" />
|
||||||
|
<Label text="/" />
|
||||||
|
<TextField fx:id="pcExtraTextField" HBox.hgrow="ALWAYS">
|
||||||
|
<HBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</HBox.margin>
|
||||||
|
</TextField>
|
||||||
|
</children>
|
||||||
|
</HBox>
|
||||||
|
<Separator prefWidth="200.0" />
|
||||||
|
<CheckBox fx:id="dontServeCb" mnemonicParsing="false" text="%netTabDontServeRequestsCb">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
</CheckBox>
|
||||||
|
<Label disable="true" text="%netTabDontServeRequestsDescription" wrapText="true">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets />
|
||||||
|
</VBox.margin>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
<padding>
|
||||||
|
<Insets left="10.0" />
|
||||||
|
</padding>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" top="5.0" />
|
||||||
|
</padding>
|
||||||
|
</VBox>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
|
@ -17,5 +17,21 @@ windowBodyConfirmWrongPFS0=Selected NSP file has incrrect starting symbols. Most
|
||||||
It's better to interrupt proccess now. Continue process anyway?
|
It's better to interrupt proccess now. Continue process anyway?
|
||||||
tableStatusLbl=Status
|
tableStatusLbl=Status
|
||||||
tableFileNameLbl=File name
|
tableFileNameLbl=File name
|
||||||
tableSizeLbl=Size (~Mb)
|
tableSizeLbl=Size
|
||||||
tableUploadLbl=Upload?
|
tableUploadLbl=Upload?
|
||||||
|
contextMenuBtnDelete=Remove
|
||||||
|
contextMenuBtnDeleteAll=Remove all
|
||||||
|
netTabHostIPLbl=Host IP
|
||||||
|
NSIPlable=NS IP:
|
||||||
|
netTabValidateNSHostNameCb=Always validate NS IP input.
|
||||||
|
windowBodyBadIp=Are you sure that you entered NS IP address correctly?
|
||||||
|
windowTitleBadIp=IP address of NS most likely incorrect
|
||||||
|
netTabExpertModeCb=Expert mode
|
||||||
|
netTabHostPortLbl=port
|
||||||
|
netTabAutoDetectIpCb=Auto-detect IP
|
||||||
|
netTabRandSelectPortCb=Randomly get port
|
||||||
|
netTabDontServeRequestsCb=Don't serve requests
|
||||||
|
netTabDontServeRequestsDescription=If selected, this computer won't reply to NSP files requests coming from NS (over the net) and use defined host settings to tell TinFoil where should it look for files.
|
||||||
|
netTabHostExtraLbl=extra
|
||||||
|
windowTitleErrorPort=Port set incorrectly!
|
||||||
|
windowBodyErrorPort=Port can't be 0 or greater than 65535.
|
37
src/main/resources/locale_fra.properties
Normal file
37
src/main/resources/locale_fra.properties
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
btnFileOpen=Selectionner les fichiers .NSP
|
||||||
|
btnUpload=Envoyer vers NS
|
||||||
|
logsEnteredAsMsg1=Vous etes connect\u00E9 en tant que:
|
||||||
|
logsEnteredAsMsg2=Vous devez \u00EAtre administrateur ou avoir configur\u00E9 les r\u00E8gles 'udev' pour cet utilisateur afin d'\u00E9viter tout probl\u00E8me.
|
||||||
|
logsFilesToUploadTitle=Fichiers a envoyer:
|
||||||
|
logsGreetingsMessage=Bienvenue sur NS-USBloader
|
||||||
|
logsNoFolderFileSelected=Aucuns fichiers s\u00E9lectionn\u00E9s: Rien a envoyer.
|
||||||
|
windowBodyConfirmExit=Le transfert de donn\u00E9es est en cours et la fermeture de cette application l\u2019interrompra.\nC\u2019est la pire chose que vous puissiez faire maintenant.\nInterrompre le processus et quitter ?
|
||||||
|
windowTitleConfirmExit=Non, ne faites pas \u00E7a!
|
||||||
|
btnStop=Interrompre
|
||||||
|
logsGreetingsMessage2=--\n\
|
||||||
|
Source: https://github.com/developersu/ns-usbloader/\n\
|
||||||
|
Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\
|
||||||
|
Dmitry Isaenko [developer.su]
|
||||||
|
windowTitleConfirmWrongPFS0=Type de fichier incorrect
|
||||||
|
windowBodyConfirmWrongPFS0=Le fichier NSP s\u00E9lectionn\u00E9 a des symboles de d\u00E9part incorect. Il est tr\u00E8s probablement corrompu.\nIl est pr\u00E9f\u00E9rable d'interrompre le processus maintenant. Continuer le processus ?
|
||||||
|
tableUploadLbl=Envoyer ?
|
||||||
|
tableSizeLbl=Taille
|
||||||
|
tableFileNameLbl=Nom de fichier
|
||||||
|
tableStatusLbl=Statut
|
||||||
|
contextMenuBtnDelete=Supprimer
|
||||||
|
contextMenuBtnDeleteAll=Supprimer tout
|
||||||
|
netTabHostIPLbl=IP de l'ordinateur
|
||||||
|
NSIPlable=IP de NS:
|
||||||
|
netTabValidateNSHostNameCb=Toujours v\u00E9rifier que l'adresse IP de NS entr\u00E9e est correcte
|
||||||
|
windowTitleBadIp=L'adresse IP de NS est probablement incorrecte
|
||||||
|
windowBodyBadIp=\u00CAtes-vous s\u00FBr que l'adresse IP de NS entr\u00E9e est correcte ?
|
||||||
|
netTabExpertModeCb=Mode expert
|
||||||
|
netTabHostPortLbl=port
|
||||||
|
netTabAutoDetectIpCb=D\u00E9tection automatique d'IP
|
||||||
|
netTabRandSelectPortCb=Obtenir un port al\u00E9atoire
|
||||||
|
netTabDontServeRequestsCb=Ne pas servir les demandes
|
||||||
|
netTabDontServeRequestsDescription=Si cette option est s\u00E9lectionn\u00E9e, cet ordinateur ne r\u00E9pond pas aux demandes de fichiers NSP provenant de NS (par le r\u00E9seau) et utilise les param\u00E8tres d\u2019h\u00F4te d\u00E9finis pour indiquer \u00E0 TinFoil o\u00F9 il doit rechercher les fichiers.
|
||||||
|
netTabHostExtraLbl=extra
|
||||||
|
windowTitleErrorPort=Port mal configur\u00E9!
|
||||||
|
windowBodyErrorPort=V\u00E9rifiez que le port est sup\u00E9rieur \u00E0 0 et inf\u00E9rieur ou \u00E9gal \u00E0 65535.
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
btnFileOpen=\u0412\u044B\u0431\u0440\u0430\u0442\u044C .NSP \u0444\u0430\u0439\u043B\u044B
|
|
||||||
btnUpload=\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0432 NS
|
|
||||||
logsEnteredAsMsg1=\u0412\u044B \u0432\u043E\u0448\u043B\u0438 \u043A\u0430\u043A:
|
|
||||||
logsEnteredAsMsg2=\u0427\u0442\u043E\u0431\u044B \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044C \u043E\u0448\u0438\u0431\u043E\u043A, \u0432\u044B \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C root \u0438\u043B\u0438 \u043D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u043F\u0440\u0430\u0432\u0438\u043B\u0430 'udev' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
|
|
||||||
logsFilesToUploadTitle=\u0424\u0430\u0439\u043B\u044B \u0434\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438:
|
|
||||||
logsGreetingsMessage=\u0414\u043E\u0431\u0440\u043E \u043F\u043E\u0436\u0430\u043B\u043E\u0432\u0430\u0442\u044C \u0432 NS-USBloader
|
|
||||||
logsNoFolderFileSelected=\u0424\u0430\u0439\u043B\u044B \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B - \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.
|
|
||||||
windowBodyConfirmExit=\u0421\u0435\u0439\u0447\u0430\u0441 \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u0438\u0442 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0434\u0430\u043D\u043D\u044B\u0445 \u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u0438\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u043F\u0440\u0435\u0440\u0432\u0451\u0442 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0443.\n\u042D\u0442\u043E \u0445\u0443\u0434\u0448\u0435\u0435 \u0447\u0442\u043E \u0442\u044B \u043C\u043E\u0436\u0435\u0448\u044C \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0434\u0435\u043B\u0430\u0442\u044C.\n\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0438 \u0432\u044B\u0439\u0442\u0438?
|
|
||||||
windowTitleConfirmExit=\u041D\u0435\u0442, \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0441\u044C!
|
|
||||||
btnStop=\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C
|
|
||||||
logsGreetingsMessage2=--\n\
|
|
||||||
\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u043A\u043E\u0434: https://github.com/developersu/ns-usbloader/\n\
|
|
||||||
\u0421\u0430\u0439\u0442: https://developersu.blogspot.com/search/label/NS-USBloader\n\
|
|
||||||
\u0418\u0441\u0430\u0435\u043D\u043A\u043E \u0414\u043C\u0438\u0442\u0440\u0438\u0439 [developer.su]
|
|
||||||
windowTitleConfirmWrongPFS0=\u041D\u0435\u043F\u0440\u0438\u0430\u0432\u0438\u043B\u044C\u043D\u044B\u0439 \u0442\u0438\u043F \u0444\u0430\u0439\u043B\u0430
|
|
||||||
windowBodyConfirmWrongPFS0=\u0412\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B NSP \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B. \u041E\u043D \u043D\u0430\u0432\u0435\u0440\u043D\u044F\u043A\u0430 \u043F\u043E\u0432\u0440\u0435\u0436\u0434\u0451\u043D.\n\
|
|
||||||
\u041B\u0443\u0447\u0448\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u0441\u0435\u0439\u0447\u0430\u0441. \u0425\u043E\u0447\u0435\u0448\u044C \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u043D\u0438 \u0441\u043C\u043E\u0442\u0440\u044F \u043D\u0438 \u043D\u0430 \u0447\u0442\u043E?\
|
|
||||||
|
|
||||||
tableUploadLbl=\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C?
|
|
||||||
tableSizeLbl=\u0420\u0430\u0437\u043C\u0435\u0440 (~\u041C\u0431)
|
|
||||||
tableFileNameLbl=\u0418\u043C\u044F \u0444\u0430\u0439\u043B\u0430
|
|
||||||
tableStatusLbl=\u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435
|
|
||||||
|
|
39
src/main/resources/locale_rus.properties
Normal file
39
src/main/resources/locale_rus.properties
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
btnFileOpen=\u0412\u044B\u0431\u0440\u0430\u0442\u044C .NSP \u0444\u0430\u0439\u043B\u044B
|
||||||
|
btnUpload=\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0432 NS
|
||||||
|
logsEnteredAsMsg1=\u0412\u044B \u0432\u043E\u0448\u043B\u0438 \u043A\u0430\u043A:
|
||||||
|
logsEnteredAsMsg2=\u0427\u0442\u043E\u0431\u044B \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044C \u043E\u0448\u0438\u0431\u043E\u043A, \u0432\u044B \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C root \u0438\u043B\u0438 \u043D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u043F\u0440\u0430\u0432\u0438\u043B\u0430 'udev' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
|
||||||
|
logsFilesToUploadTitle=\u0424\u0430\u0439\u043B\u044B \u0434\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438:
|
||||||
|
logsGreetingsMessage=\u0414\u043E\u0431\u0440\u043E \u043F\u043E\u0436\u0430\u043B\u043E\u0432\u0430\u0442\u044C \u0432 NS-USBloader
|
||||||
|
logsNoFolderFileSelected=\u0424\u0430\u0439\u043B\u044B \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B - \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.
|
||||||
|
windowBodyConfirmExit=\u0421\u0435\u0439\u0447\u0430\u0441 \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u0438\u0442 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0434\u0430\u043D\u043D\u044B\u0445 \u0438 \u0437\u0430\u043A\u0440\u044B\u0442\u0438\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u043F\u0440\u0435\u0440\u0432\u0451\u0442 \u0435\u0451.\n\u042D\u0442\u043E \u0445\u0443\u0434\u0448\u0435\u0435 \u0447\u0442\u043E \u0442\u044B \u043C\u043E\u0436\u0435\u0448\u044C \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0434\u0435\u043B\u0430\u0442\u044C.\n\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u0438 \u0432\u044B\u0439\u0442\u0438?
|
||||||
|
windowTitleConfirmExit=\u041D\u0435\u0442, \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0441\u044C!
|
||||||
|
btnStop=\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C
|
||||||
|
logsGreetingsMessage2=--\n\
|
||||||
|
\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u043A\u043E\u0434: https://github.com/developersu/ns-usbloader/\n\
|
||||||
|
\u0421\u0430\u0439\u0442: https://developersu.blogspot.com/search/label/NS-USBloader\n\
|
||||||
|
\u0418\u0441\u0430\u0435\u043D\u043A\u043E \u0414\u043C\u0438\u0442\u0440\u0438\u0439 [developer.su]
|
||||||
|
windowTitleConfirmWrongPFS0=\u041D\u0435\u043F\u0440\u0438\u0430\u0432\u0438\u043B\u044C\u043D\u044B\u0439 \u0442\u0438\u043F \u0444\u0430\u0439\u043B\u0430
|
||||||
|
windowBodyConfirmWrongPFS0=\u0412\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0444\u0430\u0439\u043B NSP \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B. \u041E\u043D \u043D\u0430\u0432\u0435\u0440\u043D\u044F\u043A\u0430 \u043F\u043E\u0432\u0440\u0435\u0436\u0434\u0451\u043D.\n\
|
||||||
|
\u041B\u0443\u0447\u0448\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u0441\u0435\u0439\u0447\u0430\u0441. \u0425\u043E\u0447\u0435\u0448\u044C \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u043D\u0438 \u0441\u043C\u043E\u0442\u0440\u044F \u043D\u0438 \u043D\u0430 \u0447\u0442\u043E?\
|
||||||
|
|
||||||
|
tableUploadLbl=\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C?
|
||||||
|
tableSizeLbl=\u0420\u0430\u0437\u043C\u0435\u0440
|
||||||
|
tableFileNameLbl=\u0418\u043C\u044F \u0444\u0430\u0439\u043B\u0430
|
||||||
|
tableStatusLbl=\u0421\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435
|
||||||
|
contextMenuBtnDelete=\u0423\u0434\u0430\u043B\u0438\u0442\u044C
|
||||||
|
contextMenuBtnDeleteAll=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u0441\u0451
|
||||||
|
netTabHostIPLbl=IP \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0430
|
||||||
|
NSIPlable=NS IP:
|
||||||
|
netTabValidateNSHostNameCb=\u0412\u0441\u0435\u0433\u0434\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E\u0441\u0442\u044C NS IP.
|
||||||
|
windowTitleBadIp=IP \u0430\u0434\u0440\u0435\u0441 NS \u043F\u043E\u0445\u043E\u0436\u0435 \u043D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u044B\u0439
|
||||||
|
windowBodyBadIp=\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B \u0447\u0442\u043E IP \u0430\u0434\u0440\u0435\u0441 NS \u0432\u0432\u0435\u0434\u0451\u043D \u0431\u0435\u0437 \u043E\u0448\u0438\u0431\u043E\u043A?
|
||||||
|
netTabExpertModeCb=\u0420\u0435\u0436\u0438\u043C \u044D\u043A\u0441\u043F\u0435\u0440\u0442\u0430
|
||||||
|
netTabHostPortLbl=\u043F\u043E\u0440\u0442
|
||||||
|
netTabAutoDetectIpCb=\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0442\u044C IP
|
||||||
|
netTabRandSelectPortCb=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0442\u044C \u043F\u043E\u0440\u0442 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u044B\u043C \u043E\u0431\u0440\u0430\u0437\u043E\u043C
|
||||||
|
netTabDontServeRequestsCb=\u041D\u0435 \u043E\u0431\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441\u044B
|
||||||
|
netTabDontServeRequestsDescription=\u0415\u0441\u043B\u0438 \u0432\u044B\u0431\u0440\u0430\u043D\u043E, \u0442\u043E\u0433\u0434\u0430 \u044D\u0442\u043E\u0442 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440 \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u043E\u0442\u0432\u0435\u0447\u0430\u0442\u044C \u043D\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B NSP \u0444\u0430\u0439\u043B\u043E\u0432. \u0411\u0443\u0434\u0443\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0445\u043E\u0441\u0442\u0430 \u0447\u0442\u043E\u0431\u044B \u0443\u043A\u0430\u0437\u0430\u0442\u044C TinFoil \u043E\u0442\u043A\u0443\u0434\u0430 \u0435\u043C\u0443 \u0441\u043B\u0435\u0434\u0443\u0435\u0442 \u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B.
|
||||||
|
netTabHostExtraLbl=\u044D\u043A\u0441\u0442\u0440\u0430
|
||||||
|
windowTitleErrorPort=\u041F\u043E\u0440\u0442 \u0443\u043A\u0430\u0437\u0430\u043D \u043D\u0435\u0432\u0435\u0440\u043D\u043E!
|
||||||
|
windowBodyErrorPort=\u041F\u043E\u0440\u0442 \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C 0 \u0438\u043B\u0438 \u043F\u0440\u0435\u0432\u044B\u0448\u0430\u0442\u044C 65535.
|
||||||
|
|
37
src/main/resources/locale_ukr.properties
Normal file
37
src/main/resources/locale_ukr.properties
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
btnFileOpen=\u0412\u0438\u0431\u0440\u0430\u0442\u0438 .NSP \u0444\u0430\u0439\u043B\u0438
|
||||||
|
btnUpload=\u0412\u0456\u0434\u0456\u0441\u043B\u0430\u0442\u0438 \u0443 NS
|
||||||
|
logsEnteredAsMsg1=\u0412\u0438 \u0443\u0432\u0456\u0439\u0448\u043B\u0438 \u044F\u043A:
|
||||||
|
logsEnteredAsMsg2=\u0414\u043B\u044F \u0437\u0430\u043F\u043E\u0431\u0456\u0433\u0430\u043D\u043D\u044F \u043F\u043E\u043C\u0438\u043B\u043E\u043A \u0432\u0438 \u043C\u0430\u0454\u0442\u0435 \u0431\u0443\u0442\u0438 root \u0430\u0431\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0457\u0442\u0438 \u043F\u0440\u0430\u0432\u0438\u043B\u0430 'udev' \u0434\u043B\u044F \u0446\u044C\u043E\u0433\u043E \u043A\u043E\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430.
|
||||||
|
logsFilesToUploadTitle=\u0424\u0430\u0439\u043B\u0438 \u0434\u043B\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F:
|
||||||
|
logsGreetingsMessage=\u041B\u0430\u0441\u043A\u0430\u0432\u043E \u043F\u0440\u043E\u0441\u0438\u043C\u043E \u0434\u043E NS-USBloader
|
||||||
|
logsNoFolderFileSelected=\u0424\u0430\u0439\u043B\u0438 \u043D\u0435 \u0432\u0438\u0431\u0440\u0430\u043D\u0456 - \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0443\u0432\u0430\u0442\u0438 \u043D\u0456\u0447\u043E\u0433\u043E.
|
||||||
|
windowBodyConfirmExit=\u0417\u0430\u0440\u0430\u0437 \u0432\u0456\u0434\u0431\u0443\u0432\u0430\u0454\u0442\u044C\u0441\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0434\u0430\u043D\u0438\u0445 \u0456 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043D\u044F \u0434\u043E\u0434\u0430\u0442\u043A\u0443 \u043F\u0440\u0435\u0440\u0432\u0435 \u0457\u0457.\n\u0426\u0435 \u043D\u0430\u0439\u0433\u0456\u0440\u0448\u0435 \u0449\u043E \u0442\u0438 \u043C\u043E\u0436\u0435\u0448 \u0437\u0430\u0440\u0430\u0437 \u0437\u0440\u043E\u0431\u0438\u0442\u0438.\n\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0446\u0435\u0441 \u0456 \u0432\u0438\u0439\u0442\u0438?
|
||||||
|
windowTitleConfirmExit=\u041D\u0456, \u0437\u0443\u043F\u0438\u043D\u0438\u0441\u044C!
|
||||||
|
btnStop=\u041F\u0435\u0440\u0435\u0440\u0432\u0430\u0442\u0438
|
||||||
|
logsGreetingsMessage2=--\n\
|
||||||
|
\u0421\u0438\u0440\u0446\u0435\u0432\u0438\u0439 \u043A\u043E\u0434: https://github.com/developersu/ns-usbloader/\n\
|
||||||
|
\u0421\u0430\u0439\u0442: https://developersu.blogspot.com/search/label/NS-USBloader\n\
|
||||||
|
\u0418\u0441\u0430\u0454\u043D\u043A\u043E \u0414\u043C\u0438\u0442\u0440\u043E [developer.su]
|
||||||
|
windowTitleConfirmWrongPFS0=\u041D\u0435\u0432\u0456\u0440\u043D\u0438\u0439 \u0442\u0438\u043F \u0444\u0430\u0439\u043B\u0443
|
||||||
|
windowBodyConfirmWrongPFS0=\u0412\u0438\u0431\u0440\u0430\u043D\u0438\u0439 \u0444\u0430\u0439\u043B NSP \u043C\u0430\u0454 \u043D\u0435\u0432\u0456\u0440\u043D\u0456 \u0441\u0438\u043C\u0432\u043E\u043B\u0438. \u0421\u043A\u043E\u0440\u0456\u0448\u0435 \u0437\u0430 \u0432\u0441\u0435 \u0432\u0456\u043D \u043F\u043E\u0448\u043A\u043E\u0434\u0436\u0435\u043D\u0438\u0439.\n\
|
||||||
|
\u041A\u0440\u0430\u0449\u0435 \u0437\u0443\u043F\u0438\u043D\u0438\u0442\u0438\u0441\u044F \u043F\u0440\u044F\u043C\u043E \u0437\u0430\u0440\u0430\u0437. \u0425\u043E\u0447\u0435\u0448 \u043F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u043D\u0435 \u0437\u0432\u0430\u0436\u0430\u044E\u0447\u0438 \u043D\u0456 \u043D\u0430 \u0449\u043E?
|
||||||
|
tableStatusLbl=\u0421\u0442\u0430\u043D
|
||||||
|
tableFileNameLbl=\u0406\u043C'\u044F \u0444\u0430\u0439\u043B\u0443
|
||||||
|
tableSizeLbl=\u0420\u043E\u0437\u043C\u0456\u0440
|
||||||
|
tableUploadLbl=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436.?
|
||||||
|
contextMenuBtnDelete=\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438
|
||||||
|
contextMenuBtnDeleteAll=\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u0432\u0441\u0435
|
||||||
|
netTabHostIPLbl=IP \u043A\u043E\u043C\u043F'\u044E\u0442\u0435\u0440\u0443
|
||||||
|
NSIPlable=NS IP:
|
||||||
|
netTabValidateNSHostNameCb=\u0417\u0430\u0432\u0436\u0434\u0438 \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u044F\u0442\u0438 \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u0456\u0441\u0442\u044C NS IP.
|
||||||
|
windowTitleBadIp=IP \u0430\u0434\u0440\u0435\u0441\u0430 NS \u0441\u043A\u043E\u0440\u0456\u0448 \u0437\u0430 \u0432\u0441\u0435 \u043D\u0435\u0432\u0456\u0440\u043D\u0430
|
||||||
|
windowBodyBadIp=\u0412\u0438 \u0432\u043F\u0435\u0432\u043D\u0435\u043D\u0456 \u0449\u043E IP \u0430\u0434\u0440\u0435\u0441\u0430 NS \u0432\u0432\u0435\u0434\u0435\u043D\u0430 \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E?
|
||||||
|
netTabExpertModeCb=\u0420\u0435\u0436\u0438\u043C \u0435\u043A\u0441\u043F\u0435\u0440\u0442\u0430
|
||||||
|
netTabHostPortLbl=\u043F\u043E\u0440\u0442
|
||||||
|
netTabAutoDetectIpCb=\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E \u0432\u0438\u0437\u043D\u0430\u0447\u0430\u0442\u0438 IP
|
||||||
|
netTabRandSelectPortCb=\u0412\u0438\u0437\u043D\u0430\u0447\u0430\u0442\u0438 \u043F\u043E\u0440\u0442 \u0432\u0438\u043F\u0430\u0434\u043A\u043E\u0432\u0438\u043C \u0447\u0438\u043D\u043E\u043C
|
||||||
|
netTabDontServeRequestsCb=\u041D\u0435 \u043E\u0431\u0440\u043E\u0431\u043B\u044F\u0442\u0438 \u0437\u0430\u043F\u0438\u0442\u0438
|
||||||
|
netTabDontServeRequestsDescription=\u042F\u043A\u0449\u043E \u0432\u0438\u0431\u0440\u0430\u043D\u043E, \u0442\u043E\u0434\u0456 \u0446\u0435\u0439 \u043A\u043E\u043C\u043F'\u044E\u0442\u0435\u0440 \u043D\u0435 \u0432\u0456\u0434\u043F\u043E\u0432\u0456\u0434\u0430\u0442\u0438\u043C\u0435 \u043D\u0430 \u0437\u0430\u043F\u0438\u0442\u0438 NSP \u0444\u0430\u0439\u043B\u0456\u0432. \u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0432\u0430\u0442\u0438\u043C\u0443\u0442\u044C\u0441\u044F \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F \u0445\u043E\u0441\u0442\u0430 \u0434\u043B\u044F \u0432\u043A\u0430\u0437\u0430\u043D\u043D\u044F TinFoil \u043C\u0456\u0441\u0446\u044F \u0437\u0432\u0456\u0434\u043A\u0438 \u0444\u0430\u0439\u043B\u0438 \u043C\u0430\u044E\u0442\u044C \u0431\u0440\u0430\u0442\u0438\u0441\u044F.
|
||||||
|
netTabHostExtraLbl=\u0435\u043A\u0441\u0442\u0440\u0430
|
||||||
|
windowTitleErrorPort=\u041D\u0435\u0432\u0456\u0440\u043D\u043E \u0432\u0438\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u043F\u043E\u0440\u0442!
|
||||||
|
windowBodyErrorPort=\u041F\u043E\u0440\u0442 \u043D\u0435 \u043C\u043E\u0436\u0435 \u0431\u0443\u0442\u0438 0 \u0430\u0431\u043E \u043F\u0440\u0438\u0432\u0438\u0449\u0443\u0432\u0430\u0442\u0438 65535.
|
|
@ -193,7 +193,6 @@
|
||||||
.table-view .column-header-background .label{
|
.table-view .column-header-background .label{
|
||||||
-fx-background-color: transparent;
|
-fx-background-color: transparent;
|
||||||
-fx-text-fill: #08f3ff;
|
-fx-text-fill: #08f3ff;
|
||||||
|
|
||||||
}
|
}
|
||||||
.table-view .column-header-background, .table-view .filler{
|
.table-view .column-header-background, .table-view .filler{
|
||||||
-fx-background-color: #4f4f4f;
|
-fx-background-color: #4f4f4f;
|
||||||
|
@ -202,14 +201,19 @@
|
||||||
.table-view .table-cell{
|
.table-view .table-cell{
|
||||||
-fx-text-fill: #f7fafa;
|
-fx-text-fill: #f7fafa;
|
||||||
}
|
}
|
||||||
.table-row-cell, .table-row-cell:filled:selected, .table-row-cell:selected{
|
.table-row-cell, .table-row-cell:selected, .table-row-cell:filled:selected{
|
||||||
-fx-background-color: -fx-table-cell-border-color, #424242;
|
-fx-background-color: -fx-table-cell-border-color, #424242;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #6d8484;
|
-fx-table-cell-border-color: #6d8484;
|
||||||
}
|
}
|
||||||
|
.table-row-cell .text, .table-row-cell:odd .text{
|
||||||
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
-fx-fill: #f7fafa;
|
||||||
|
}
|
||||||
|
.table-row-cell:filled:selected .text, .table-row-cell:odd:filled:selected .text{
|
||||||
|
-fx-fill: #08f3ff;
|
||||||
|
}
|
||||||
|
.table-row-cell:odd, .table-row-cell:odd:selected, .table-row-cell:odd:filled:selected{
|
||||||
-fx-background-color: -fx-table-cell-border-color, #4f4f4f;
|
-fx-background-color: -fx-table-cell-border-color, #4f4f4f;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
|
@ -218,16 +222,28 @@
|
||||||
// -========================== Context menu =====================-
|
// -========================== Context menu =====================-
|
||||||
.context-menu {
|
.context-menu {
|
||||||
-fx-background-color: #2d2d2d;
|
-fx-background-color: #2d2d2d;
|
||||||
-fx-text-fill: white;
|
|
||||||
-fx-cursor: hand;
|
-fx-cursor: hand;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item .label {
|
.context-menu .menu-item .label {
|
||||||
-fx-text-fill: #f7fafa;
|
-fx-text-fill: #f7fafa;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item:focused .label {
|
.context-menu .menu-item:focused .label {
|
||||||
-fx-text-fill: #f7fafa;
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
// -========================== Text Field =====================-
|
||||||
|
.text-field {
|
||||||
|
-fx-prompt-text-fill: #40596c;
|
||||||
|
-fx-border-color: #289de8;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
.text-field:focused {
|
||||||
|
-fx-border-color: #e82382;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-text-fill: #08f3ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
-fx-background-color: #fefefe;
|
-fx-background-color: #fefefe;
|
||||||
}
|
}
|
||||||
.dialog-pane > .button-bar > .container{
|
.dialog-pane > .button-bar > .container{
|
||||||
-fx-background-color: #2d2d2d;
|
-fx-background-color: #ebebeb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-pane > .label{
|
.dialog-pane > .label{
|
||||||
|
@ -207,7 +207,13 @@
|
||||||
-fx-padding: 0.0em; /* 0 */
|
-fx-padding: 0.0em; /* 0 */
|
||||||
-fx-table-cell-border-color: #b0b0b0;
|
-fx-table-cell-border-color: #b0b0b0;
|
||||||
}
|
}
|
||||||
|
.table-row-cell .text, .table-row-cell:odd .text {
|
||||||
|
-fx-fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
.table-row-cell:filled:selected .text, .table-row-cell:odd:filled:selected .text{
|
||||||
|
-fx-fill: #2c2c2c;
|
||||||
|
-fx-font-weight: bold
|
||||||
|
}
|
||||||
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
|
||||||
-fx-background-color: -fx-table-cell-border-color, #fefefe;
|
-fx-background-color: -fx-table-cell-border-color, #fefefe;
|
||||||
-fx-background-insets: 0, 0 0 1 0;
|
-fx-background-insets: 0, 0 0 1 0;
|
||||||
|
@ -217,16 +223,27 @@
|
||||||
// -========================== Context menu =====================-
|
// -========================== Context menu =====================-
|
||||||
.context-menu {
|
.context-menu {
|
||||||
-fx-background-color: #fefefe;
|
-fx-background-color: #fefefe;
|
||||||
-fx-text-fill: white;
|
|
||||||
-fx-cursor: hand;
|
-fx-cursor: hand;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item .label {
|
.context-menu .menu-item .label {
|
||||||
-fx-text-fill: #2c2c2c;
|
-fx-text-fill: #2c2c2c;
|
||||||
}
|
}
|
||||||
.context-menu .menu-item:focused .label {
|
.context-menu .menu-item:focused .label {
|
||||||
-fx-text-fill: #2c2c2c;
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
// -========================== Text Field =====================-
|
||||||
|
.text-field {
|
||||||
|
-fx-border-color: #289de8;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-text-fill: #2c2c2c;
|
||||||
|
}
|
||||||
|
.text-field:focused {
|
||||||
|
-fx-border-color: #e82382;
|
||||||
|
-fx-border-width: 0 0 1 0;
|
||||||
|
-fx-background-color: transparent;
|
||||||
|
-fx-text-fill: #e82382;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
Loading…
Reference in a new issue