Typos, minor fixes, new locale/resourceBundle support, code-refactoring
This commit is contained in:
parent
bda316abbb
commit
00db6984d9
14 changed files with 296 additions and 324 deletions
16
README.md
16
README.md
|
@ -35,16 +35,20 @@ JRE 8u60 or higher. See below.
|
||||||
|
|
||||||
### 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.
|
||||||
|
|
||||||
|
If you use different MacOS (not Mojave) - check release section for another JAR file.
|
||||||
|
|
||||||
### Windows:
|
### Windows:
|
||||||
|
|
||||||
* Download Zadig: https://zadig.akeo.ie/
|
* Download Zadig: https://zadig.akeo.ie/
|
||||||
* Open tinfoil. Set 'Title Managment' -> 'Usb install NSP'
|
* 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`)
|
||||||
|
@ -66,10 +70,10 @@ Table 'Status' = 'Uploaded' does not means that file installed. It means that it
|
||||||
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:
|
## TODO:
|
||||||
- [x] macOS QA v0.1
|
- [x] macOS QA v0.1 (Mojave)
|
||||||
- [ ] macOS QA v0.2 (partly)
|
- [x] macOS QA v0.2.2 (Mojave)
|
||||||
- [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)
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -8,7 +8,7 @@
|
||||||
<name>NS-USBloader</name>
|
<name>NS-USBloader</name>
|
||||||
|
|
||||||
<artifactId>ns-usbloader</artifactId>
|
<artifactId>ns-usbloader</artifactId>
|
||||||
<version>0.2.3_DEV-SNAPSHOT</version>
|
<version>0.3_DEV-SNAPSHOT</version>
|
||||||
|
|
||||||
<url>https://github.com/developersu/ns-usbloader/</url>
|
<url>https://github.com/developersu/ns-usbloader/</url>
|
||||||
<description>
|
<description>
|
||||||
|
@ -140,7 +140,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.usb4java</groupId>
|
<groupId>org.usb4java</groupId>
|
||||||
<artifactId>usb4java</artifactId>
|
<artifactId>usb4java</artifactId>
|
||||||
<version>1.2.0</version>
|
<version>1.3.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
@ -11,7 +11,7 @@ import javafx.stage.FileChooser;
|
||||||
import nsusbloader.AppPreferences;
|
import nsusbloader.AppPreferences;
|
||||||
import nsusbloader.MediatorControl;
|
import nsusbloader.MediatorControl;
|
||||||
import nsusbloader.NSLMain;
|
import nsusbloader.NSLMain;
|
||||||
import nsusbloader.UsbCommunications;
|
import nsusbloader.USB.UsbCommunications;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
@ -137,7 +137,7 @@ public class NSLMainController implements Initializable {
|
||||||
if (usbThread == null || !usbThread.isAlive()){
|
if (usbThread == null || !usbThread.isAlive()){
|
||||||
List<File> nspToUpload;
|
List<File> nspToUpload;
|
||||||
if ((nspToUpload = tableFilesListController.getFiles()) == null) {
|
if ((nspToUpload = tableFilesListController.getFiles()) == 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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -12,17 +12,16 @@ 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.3_DEV";
|
public static final String appVersion = "v0.3_DEV";
|
||||||
@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;
|
ResourceBundle rb;
|
||||||
if (Locale.getDefault().getISO3Language().equals("rus"))
|
Locale userLocale = new Locale(Locale.getDefault().getISO3Language()); // NOTE: user locale based on ISO3 Language codes
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("ru"));
|
rb = ResourceBundle.getBundle("locale", userLocale);
|
||||||
else
|
|
||||||
rb = ResourceBundle.getBundle("locale", new Locale("en"));
|
|
||||||
|
|
||||||
loader.setResources(rb);
|
loader.setResources(rb);
|
||||||
Parent root = loader.load();
|
Parent root = loader.load();
|
||||||
|
|
63
src/main/java/nsusbloader/USB/LogPrinter.java
Normal file
63
src/main/java/nsusbloader/USB/LogPrinter.java
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package nsusbloader.USB;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
* */
|
||||||
|
public void updateAndClose(HashMap<String, File> nspMap, EFileStatus status){
|
||||||
|
for (String fileName: nspMap.keySet())
|
||||||
|
statusMap.put(fileName, status);
|
||||||
|
msgConsumer.interrupt();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
package nsusbloader;
|
package nsusbloader.USB;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.USB.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,9 @@
|
||||||
package nsusbloader;
|
package nsusbloader.USB;
|
||||||
|
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
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 +15,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 +44,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 +81,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,13 +102,13 @@ public class UsbCommunications extends Task<Void> {
|
||||||
|
|
||||||
switch (result){
|
switch (result){
|
||||||
case 0:
|
case 0:
|
||||||
printLog("DBG: getActiveConfigDescriptor\n"+configDescriptor.dump(), EMsgType.PASS);
|
logPrinter.print("DBG: getActiveConfigDescriptor\n"+configDescriptor.dump(), EMsgType.PASS);
|
||||||
break;
|
break;
|
||||||
case LibUsb.ERROR_NOT_FOUND:
|
case LibUsb.ERROR_NOT_FOUND:
|
||||||
printLog("DBG: getActiveConfigDescriptor: ERROR_NOT_FOUND", EMsgType.FAIL);
|
logPrinter.print("DBG: getActiveConfigDescriptor: ERROR_NOT_FOUND", EMsgType.FAIL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printLog("DBG: getActiveConfigDescriptor: "+result, EMsgType.FAIL);
|
logPrinter.print("DBG: getActiveConfigDescriptor: "+result, EMsgType.FAIL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,10 +129,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;
|
||||||
}
|
}
|
||||||
|
@ -152,27 +140,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
|
||||||
|
@ -181,98 +158,54 @@ public class UsbCommunications extends Task<Void> {
|
||||||
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){
|
|
||||||
case 1: // used by kernel
|
|
||||||
result = LibUsb.detachKernelDriver(handlerNS, DEFAULT_INTERFACE);
|
result = LibUsb.detachKernelDriver(handlerNS, DEFAULT_INTERFACE);
|
||||||
printLog("Detach kernel required", EMsgType.INFO);
|
logPrinter.print("Detach kernel required", EMsgType.INFO);
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
switch (result){
|
logPrinter.print("Detach kernel\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
case LibUsb.ERROR_NOT_FOUND:
|
|
||||||
printLog("Detach kernel\n Returned: ERROR_NOT_FOUND", EMsgType.FAIL);
|
|
||||||
break;
|
|
||||||
case LibUsb.ERROR_INVALID_PARAM:
|
|
||||||
printLog("Detach kernel\n Returned: ERROR_INVALID_PARAM", 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();
|
close();
|
||||||
return null;
|
return null;
|
||||||
}
|
} else
|
||||||
else {
|
logPrinter.print("Detach kernel", EMsgType.PASS);
|
||||||
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("Can't proceed with libusb driver\n Returned: "+UsbErrorCodes.getErrCode(usedByKernel), EMsgType.FAIL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("libusb doesn't support function 'CAP_SUPPORTS_DETACH_KERNEL_DRIVER'. It's normal. Proceeding.", EMsgType.WARNING);
|
||||||
/*
|
/*
|
||||||
// Reset device
|
// Reset device
|
||||||
result = LibUsb.resetDevice(handlerNS);
|
result = LibUsb.resetDevice(handlerNS);
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
printLog("Reset device", EMsgType.PASS);
|
logPrinter.print("Reset device", EMsgType.PASS);
|
||||||
else {
|
else {
|
||||||
printLog("Reset device returned: " + result, EMsgType.FAIL);
|
logPrinter.print("Reset device returned: " + result, EMsgType.FAIL);
|
||||||
close();
|
updateAndClose();
|
||||||
return null;
|
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")) {
|
||||||
|
@ -282,7 +215,7 @@ public class UsbCommunications extends Task<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
close();
|
close();
|
||||||
printLog("\tEnd chain", EMsgType.INFO);
|
logPrinter.print("\tEnd chain", EMsgType.INFO);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -304,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()) {
|
||||||
|
@ -323,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;
|
||||||
}
|
}
|
||||||
|
@ -348,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);
|
||||||
|
@ -370,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
|
||||||
|
@ -414,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);
|
||||||
|
|
||||||
|
@ -428,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,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
|
||||||
}
|
}
|
||||||
|
@ -468,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;
|
||||||
}
|
}
|
||||||
|
@ -502,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,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
|
||||||
|
@ -560,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) {
|
||||||
|
@ -595,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,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;
|
||||||
}
|
}
|
||||||
|
@ -630,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;
|
||||||
}
|
}
|
||||||
|
@ -679,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();
|
||||||
|
@ -723,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
|
||||||
}
|
}
|
||||||
|
@ -742,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;
|
||||||
}
|
}
|
||||||
|
@ -754,30 +687,27 @@ 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.updateAndClose(nspMap, status);
|
||||||
statusMap.put(fileName, status);
|
|
||||||
|
|
||||||
msgConsumer.interrupt();
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sending any byte array to USB device
|
* Sending any byte array to USB device
|
||||||
|
@ -792,27 +722,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 {
|
||||||
|
@ -834,26 +749,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();
|
||||||
|
@ -865,30 +762,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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ logsEnteredAsMsg2=\u0427\u0442\u043E\u0431\u044B \u0438\u0437\u0431\u0435\u0436\
|
||||||
logsFilesToUploadTitle=\u0424\u0430\u0439\u043B\u044B \u0434\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438:
|
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
|
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.
|
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?
|
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!
|
windowTitleConfirmExit=\u041D\u0435\u0442, \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0441\u044C!
|
||||||
btnStop=\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C
|
btnStop=\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C
|
||||||
logsGreetingsMessage2=--\n\
|
logsGreetingsMessage2=--\n\
|
21
src/main/resources/locale_ukr.properties
Normal file
21
src/main/resources/locale_ukr.properties
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
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 (~\u041C\u0431)
|
||||||
|
tableUploadLbl=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436.?
|
Loading…
Reference in a new issue