mirror of
https://github.com/developersu/ns-usbloader.git
synced 2025-05-20 02:05:36 -04:00
Add split-files support for every 'protocol' supported
This commit is contained in:
parent
077aa9b0d8
commit
049c07fe8d
28 changed files with 618 additions and 265 deletions
91
src/main/java/nsusbloader/COM/Helpers/NSSplitReader.java
Normal file
91
src/main/java/nsusbloader/COM/Helpers/NSSplitReader.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
package nsusbloader.COM.Helpers;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Handle Split files
|
||||
* */
|
||||
public class NSSplitReader implements Closeable {
|
||||
|
||||
private final String splitFileDir;
|
||||
private final long referenceSplitChunkSize;
|
||||
|
||||
private byte subFileNum;
|
||||
private long curPosition;
|
||||
private BufferedInputStream biStream;
|
||||
|
||||
public NSSplitReader(File file, long seekToPosition) throws IOException, NullPointerException {
|
||||
this.splitFileDir = file.getAbsolutePath()+File.separator;
|
||||
File subFile = new File(file.getAbsolutePath()+File.separator+"00");
|
||||
if (! file.exists())
|
||||
throw new FileNotFoundException("File not found on "+file.getAbsolutePath()+File.separator+"00");
|
||||
this.referenceSplitChunkSize = subFile.length();
|
||||
this.subFileNum = (byte) (seekToPosition / referenceSplitChunkSize);
|
||||
this.biStream = new BufferedInputStream(new FileInputStream(splitFileDir + String.format("%02d", subFileNum)));
|
||||
this.curPosition = seekToPosition;
|
||||
|
||||
seekToPosition -= referenceSplitChunkSize * subFileNum;
|
||||
|
||||
if (seekToPosition != biStream.skip(seekToPosition))
|
||||
throw new IOException("Unable to seek to requested position of "+seekToPosition+" for file "+splitFileDir+String.format("%02d", subFileNum));
|
||||
}
|
||||
|
||||
public long seek(long position) throws IOException{
|
||||
|
||||
byte subFileRequested = (byte) (position / referenceSplitChunkSize);
|
||||
|
||||
if ((subFileRequested != this.subFileNum) || (curPosition > position)) {
|
||||
biStream.close();
|
||||
biStream = new BufferedInputStream(new FileInputStream(splitFileDir + String.format("%02d", subFileRequested)));
|
||||
this.subFileNum = subFileRequested;
|
||||
this.curPosition = referenceSplitChunkSize * subFileRequested;
|
||||
}
|
||||
|
||||
long retVal = biStream.skip(position - curPosition);
|
||||
|
||||
retVal += curPosition;
|
||||
this.curPosition = position;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public int read(byte[] readBuffer) throws IOException, NullPointerException {
|
||||
final int requested = readBuffer.length;
|
||||
int readPrtOne;
|
||||
|
||||
if ( (curPosition + requested) <= (referenceSplitChunkSize * (subFileNum+1))) {
|
||||
if ((readPrtOne = biStream.read(readBuffer)) < 0 )
|
||||
return readPrtOne;
|
||||
curPosition += readPrtOne;
|
||||
return readPrtOne;
|
||||
}
|
||||
|
||||
int partOne = (int) (referenceSplitChunkSize * (subFileNum+1) - curPosition);
|
||||
int partTwo = requested - partOne;
|
||||
int readPrtTwo;
|
||||
|
||||
if ( (readPrtOne = biStream.read(readBuffer, 0, partOne)) < 0)
|
||||
return readPrtOne;
|
||||
|
||||
curPosition += readPrtOne;
|
||||
|
||||
if (readPrtOne != partOne)
|
||||
return readPrtOne;
|
||||
|
||||
biStream.close();
|
||||
subFileNum += 1;
|
||||
biStream = new BufferedInputStream(new FileInputStream(splitFileDir + String.format("%02d", subFileNum)));
|
||||
|
||||
if ( (readPrtTwo = biStream.read(readBuffer, partOne, partTwo) ) < 0)
|
||||
return readPrtTwo;
|
||||
|
||||
curPosition += readPrtTwo;
|
||||
|
||||
return readPrtOne + readPrtTwo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (biStream != null)
|
||||
biStream.close();
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package nsusbloader.NET;
|
||||
package nsusbloader.COM.NET;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.COM.Helpers.NSSplitReader;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
@ -22,6 +23,7 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
private String switchIP;
|
||||
|
||||
private HashMap<String, File> nspMap;
|
||||
private HashMap<String, Long> nspFileSizes;
|
||||
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
|
@ -42,6 +44,29 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
this.switchIP = switchIP;
|
||||
this.logPrinter = new LogPrinter();
|
||||
this.nspMap = new HashMap<>();
|
||||
this.nspFileSizes = new HashMap<>();
|
||||
// Filter and remove empty/incorrect split-files
|
||||
filesList.removeIf(f -> {
|
||||
if (f.isDirectory()){
|
||||
File[] subFiles = f.listFiles((file, name) -> name.matches("[0-9]{2}"));
|
||||
if (subFiles == null || subFiles.length == 0) {
|
||||
logPrinter.print("NET: Removing empty folder: " + f.getName(), EMsgType.WARNING);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Arrays.sort(subFiles, Comparator.comparingInt(file -> Integer.parseInt(file.getName())));
|
||||
|
||||
for (int i = subFiles.length - 2; i > 0 ; i--){
|
||||
if (subFiles[i].length() < subFiles[i-1].length()) {
|
||||
logPrinter.print("NET: Removing strange split file: "+f.getName()+
|
||||
"\n (Chunk sizes of the split file are not the same, but has to be.)", EMsgType.WARNING);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// Collect and encode NSP files list
|
||||
try {
|
||||
for (File nspFile : filesList)
|
||||
|
@ -49,12 +74,27 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
}
|
||||
catch (UnsupportedEncodingException uee){
|
||||
isValid = false;
|
||||
logPrinter.print("NET: Unsupported encoding for 'URLEncoder'. Internal issue you can't fix. Please report. Returned:\n\t"+uee.getMessage(), EMsgType.FAIL);
|
||||
for (File nspFile : filesList)
|
||||
nspMap.put(nspFile.getName(), nspFile);
|
||||
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;
|
||||
}
|
||||
// Collect sizes since now we can have split-files support
|
||||
for (Map.Entry<String, File> entry : nspMap.entrySet()){
|
||||
File inFile = entry.getValue();
|
||||
long fSize = 0;
|
||||
if (inFile.isDirectory()){
|
||||
File[] subFiles = inFile.listFiles((file, name) -> name.matches("[0-9]{2}"));
|
||||
for (File subFile : subFiles)
|
||||
fSize += subFile.length();
|
||||
nspFileSizes.put(entry.getKey(), fSize);
|
||||
}
|
||||
else
|
||||
nspFileSizes.put(entry.getKey(), inFile.length());
|
||||
}
|
||||
|
||||
|
||||
// Resolve IP
|
||||
if (hostIPaddr.isEmpty()) {
|
||||
DatagramSocket socket;
|
||||
|
@ -242,23 +282,23 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
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
|
||||
//System.out.println(line); // Debug
|
||||
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
|
||||
tcpPacket.add(line); // Otherwise collect data
|
||||
}
|
||||
// and reopen client sock
|
||||
clientSocket.close();
|
||||
}
|
||||
catch (IOException ioe){ // If server socket closed, then client socket also closed.
|
||||
catch (IOException ioe){ // If server socket closed, then client socket also closed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isCancelled())
|
||||
if ( ! isCancelled() )
|
||||
close(EFileStatus.UNKNOWN);
|
||||
return null;
|
||||
}
|
||||
|
@ -271,8 +311,11 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
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
|
||||
String reqFileName = packet.get(0).replaceAll("(^[A-z\\s]+/)|(\\s+?.*$)", "");
|
||||
long reqFileSize = nspFileSizes.get(reqFileName);
|
||||
requestedFile = nspMap.get(reqFileName);
|
||||
|
||||
if (!requestedFile.exists() || reqFileSize == 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);
|
||||
|
@ -280,7 +323,7 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
return true;
|
||||
}
|
||||
if (packet.get(0).startsWith("HEAD")){
|
||||
currSockPW.write(NETPacket.getCode200(requestedFile.length()));
|
||||
currSockPW.write(NETPacket.getCode200(reqFileSize));
|
||||
currSockPW.flush();
|
||||
logPrinter.print("NET: Replying for requested file: "+requestedFile.getName(), EMsgType.INFO);
|
||||
return false;
|
||||
|
@ -298,23 +341,23 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||
return true;
|
||||
}
|
||||
if (writeToSocket(requestedFile, Long.parseLong(rangeStr[0]), Long.parseLong(rangeStr[1]))) // DO WRITE
|
||||
if (writeToSocket(reqFileName, 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
|
||||
if (writeToSocket(reqFileName, Long.parseLong(rangeStr[0]), reqFileSize)) // 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
|
||||
if (reqFileSize > 500){
|
||||
if (writeToSocket(reqFileName, reqFileSize-500, reqFileSize)) // 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.print("NET: File size requested for "+requestedFile.getName()+" while actual size of it: "+reqFileSize+". Returning 416", EMsgType.FAIL);
|
||||
logPrinter.update(requestedFile, EFileStatus.FAILED);
|
||||
return true;
|
||||
}
|
||||
|
@ -343,50 +386,84 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
/**
|
||||
* Send files.
|
||||
* */
|
||||
private boolean writeToSocket(File file, long start, long end){
|
||||
private boolean writeToSocket(String fileName, long start, long end){
|
||||
File reqFile = nspMap.get(fileName);
|
||||
// Inform
|
||||
logPrinter.print("NET: Responding to requested range: "+start+"-"+end, EMsgType.INFO);
|
||||
currSockPW.write(NETPacket.getCode206(file.length(), start, end));
|
||||
// Reply
|
||||
currSockPW.write(NETPacket.getCode206(nspFileSizes.get(fileName), start, end));
|
||||
currSockPW.flush();
|
||||
// Prepare transfer
|
||||
long count = end - start + 1;
|
||||
|
||||
int readPice = 8388608; // = 8Mb
|
||||
byte[] byteBuf;
|
||||
long currentOffset = 0;
|
||||
|
||||
try{
|
||||
long count = end - start + 1;
|
||||
//================================= SPLIT FILE ====================================
|
||||
if (reqFile.isDirectory()){
|
||||
NSSplitReader nsr = new NSSplitReader(reqFile, start);
|
||||
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
int readPice = 8388608; // = 8Mb
|
||||
byte[] byteBuf;
|
||||
while (currentOffset < count){
|
||||
if (isCancelled())
|
||||
return true;
|
||||
if ((currentOffset + readPice) >= count){
|
||||
readPice = Math.toIntExact(count - currentOffset);
|
||||
}
|
||||
byteBuf = new byte[readPice];
|
||||
|
||||
if (bis.skip(start) != start){
|
||||
logPrinter.print("NET: Unable to skip requested range.", EMsgType.FAIL);
|
||||
logPrinter.update(file, EFileStatus.FAILED);
|
||||
return true;
|
||||
}
|
||||
long currentOffset = 0;
|
||||
while (currentOffset < count){
|
||||
if (isCancelled())
|
||||
return true;
|
||||
if ((currentOffset+readPice) >= count){
|
||||
readPice = Math.toIntExact(count - currentOffset);
|
||||
if (nsr.read(byteBuf) != readPice){
|
||||
logPrinter.print("NET: Reading of file stream suddenly ended.", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
currSockOS.write(byteBuf);
|
||||
//-------/
|
||||
logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0);
|
||||
//-------/
|
||||
currentOffset += readPice;
|
||||
}
|
||||
byteBuf = new byte[readPice];
|
||||
currSockOS.flush(); // TODO: check if this really needed.
|
||||
nsr.close();
|
||||
}
|
||||
//================================= REGULAR FILE ====================================
|
||||
else {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(reqFile));
|
||||
|
||||
if (bis.read(byteBuf) != readPice){
|
||||
logPrinter.print("NET: Reading of file stream suddenly ended.", EMsgType.FAIL);
|
||||
if (bis.skip(start) != start){
|
||||
logPrinter.print("NET: Unable to skip requested range.", EMsgType.FAIL);
|
||||
logPrinter.update(reqFile, EFileStatus.FAILED);
|
||||
return true;
|
||||
}
|
||||
currSockOS.write(byteBuf);
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0);
|
||||
//-----------------------------------------/
|
||||
currentOffset += readPice;
|
||||
|
||||
while (currentOffset < count){
|
||||
if (isCancelled())
|
||||
return true;
|
||||
if ((currentOffset + readPice) >= count){
|
||||
readPice = Math.toIntExact(count - currentOffset);
|
||||
}
|
||||
byteBuf = new byte[readPice];
|
||||
|
||||
if (bis.read(byteBuf) != readPice){
|
||||
logPrinter.print("NET: Reading of file stream suddenly ended.", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
currSockOS.write(byteBuf);
|
||||
//-------/
|
||||
logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0);
|
||||
//-------/
|
||||
currentOffset += readPice;
|
||||
}
|
||||
currSockOS.flush(); // TODO: check if this really needed.
|
||||
bis.close();
|
||||
}
|
||||
currSockOS.flush(); // TODO: check if this really needed.
|
||||
bis.close();
|
||||
//-----------------------------------------/
|
||||
//-------/
|
||||
logPrinter.updateProgress(1.0);
|
||||
//-----------------------------------------/
|
||||
//-------/
|
||||
}
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("NET: File transmission failed. Returned:\n\t"+ioe.getMessage(), EMsgType.FAIL);
|
||||
logPrinter.update(file, EFileStatus.FAILED);
|
||||
catch (IOException | NullPointerException e){
|
||||
logPrinter.print("NET: File transmission failed. Returned:\n\t"+e.getMessage(), EMsgType.FAIL);
|
||||
logPrinter.update(reqFile, EFileStatus.FAILED);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -403,7 +480,7 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
|||
logPrinter.print("NET: Closing server socket.", EMsgType.PASS);
|
||||
}
|
||||
}
|
||||
catch (IOException | NullPointerException ioe){
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("NET: Closing server socket failed. Sometimes it's not an issue.", EMsgType.WARNING);
|
||||
}
|
||||
if (status != null) {
|
|
@ -1,4 +1,4 @@
|
|||
package nsusbloader.NET;
|
||||
package nsusbloader.COM.NET;
|
||||
|
||||
import nsusbloader.NSLMain;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.stage.FileChooser;
|
||||
import nsusbloader.MediatorControl;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.COM.Helpers.NSSplitReader;
|
||||
import org.usb4java.DeviceHandle;
|
||||
import org.usb4java.LibUsb;
|
||||
|
||||
|
@ -19,14 +19,10 @@ import java.util.*;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* GoldLeaf processing
|
||||
* GoldLeaf 0.7 - 0.7.3 processing
|
||||
*/
|
||||
class GoldLeaf implements ITransferModule {
|
||||
private LogPrinter logPrinter;
|
||||
private DeviceHandle handlerNS;
|
||||
private LinkedHashMap<String, File> nspMap;
|
||||
class GoldLeaf extends TransferModule {
|
||||
private boolean nspFilterForGl;
|
||||
private Task<Void> task;
|
||||
|
||||
// CMD
|
||||
private final byte[] CMD_GLCO_SUCCESS = new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00}; // used @ writeToUsb_GLCMD
|
||||
|
@ -44,8 +40,11 @@ class GoldLeaf implements ITransferModule {
|
|||
|
||||
private String openReadFileNameAndPath;
|
||||
private RandomAccessFile randAccessFile;
|
||||
private NSSplitReader splitReader;
|
||||
|
||||
private HashMap<String, BufferedOutputStream> writeFilesMap;
|
||||
private long virtDriveSize;
|
||||
private HashMap<String, Long> splitFileSize;
|
||||
|
||||
private boolean isWindows;
|
||||
private String homePath;
|
||||
|
@ -53,6 +52,8 @@ class GoldLeaf implements ITransferModule {
|
|||
private File selectedFile;
|
||||
|
||||
GoldLeaf(DeviceHandle handler, LinkedHashMap<String, File> nspMap, Task<Void> task, LogPrinter logPrinter, boolean nspFilter){
|
||||
super(handler, nspMap, task, logPrinter);
|
||||
|
||||
final byte CMD_GetDriveCount = 0x00;
|
||||
final byte CMD_GetDriveInfo = 0x01;
|
||||
final byte CMD_StatPath = 0x02; // proxy done [proxy: in case if folder contains ENG+RUS+UKR file names works incorrect]
|
||||
|
@ -72,11 +73,7 @@ class GoldLeaf implements ITransferModule {
|
|||
|
||||
final byte[] CMD_GLCI = new byte[]{0x47, 0x4c, 0x43, 0x49};
|
||||
|
||||
this.handlerNS = handler;
|
||||
this.nspMap = nspMap;
|
||||
this.logPrinter = logPrinter;
|
||||
this.nspFilterForGl = nspFilter;
|
||||
this.task = task;
|
||||
|
||||
logPrinter.print("============= GoldLeaf =============\n\tVIRT:/ equals files added into the application\n\tHOME:/ equals "
|
||||
+System.getProperty("user.home"), EMsgType.INFO);
|
||||
|
@ -92,6 +89,22 @@ class GoldLeaf implements ITransferModule {
|
|||
|
||||
homePath = System.getProperty("user.home")+File.separator;
|
||||
|
||||
splitFileSize = new HashMap<>();
|
||||
|
||||
// Calculate size of VIRT:/ drive
|
||||
for (File nspFile : nspMap.values()){
|
||||
if (nspFile.isDirectory()) {
|
||||
File[] subFiles = nspFile.listFiles((file, name) -> name.matches("[0-9]{2}"));
|
||||
long size = 0;
|
||||
for (File subFile : subFiles) // Validated by parent class
|
||||
size += subFile.length();
|
||||
virtDriveSize += size;
|
||||
splitFileSize.put(nspFile.getName(), size);
|
||||
}
|
||||
else
|
||||
virtDriveSize += nspFile.length();
|
||||
}
|
||||
|
||||
// Go parse commands
|
||||
byte[] readByte;
|
||||
int someLength1,
|
||||
|
@ -193,7 +206,7 @@ class GoldLeaf implements ITransferModule {
|
|||
for (BufferedOutputStream fBufOutStream: writeFilesMap.values()){
|
||||
try{
|
||||
fBufOutStream.close();
|
||||
}catch (IOException ignored){}
|
||||
}catch (IOException | NullPointerException ignored){}
|
||||
}
|
||||
}
|
||||
closeOpenedReadFilesGl();
|
||||
|
@ -207,9 +220,14 @@ class GoldLeaf implements ITransferModule {
|
|||
try{
|
||||
randAccessFile.close();
|
||||
}
|
||||
catch (IOException ignored){}
|
||||
catch (IOException | NullPointerException ignored){}
|
||||
try{
|
||||
splitReader.close();
|
||||
}
|
||||
catch (IOException | NullPointerException ignored){}
|
||||
openReadFileNameAndPath = null;
|
||||
randAccessFile = null;
|
||||
splitReader = null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -243,7 +261,7 @@ class GoldLeaf implements ITransferModule {
|
|||
driveLetterLen,
|
||||
totalFreeSpace,
|
||||
totalSize;
|
||||
long totalSizeLong = 0;
|
||||
long totalSizeLong;
|
||||
|
||||
// 0 == VIRTUAL DRIVE
|
||||
if (driveNo == 0){
|
||||
|
@ -252,9 +270,7 @@ class GoldLeaf implements ITransferModule {
|
|||
driveLetter = "VIRT".getBytes(StandardCharsets.UTF_16LE); // TODO: Consider moving to class field declaration
|
||||
driveLetterLen = intToArrLE(driveLetter.length / 2);// since GL 0.7
|
||||
totalFreeSpace = new byte[4];
|
||||
for (File nspFile : nspMap.values()){
|
||||
totalSizeLong += nspFile.length();
|
||||
}
|
||||
totalSizeLong = virtDriveSize;
|
||||
totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4); // Dirty hack; now for GL!
|
||||
}
|
||||
else { //1 == User home dir
|
||||
|
@ -567,7 +583,12 @@ class GoldLeaf implements ITransferModule {
|
|||
filePath = filePath.replaceFirst("VIRT:/", "");
|
||||
if (nspMap.containsKey(filePath)){
|
||||
command.add(GL_OBJ_TYPE_FILE); // THIS IS INT
|
||||
command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG!
|
||||
if (nspMap.get(filePath).isDirectory()) {
|
||||
command.add(longToArrLE(splitFileSize.get(filePath))); // YES, THIS IS LONG!;
|
||||
}
|
||||
else
|
||||
command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG!
|
||||
|
||||
if (writeGL_PASS(command)) {
|
||||
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL);
|
||||
return true;
|
||||
|
@ -693,7 +714,7 @@ class GoldLeaf implements ITransferModule {
|
|||
* false if everything is ok
|
||||
* */
|
||||
private boolean readFile(String fileName, long offset, long size) {
|
||||
//System.out.println("readFile "+fileName+" "+offset+" "+size);
|
||||
//System.out.println("readFile "+fileName+" "+offset+" "+size+"\n");
|
||||
if (fileName.startsWith("VIRT:/")){
|
||||
// Let's find out which file requested
|
||||
String fNamePath = nspMap.get(fileName.substring(6)).getAbsolutePath(); // NOTE: 6 = "VIRT:/".length
|
||||
|
@ -703,14 +724,25 @@ class GoldLeaf implements ITransferModule {
|
|||
if (openReadFileNameAndPath != null){
|
||||
try{
|
||||
randAccessFile.close();
|
||||
}catch (IOException ignored){}
|
||||
}catch (Exception ignored){}
|
||||
try{
|
||||
splitReader.close();
|
||||
}catch (Exception ignored){}
|
||||
}
|
||||
// Open what has to be opened
|
||||
try{
|
||||
randAccessFile = new RandomAccessFile(nspMap.get(fileName.substring(6)), "r");
|
||||
File tempFile = nspMap.get(fileName.substring(6));
|
||||
if (tempFile.isDirectory()) {
|
||||
randAccessFile = null;
|
||||
splitReader = new NSSplitReader(tempFile, 0);
|
||||
}
|
||||
else {
|
||||
splitReader = null;
|
||||
randAccessFile = new RandomAccessFile(tempFile, "r");
|
||||
}
|
||||
openReadFileNameAndPath = fNamePath;
|
||||
}
|
||||
catch (IOException ioe){
|
||||
catch (IOException | NullPointerException ioe){
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command\n\t"+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -724,47 +756,79 @@ class GoldLeaf implements ITransferModule {
|
|||
if (openReadFileNameAndPath != null){
|
||||
try{
|
||||
randAccessFile.close();
|
||||
}catch (IOException ignored){}
|
||||
}catch (IOException | NullPointerException ignored){}
|
||||
}
|
||||
// Open what has to be opened
|
||||
try{
|
||||
randAccessFile = new RandomAccessFile(fileName, "r");
|
||||
openReadFileNameAndPath = fileName;
|
||||
}catch (IOException ioe){
|
||||
}catch (IOException | NullPointerException ioe){
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command\n\t"+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------- Actual transfer chain ------------------------
|
||||
try{
|
||||
randAccessFile.seek(offset);
|
||||
byte[] chunk = new byte[(int)size]; // WTF MAN?
|
||||
// Let's find out how much bytes we got
|
||||
int bytesRead = randAccessFile.read(chunk);
|
||||
// Let's check that we read expected size
|
||||
if (bytesRead != (int)size)
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead);
|
||||
// Let's tell as a command about our result.
|
||||
if (writeGL_PASS(longToArrLE(size))) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
|
||||
return true;
|
||||
if (randAccessFile == null){
|
||||
splitReader.seek(offset);
|
||||
byte[] chunk = new byte[(int)size]; // WTF MAN?
|
||||
// Let's find out how much bytes we got
|
||||
int bytesRead = splitReader.read(chunk);
|
||||
// Let's check that we read expected size
|
||||
if (bytesRead != (int)size)
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command [CMD]\n" +
|
||||
" At offset: "+offset+"\n Requested: "+size+"\n Received: "+bytesRead);
|
||||
// Let's tell as a command about our result.
|
||||
if (writeGL_PASS(longToArrLE(size))) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
// Let's bypass bytes we read total
|
||||
if (writeToUsb(chunk)) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Let's bypass bytes we read total
|
||||
if (writeToUsb(chunk)) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL);
|
||||
return true;
|
||||
else {
|
||||
randAccessFile.seek(offset);
|
||||
byte[] chunk = new byte[(int)size]; // WTF MAN?
|
||||
// Let's find out how much bytes we got
|
||||
int bytesRead = randAccessFile.read(chunk);
|
||||
// Let's check that we read expected size
|
||||
if (bytesRead != (int)size)
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead);
|
||||
// Let's tell as a command about our result.
|
||||
if (writeGL_PASS(longToArrLE(size))) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
// Let's bypass bytes we read total
|
||||
if (writeToUsb(chunk)) {
|
||||
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (IOException ioe){
|
||||
catch (Exception ioe){
|
||||
try{
|
||||
randAccessFile.close();
|
||||
}
|
||||
catch (IOException ioee){
|
||||
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioee.getMessage(), EMsgType.WARNING);
|
||||
catch (NullPointerException ignored){}
|
||||
catch (IOException ioe_){
|
||||
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
|
||||
}
|
||||
try{
|
||||
splitReader.close();
|
||||
}
|
||||
catch (NullPointerException ignored){}
|
||||
catch (IOException ioe_){
|
||||
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
|
||||
}
|
||||
openReadFileNameAndPath = null;
|
||||
randAccessFile = null;
|
||||
splitReader = null;
|
||||
return writeGL_FAIL("GL Handle 'ReadFile' command\n\t"+ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -852,10 +916,6 @@ class GoldLeaf implements ITransferModule {
|
|||
return writeGL_FAIL("GL Handle 'SelectFile' command: Nothing selected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EFileStatus getStatus() {
|
||||
return EFileStatus.UNKNOWN;
|
||||
}
|
||||
/*----------------------------------------------------*/
|
||||
/* GL HELPERS */
|
||||
/*----------------------------------------------------*/
|
|
@ -1,10 +1,11 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.USB.PFS.PFSProvider;
|
||||
import nsusbloader.COM.Helpers.NSSplitReader;
|
||||
import nsusbloader.COM.USB.PFS.PFSProvider;
|
||||
import org.usb4java.DeviceHandle;
|
||||
import org.usb4java.LibUsb;
|
||||
|
||||
|
@ -18,7 +19,7 @@ import java.util.LinkedHashMap;
|
|||
/**
|
||||
* GoldLeaf processing
|
||||
* */
|
||||
public class GoldLeaf_05 implements ITransferModule{
|
||||
public class GoldLeaf_05 extends TransferModule {
|
||||
// CMD G L U C
|
||||
private static final byte[] CMD_GLUC = new byte[]{0x47, 0x4c, 0x55, 0x43};
|
||||
private static final byte[] CMD_ConnectionRequest = new byte[]{0x00, 0x00, 0x00, 0x00}; // Write-only command
|
||||
|
@ -31,13 +32,13 @@ public class GoldLeaf_05 implements ITransferModule{
|
|||
private static final byte[] CMD_NSPTicket = new byte[]{0x06, 0x00, 0x00, 0x00};
|
||||
private static final byte[] CMD_Finish = new byte[]{0x07, 0x00, 0x00, 0x00};
|
||||
|
||||
private DeviceHandle handlerNS;
|
||||
private Task<Void> task;
|
||||
private LogPrinter logPrinter;
|
||||
private EFileStatus status = EFileStatus.FAILED;
|
||||
private RandomAccessFile raf; // NSP File
|
||||
private NSSplitReader nsr; // It'a also NSP File
|
||||
|
||||
GoldLeaf_05(DeviceHandle handler, LinkedHashMap<String, File> nspMap, Task<Void> task, LogPrinter logPrinter){
|
||||
super(handler, nspMap, task, logPrinter);
|
||||
status = EFileStatus.FAILED;
|
||||
|
||||
logPrinter.print("============= GoldLeaf v0.5 =============\n" +
|
||||
" Only one file per time could be sent. In case you selected more the first one would be picked.", EMsgType.INFO);
|
||||
if (nspMap.isEmpty()){
|
||||
|
@ -62,14 +63,14 @@ public class GoldLeaf_05 implements ITransferModule{
|
|||
}
|
||||
logPrinter.print("GL File structure validated and it will be uploaded", EMsgType.PASS);
|
||||
|
||||
this.handlerNS = handler;
|
||||
this.task = task;
|
||||
this.logPrinter = logPrinter;
|
||||
try{
|
||||
this.raf = new RandomAccessFile(nspFile, "r");
|
||||
if (nspFile.isDirectory())
|
||||
this.nsr = new NSSplitReader(nspFile, 0);
|
||||
else
|
||||
this.raf = new RandomAccessFile(nspFile, "r");
|
||||
}
|
||||
catch (FileNotFoundException fnfe){
|
||||
logPrinter.print("GL File not found\n\t"+fnfe.getMessage(), EMsgType.FAIL);
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("GL File not found\n\t"+ioe.getMessage(), EMsgType.FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -131,9 +132,11 @@ public class GoldLeaf_05 implements ITransferModule{
|
|||
try {
|
||||
raf.close();
|
||||
}
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("GL Failed to close file.", EMsgType.INFO);
|
||||
catch (IOException | NullPointerException ignored){}
|
||||
try {
|
||||
nsr.close();
|
||||
}
|
||||
catch (IOException | NullPointerException ignored){}
|
||||
}
|
||||
/**
|
||||
* ConnectionResponse command handler
|
||||
|
@ -254,21 +257,41 @@ public class GoldLeaf_05 implements ITransferModule{
|
|||
byte[] readBuf;
|
||||
|
||||
try{
|
||||
raf.seek(realNcaOffset);
|
||||
if (raf == null){
|
||||
nsr.seek(realNcaOffset);
|
||||
|
||||
while (readFrom < realNcaSize){
|
||||
if (realNcaSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realNcaSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (raf.read(readBuf) != readPice)
|
||||
return true;
|
||||
//System.out.println("S: "+readFrom+" T: "+realNcaSize+" P: "+readPice); // DEBUG
|
||||
if (writeUsb(readBuf))
|
||||
return true;
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0);
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
while (readFrom < realNcaSize){
|
||||
if (realNcaSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realNcaSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (nsr.read(readBuf) != readPice)
|
||||
return true;
|
||||
//System.out.println("S: "+readFrom+" T: "+realNcaSize+" P: "+readPice); // DEBUG
|
||||
if (writeUsb(readBuf))
|
||||
return true;
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0);
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
}
|
||||
}
|
||||
else {
|
||||
raf.seek(realNcaOffset);
|
||||
|
||||
while (readFrom < realNcaSize){
|
||||
if (realNcaSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realNcaSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (raf.read(readBuf) != readPice)
|
||||
return true;
|
||||
//System.out.println("S: "+readFrom+" T: "+realNcaSize+" P: "+readPice); // DEBUG
|
||||
if (writeUsb(readBuf))
|
||||
return true;
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realNcaSize/100.0) / 100.0);
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress(1.0);
|
||||
|
@ -282,8 +305,6 @@ public class GoldLeaf_05 implements ITransferModule{
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EFileStatus getStatus() { return status; }
|
||||
|
||||
/**
|
||||
* Sending any byte array to USB device
|
|
@ -1,4 +1,4 @@
|
|||
package nsusbloader.USB.PFS;
|
||||
package nsusbloader.COM.USB.PFS;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
|
@ -1,8 +1,7 @@
|
|||
package nsusbloader.USB.PFS;
|
||||
package nsusbloader.COM.USB.PFS;
|
||||
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.ServiceWindow;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -22,9 +21,14 @@ public class PFSProvider {
|
|||
private int ticketID = -1;
|
||||
|
||||
public PFSProvider(File nspFile, LogPrinter logPrinter) throws Exception{
|
||||
if (nspFile.isDirectory()) {
|
||||
nspFileName = nspFile.getName();
|
||||
nspFile = new File(nspFile.getAbsolutePath() + File.separator + "00");
|
||||
}
|
||||
else
|
||||
nspFileName = nspFile.getName();
|
||||
|
||||
RandomAccessFile randAccessFile = new RandomAccessFile(nspFile, "r");
|
||||
nspFileName = nspFile.getName();
|
||||
|
||||
int filesCount;
|
||||
int header;
|
|
@ -1,9 +1,10 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import nsusbloader.COM.Helpers.NSSplitReader;
|
||||
import org.usb4java.DeviceHandle;
|
||||
import org.usb4java.LibUsb;
|
||||
|
||||
|
@ -18,18 +19,9 @@ import java.util.LinkedHashMap;
|
|||
/**
|
||||
* Tinfoil processing
|
||||
* */
|
||||
class TinFoil implements ITransferModule {
|
||||
private LogPrinter logPrinter;
|
||||
private DeviceHandle handlerNS;
|
||||
private LinkedHashMap<String, File> nspMap;
|
||||
private EFileStatus status = EFileStatus.FAILED;
|
||||
private Task<Void> task;
|
||||
|
||||
class TinFoil extends TransferModule {
|
||||
TinFoil(DeviceHandle handler, LinkedHashMap<String, File> nspMap, Task<Void> task, LogPrinter logPrinter){
|
||||
this.handlerNS = handler;
|
||||
this.nspMap = nspMap;
|
||||
this.task = task;
|
||||
this.logPrinter = logPrinter;
|
||||
super(handler, nspMap, task, logPrinter);
|
||||
|
||||
logPrinter.print("============= TinFoil =============", EMsgType.INFO);
|
||||
|
||||
|
@ -162,44 +154,83 @@ class TinFoil implements ITransferModule {
|
|||
return false;
|
||||
|
||||
try {
|
||||
|
||||
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(nspMap.get(receivedRequestedNSP))); // TODO: refactor?
|
||||
byte[] bufferCurrent ;//= new byte[1048576]; // eq. Allocate 1mb
|
||||
|
||||
if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset){
|
||||
logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
byte[] bufferCurrent; //= new byte[1048576]; // eq. Allocate 1mb
|
||||
|
||||
long currentOffset = 0;
|
||||
// 'End Offset' equal to receivedRangeSize.
|
||||
int readPice = 8388608; // = 8Mb
|
||||
|
||||
while (currentOffset < receivedRangeSize){
|
||||
if ((currentOffset + readPice) >= receivedRangeSize )
|
||||
readPice = Math.toIntExact(receivedRangeSize - currentOffset);
|
||||
//System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+readPice); // NOTE: DEBUG
|
||||
// updating progress bar (if a lot of data requested) START BLOCK
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0);
|
||||
//-----------------------------------------/
|
||||
bufferCurrent = new byte[readPice]; // TODO: not perfect moment, consider refactoring.
|
||||
//---------------! Split files start !---------------
|
||||
if (nspMap.get(receivedRequestedNSP).isDirectory()){
|
||||
NSSplitReader nsSplitReader = new NSSplitReader(nspMap.get(receivedRequestedNSP), receivedRangeSize);
|
||||
if (nsSplitReader.seek(receivedRangeOffset) != receivedRangeOffset){
|
||||
logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bufferedInStream.read(bufferCurrent) != readPice) { // changed since @ v0.3.2
|
||||
logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
||||
return false;
|
||||
while (currentOffset < receivedRangeSize){
|
||||
if ((currentOffset + readPice) >= receivedRangeSize )
|
||||
readPice = Math.toIntExact(receivedRangeSize - currentOffset);
|
||||
//System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+readPice); // NOTE: DEBUG
|
||||
// updating progress bar (if a lot of data requested) START BLOCK
|
||||
//---Tell progress to UI---/
|
||||
logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0);
|
||||
//------------------------/
|
||||
bufferCurrent = new byte[readPice]; // TODO: not perfect moment, consider refactoring.
|
||||
|
||||
if (nsSplitReader.read(bufferCurrent) != readPice) { // changed since @ v0.3.2
|
||||
logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
||||
return false;
|
||||
}
|
||||
//write to USB
|
||||
if (writeUsb(bufferCurrent)) {
|
||||
logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
currentOffset += readPice;
|
||||
}
|
||||
//write to USB
|
||||
if (writeUsb(bufferCurrent)) {
|
||||
logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
currentOffset += readPice;
|
||||
nsSplitReader.close();
|
||||
//---Tell progress to UI---/
|
||||
logPrinter.updateProgress(1.0);
|
||||
//------------------------/
|
||||
}
|
||||
bufferedInStream.close();
|
||||
//-----------------------------------------/
|
||||
logPrinter.updateProgress(1.0);
|
||||
//-----------------------------------------/
|
||||
//---------------! Split files end !---------------
|
||||
//---------------! Regular files start !---------------
|
||||
else {
|
||||
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(nspMap.get(receivedRequestedNSP))); // TODO: refactor?
|
||||
|
||||
if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset) {
|
||||
logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (currentOffset < receivedRangeSize) {
|
||||
if ((currentOffset + readPice) >= receivedRangeSize)
|
||||
readPice = Math.toIntExact(receivedRangeSize - currentOffset);
|
||||
//System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+readPice); // NOTE: DEBUG
|
||||
// updating progress bar (if a lot of data requested) START BLOCK
|
||||
//---Tell progress to UI---/
|
||||
logPrinter.updateProgress((currentOffset + readPice) / (receivedRangeSize / 100.0) / 100.0);
|
||||
//------------------------/
|
||||
bufferCurrent = new byte[readPice]; // TODO: not perfect moment, consider refactoring.
|
||||
|
||||
if (bufferedInStream.read(bufferCurrent) != readPice) { // changed since @ v0.3.2
|
||||
logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
||||
return false;
|
||||
}
|
||||
//write to USB
|
||||
if (writeUsb(bufferCurrent)) {
|
||||
logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL);
|
||||
return false;
|
||||
}
|
||||
currentOffset += readPice;
|
||||
}
|
||||
bufferedInStream.close();
|
||||
//---Tell progress to UI---/
|
||||
logPrinter.updateProgress(1.0);
|
||||
//------------------------/
|
||||
}
|
||||
//---------------! Regular files end !---------------
|
||||
} catch (FileNotFoundException fnfe){
|
||||
logPrinter.print("TF FileNotFoundException:\n "+fnfe.getMessage(), EMsgType.FAIL);
|
||||
fnfe.printStackTrace();
|
||||
|
@ -212,6 +243,10 @@ class TinFoil implements ITransferModule {
|
|||
logPrinter.print("TF ArithmeticException (can't cast 'offset end' - 'offsets current' to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL);
|
||||
ae.printStackTrace();
|
||||
return false;
|
||||
} catch (NullPointerException npe){
|
||||
logPrinter.print("TF NullPointerException (in some moment application didn't find something. Something important.):\n "+npe.getMessage(), EMsgType.FAIL);
|
||||
npe.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -309,13 +344,4 @@ class TinFoil implements ITransferModule {
|
|||
logPrinter.print("TF Execution interrupted", EMsgType.INFO);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status getter
|
||||
* @return status
|
||||
*/
|
||||
@Override
|
||||
public EFileStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
}
|
54
src/main/java/nsusbloader/COM/USB/TransferModule.java
Normal file
54
src/main/java/nsusbloader/COM/USB/TransferModule.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package nsusbloader.COM.USB;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
||||
import org.usb4java.DeviceHandle;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class TransferModule {
|
||||
EFileStatus status = EFileStatus.UNKNOWN;
|
||||
|
||||
LinkedHashMap<String, File> nspMap;
|
||||
LogPrinter logPrinter;
|
||||
DeviceHandle handlerNS;
|
||||
Task<Void> task;
|
||||
|
||||
TransferModule(DeviceHandle handler, LinkedHashMap<String, File> nspMap, Task<Void> task, LogPrinter printer){
|
||||
this.handlerNS = handler;
|
||||
this.nspMap = nspMap;
|
||||
this.task = task;
|
||||
this.logPrinter = printer;
|
||||
|
||||
// Validate split files to be sure that there is no crap
|
||||
logPrinter.print("TransferModule: Validating split files ...", EMsgType.INFO);
|
||||
Iterator<Map.Entry<String, File>> iterator = nspMap.entrySet().iterator();
|
||||
while (iterator.hasNext()){
|
||||
File f = iterator.next().getValue();
|
||||
if (f.isDirectory()){
|
||||
File[] subFiles = f.listFiles((file, name) -> name.matches("[0-9]{2}"));
|
||||
if (subFiles == null || subFiles.length == 0) {
|
||||
logPrinter.print("TransferModule: Removing empty folder: " + f.getName(), EMsgType.WARNING);
|
||||
iterator.remove();
|
||||
}
|
||||
else {
|
||||
Arrays.sort(subFiles, Comparator.comparingInt(file -> Integer.parseInt(file.getName())));
|
||||
|
||||
for (int i = subFiles.length - 2; i > 0 ; i--){
|
||||
if (subFiles[i].length() < subFiles[i-1].length()) {
|
||||
logPrinter.print("TransferModule: Removing strange split file: "+f.getName()+
|
||||
"\n (Chunk sizes of the split file are not the same, but has to be.)", EMsgType.WARNING);
|
||||
iterator.remove();
|
||||
} // what
|
||||
} // a
|
||||
} // nice
|
||||
} // stairway
|
||||
} // here =)
|
||||
logPrinter.print("TransferModule: Validation complete.", EMsgType.INFO);
|
||||
}
|
||||
|
||||
public EFileStatus getStatus(){ return status; }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
|
@ -50,7 +50,7 @@ public class UsbCommunications extends Task<Void> {
|
|||
|
||||
DeviceHandle handler = usbConnect.getHandlerNS();
|
||||
|
||||
ITransferModule module;
|
||||
TransferModule module;
|
||||
|
||||
if (protocol.equals("TinFoil"))
|
||||
module = new TinFoil(handler, nspMap, this, logPrinter);
|
|
@ -1,4 +1,4 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import nsusbloader.ModelControllers.LogPrinter;
|
||||
import nsusbloader.NSLDataTypes.EMsgType;
|
|
@ -1,4 +1,4 @@
|
|||
package nsusbloader.USB;
|
||||
package nsusbloader.COM.USB;
|
||||
|
||||
import org.usb4java.LibUsb;
|
||||
|
|
@ -8,15 +8,15 @@ import javafx.scene.control.*;
|
|||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import javafx.stage.FileChooser;
|
||||
import nsusbloader.*;
|
||||
import nsusbloader.ModelControllers.UpdatesChecker;
|
||||
import nsusbloader.NET.NETCommunications;
|
||||
import nsusbloader.USB.UsbCommunications;
|
||||
import nsusbloader.COM.NET.NETCommunications;
|
||||
import nsusbloader.COM.USB.UsbCommunications;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -28,9 +28,8 @@ public class NSLMainController implements Initializable {
|
|||
@FXML
|
||||
public TextArea logArea; // Accessible from Mediator
|
||||
@FXML
|
||||
private Button selectNspBtn;
|
||||
@FXML
|
||||
private Button uploadStopBtn;
|
||||
private Button selectNspBtn, selectSplitNspBtn, uploadStopBtn;
|
||||
|
||||
private Region btnUpStopImage;
|
||||
@FXML
|
||||
public ProgressBar progressBar; // Accessible from Mediator
|
||||
|
@ -62,6 +61,10 @@ public class NSLMainController implements Initializable {
|
|||
else
|
||||
uploadStopBtn.setDisable(false);
|
||||
selectNspBtn.setOnAction(e-> selectFilesBtnAction());
|
||||
|
||||
selectSplitNspBtn.setOnAction(e-> selectSplitBtnAction());
|
||||
selectSplitNspBtn.getStyleClass().add("buttonSelect");
|
||||
|
||||
uploadStopBtn.setOnAction(e-> uploadBtnAction());
|
||||
|
||||
selectNspBtn.getStyleClass().add("buttonSelect");
|
||||
|
@ -101,7 +104,6 @@ public class NSLMainController implements Initializable {
|
|||
public ResourceBundle getResourceBundle() {
|
||||
return resourceBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide hostServices to Settings tab
|
||||
* */
|
||||
|
@ -109,7 +111,6 @@ public class NSLMainController implements Initializable {
|
|||
|
||||
/**
|
||||
* Functionality for selecting NSP button.
|
||||
* Uses setReady and setNotReady to simplify code readability.
|
||||
* */
|
||||
private void selectFilesBtnAction(){
|
||||
List<File> filesList;
|
||||
|
@ -138,6 +139,28 @@ public class NSLMainController implements Initializable {
|
|||
previouslyOpenedPath = filesList.get(0).getParent();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Functionality for selecting Split NSP button.
|
||||
* */
|
||||
private void selectSplitBtnAction(){
|
||||
File splitFile;
|
||||
DirectoryChooser dirChooser = new DirectoryChooser();
|
||||
dirChooser.setTitle(resourceBundle.getString("btn_OpenFile"));
|
||||
|
||||
File validator = new File(previouslyOpenedPath);
|
||||
if (validator.exists())
|
||||
dirChooser.setInitialDirectory(validator);
|
||||
else
|
||||
dirChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
||||
|
||||
splitFile = dirChooser.showDialog(logArea.getScene().getWindow());
|
||||
|
||||
if (splitFile != null && splitFile.getName().toLowerCase().endsWith(".nsp")) {
|
||||
FrontTabController.tableFilesListController.setFile(splitFile);
|
||||
uploadStopBtn.setDisable(false); // Is it useful?
|
||||
previouslyOpenedPath = splitFile.getParent();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* It's button listener when no transmission executes
|
||||
* */
|
||||
|
@ -210,6 +233,7 @@ public class NSLMainController implements Initializable {
|
|||
public void notifyTransmissionStarted(boolean isTransmissionStarted){
|
||||
if (isTransmissionStarted) {
|
||||
selectNspBtn.setDisable(true);
|
||||
selectSplitNspBtn.setDisable(true);
|
||||
uploadStopBtn.setOnAction(e-> stopBtnAction());
|
||||
|
||||
uploadStopBtn.setText(resourceBundle.getString("btn_Stop"));
|
||||
|
@ -222,6 +246,7 @@ public class NSLMainController implements Initializable {
|
|||
}
|
||||
else {
|
||||
selectNspBtn.setDisable(false);
|
||||
selectSplitNspBtn.setDisable(false);
|
||||
uploadStopBtn.setOnAction(e-> uploadBtnAction());
|
||||
|
||||
uploadStopBtn.setText(resourceBundle.getString("btn_Upload"));
|
||||
|
@ -253,58 +278,22 @@ public class NSLMainController implements Initializable {
|
|||
/**
|
||||
* Drag-n-drop support (drop consumer)
|
||||
* */
|
||||
// TODO: DO SOMETHING WITH THIS
|
||||
@FXML
|
||||
private void handleDrop(DragEvent event){
|
||||
if (MediatorControl.getInstance().getTransferActive()) {
|
||||
event.setDropCompleted(true);
|
||||
return;
|
||||
}
|
||||
List<File> filesDropped = new ArrayList<>();
|
||||
try {
|
||||
if (FrontTabController.getSelectedProtocol().equals("TinFoil") && SettingsTabController.getTfXciNszXczSupport()){
|
||||
for (File fileOrDir : event.getDragboard().getFiles()) {
|
||||
if (fileOrDir.isDirectory()) {
|
||||
for (File file : fileOrDir.listFiles())
|
||||
if ((! file.isDirectory()) && (file.getName().toLowerCase().endsWith(".nsp") ||
|
||||
file.getName().toLowerCase().endsWith(".xci") ||
|
||||
file.getName().toLowerCase().endsWith(".nsz") ||
|
||||
file.getName().toLowerCase().endsWith(".xcz")))
|
||||
filesDropped.add(file);
|
||||
}
|
||||
else if (fileOrDir.getName().toLowerCase().endsWith(".nsp") || fileOrDir.getName().toLowerCase().endsWith(".xci") ||
|
||||
fileOrDir.getName().toLowerCase().endsWith(".nsz") || fileOrDir.getName().toLowerCase().endsWith(".xcz") )
|
||||
filesDropped.add(fileOrDir);
|
||||
List<File> filesDropped = event.getDragboard().getFiles();
|
||||
|
||||
}
|
||||
}// TODO: Somehow improve this double-action function in settings.
|
||||
else if (FrontTabController.getSelectedProtocol().equals("GoldLeaf") && (! SettingsTabController.getNSPFileFilterForGL())){
|
||||
for (File fileOrDir : event.getDragboard().getFiles()) {
|
||||
if (fileOrDir.isDirectory()) {
|
||||
for (File file : fileOrDir.listFiles())
|
||||
if ((! file.isDirectory()) && (! file.isHidden()))
|
||||
filesDropped.add(file);
|
||||
}
|
||||
else
|
||||
filesDropped.add(fileOrDir);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (File fileOrDir : event.getDragboard().getFiles()) {
|
||||
if (fileOrDir.isDirectory()){
|
||||
for (File file : fileOrDir.listFiles())
|
||||
if (file.getName().toLowerCase().endsWith(".nsp") && (! file.isDirectory()))
|
||||
filesDropped.add(file);
|
||||
}
|
||||
else if (fileOrDir.getName().toLowerCase().endsWith(".nsp"))
|
||||
filesDropped.add(fileOrDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SecurityException se){
|
||||
se.printStackTrace();
|
||||
}
|
||||
if (!filesDropped.isEmpty())
|
||||
if (FrontTabController.getSelectedProtocol().equals("TinFoil") && SettingsTabController.getTfXciNszXczSupport())
|
||||
filesDropped.removeIf(file -> ! file.getName().toLowerCase().matches("(.*\\.nsp$)|(.*\\.xci$)|(.*\\.nsz$)|(.*\\.xcz$)"));
|
||||
else if (FrontTabController.getSelectedProtocol().equals("GoldLeaf") && (! SettingsTabController.getNSPFileFilterForGL()))
|
||||
filesDropped.removeIf(file -> (file.isDirectory() && ! file.getName().toLowerCase().matches(".*\\.nsp$")));
|
||||
else
|
||||
filesDropped.removeIf(file -> ! file.getName().toLowerCase().matches(".*\\.nsp$"));
|
||||
|
||||
if ( ! filesDropped.isEmpty() )
|
||||
FrontTabController.tableFilesListController.setFiles(filesDropped);
|
||||
|
||||
event.setDropCompleted(true);
|
||||
|
|
|
@ -3,6 +3,7 @@ package nsusbloader.Controllers;
|
|||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
|
||||
public class NSLRowModel {
|
||||
|
||||
|
@ -16,7 +17,15 @@ public class NSLRowModel {
|
|||
this.nspFile = nspFile;
|
||||
this.markForUpload = checkBoxValue;
|
||||
this.nspFileName = nspFile.getName();
|
||||
this.nspFileSize = nspFile.length();
|
||||
if (nspFile.isFile())
|
||||
this.nspFileSize = nspFile.length();
|
||||
else {
|
||||
File[] subFilesArr = nspFile.listFiles((file, name) -> name.matches("[0-9]{2}"));
|
||||
if (subFilesArr != null) {
|
||||
for (File subFile : subFilesArr)
|
||||
this.nspFileSize += subFile.length();
|
||||
}
|
||||
}
|
||||
this.status = "";
|
||||
}
|
||||
// Model methods start
|
||||
|
|
|
@ -149,6 +149,24 @@ public class NSTableViewController implements Initializable {
|
|||
table.getColumns().add(fileSizeColumn);
|
||||
table.getColumns().add(uploadColumn);
|
||||
}
|
||||
/**
|
||||
* Add single file when user selected it (Split file usually)
|
||||
* */
|
||||
public void setFile(File file){
|
||||
if ( ! rowsObsLst.isEmpty()){
|
||||
List<String> filesAlreayInList = new ArrayList<>();
|
||||
for (NSLRowModel model : rowsObsLst)
|
||||
filesAlreayInList.add(model.getNspFileName());
|
||||
|
||||
if ( ! filesAlreayInList.contains(file.getName()))
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
}
|
||||
else {
|
||||
rowsObsLst.add(new NSLRowModel(file, true));
|
||||
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
|
||||
}
|
||||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Add files when user selected them
|
||||
* */
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Locale;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
public class NSLMain extends Application {
|
||||
public static final String appVersion = "v0.8.2";
|
||||
public static final String appVersion = "v0.9";
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception{
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
||||
|
|
|
@ -24,6 +24,7 @@ public class RainbowHexDump {
|
|||
System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
|
||||
for (byte b: byteArray)
|
||||
System.out.print(String.format("%02x ", b));
|
||||
//System.out.println();
|
||||
System.out.print("\t\t\t"
|
||||
+ new String(byteArray, StandardCharsets.UTF_8)
|
||||
+ "\n");
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package nsusbloader.USB;
|
||||
|
||||
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||
|
||||
public interface ITransferModule {
|
||||
EFileStatus getStatus();
|
||||
}
|
|
@ -57,7 +57,7 @@
|
|||
<Insets left="5.0" right="5.0" top="2.0" />
|
||||
</VBox.margin>
|
||||
</ProgressBar>
|
||||
<HBox alignment="TOP_CENTER" VBox.vgrow="NEVER">
|
||||
<HBox alignment="TOP_CENTER" spacing="3.0" VBox.vgrow="NEVER">
|
||||
<children>
|
||||
<Button fx:id="selectNspBtn" contentDisplay="TOP" mnemonicParsing="false" prefHeight="60.0" text="%btn_OpenFile">
|
||||
<HBox.margin>
|
||||
|
@ -67,6 +67,10 @@
|
|||
<SVGPath content="M 8,0 C 6.8954305,0 6,0.8954305 6,2 v 16 c 0,1.1 0.89,2 2,2 h 12 c 1.104569,0 2,-0.895431 2,-2 V 2 C 22,0.90484721 21.089844,0 20,0 Z m 2.1,1.2 h 7.8 C 18,1.20208 18,1.2002604 18,1.3 v 0.1 c 0,0.095833 0,0.097917 -0.1,0.1 H 10.1 C 10,1.5057292 10,1.5036458 10,1.4 V 1.3 C 10,1.20026 10,1.1981771 10.1,1.2 Z M 8,2 h 12 c 0.303385,0 0.5,0.2044271 0.5,0.5 v 12 C 20.5,14.789959 20.29836,15 20,15 H 8 C 7.7044271,15 7.5,14.803385 7.5,14.5 V 2.5 C 7.5,2.2083333 7.7122396,2 8,2 Z M 2,4 v 18 c 0,1.104569 0.8954305,2 2,2 H 20 V 22 H 4 V 4 Z m 8,12 h 8 l -4,3 z" fill="#289de8" />
|
||||
</graphic>
|
||||
</Button>
|
||||
<Button fx:id="selectSplitNspBtn" contentDisplay="TOP" mnemonicParsing="false" prefHeight="60.0" text="%btn_OpenSplitFile">
|
||||
<graphic>
|
||||
<SVGPath content="M 2.4003906 2 C 1.0683906 2 0 3.1125 0 4.5 L 0 19.5 A 2.4 2.5 0 0 0 2.4003906 22 L 21.599609 22 A 2.4 2.5 0 0 0 24 19.5 L 24 7 C 24 5.6125 22.919609 4.5 21.599609 4.5 L 12 4.5 L 9.5996094 2 L 2.4003906 2 z M 13.193359 10.962891 C 14.113498 10.962891 14.814236 11.348741 15.296875 12.123047 C 15.779514 12.89388 16.021484 13.935113 16.021484 15.244141 C 16.021484 16.556641 15.779514 17.598741 15.296875 18.373047 C 14.814236 19.14388 14.113498 19.529297 13.193359 19.529297 C 12.276693 19.529297 11.575955 19.14388 11.089844 18.373047 C 10.607205 17.598741 10.365234 16.556641 10.365234 15.244141 C 10.365234 13.935113 10.607205 12.89388 11.089844 12.123047 C 11.575955 11.348741 12.276693 10.962891 13.193359 10.962891 z M 19.589844 10.962891 C 20.509983 10.962891 21.21072 11.348741 21.693359 12.123047 C 22.175998 12.89388 22.417969 13.935113 22.417969 15.244141 C 22.417969 16.556641 22.175998 17.598741 21.693359 18.373047 C 21.21072 19.14388 20.509983 19.529297 19.589844 19.529297 C 18.673177 19.529297 17.970486 19.14388 17.484375 18.373047 C 17.001736 17.598741 16.761719 16.556641 16.761719 15.244141 C 16.761719 13.935113 17.001736 12.89388 17.484375 12.123047 C 17.970486 11.348741 18.673177 10.962891 19.589844 10.962891 z M 13.193359 11.769531 C 12.613498 11.769531 12.173177 12.092448 11.871094 12.738281 C 11.56901 13.380642 11.417969 14.195964 11.417969 15.185547 C 11.417969 15.411241 11.423611 15.655599 11.4375 15.916016 C 11.451389 16.176432 11.511068 16.528212 11.615234 16.972656 L 14.412109 12.591797 C 14.235026 12.26888 14.042318 12.052517 13.833984 11.941406 C 13.629123 11.826823 13.415582 11.769531 13.193359 11.769531 z M 19.589844 11.769531 C 19.009983 11.769531 18.567708 12.092448 18.265625 12.738281 C 17.963542 13.380642 17.8125 14.195964 17.8125 15.185547 C 17.8125 15.411241 17.820095 15.655599 17.833984 15.916016 C 17.847873 16.176432 17.907552 16.528212 18.011719 16.972656 L 20.808594 12.591797 C 20.63151 12.26888 20.438802 12.052517 20.230469 11.941406 C 20.025608 11.826823 19.812066 11.769531 19.589844 11.769531 z M 14.761719 13.556641 L 11.984375 17.962891 C 12.133681 18.216363 12.305556 18.406684 12.5 18.535156 C 12.694444 18.660156 12.91276 18.722656 13.152344 18.722656 C 13.812066 18.722656 14.280816 18.355252 14.558594 17.619141 C 14.836372 16.879557 14.974609 16.059462 14.974609 15.160156 C 14.974609 14.604601 14.90408 14.07053 14.761719 13.556641 z M 21.15625 13.556641 L 18.380859 17.962891 C 18.530165 18.216363 18.70204 18.406684 18.896484 18.535156 C 19.090929 18.660156 19.307292 18.722656 19.546875 18.722656 C 20.206597 18.722656 20.675347 18.355252 20.953125 17.619141 C 21.230903 16.879557 21.371094 16.059462 21.371094 15.160156 C 21.371094 14.604601 21.298611 14.07053 21.15625 13.556641 z" fill="#289de8" />
|
||||
</graphic></Button>
|
||||
<Pane HBox.hgrow="ALWAYS" />
|
||||
<Button fx:id="uploadStopBtn" contentDisplay="TOP" mnemonicParsing="false" prefHeight="60.0" text="%btn_Upload">
|
||||
<HBox.margin>
|
||||
|
|
|
@ -38,9 +38,10 @@ windowTitleNewVersionNOTAval=No new versions available
|
|||
windowTitleNewVersionUnknown=Unable to check for new versions
|
||||
windowBodyNewVersionUnknown=Something went wrong\nMaybe internet unavailable, or GitHub is down
|
||||
windowBodyNewVersionNOTAval=You're using the latest version
|
||||
tab2_Cb_AllowXciNszXcz=Allow XCI/NSZ/XCZ files selection for TinFoil
|
||||
tab2_Cb_AllowXciNszXcz=Allow XCI / NSZ / XCZ files selection for TinFoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=Used by applications that support XCI/NSZ/XCZ and utilizes TinFoil transfer protocol. Don't change if not sure.
|
||||
tab2_Lbl_Language=Language
|
||||
windowBodyRestartToApplyLang=Please restart application to apply changes.
|
||||
tab2_Cb_GLshowNspOnly=Show only *.nsp in GoldLeaf.
|
||||
tab2_Cb_UseOldGlVersion=Use old GoldLeaf version
|
||||
btn_OpenSplitFile=Select split NSP
|
||||
|
|
|
@ -38,7 +38,7 @@ windowTitleNewVersionNOTAval=Keine neue Version verf\u00FCgbar
|
|||
windowTitleNewVersionUnknown=Nicht in der Lage nach Updates zu suchen
|
||||
windowBodyNewVersionUnknown=Etwas ist schiefgelaufen\nInternet vielleicht nicht verf\u00FCgbar, oder GitHub nicht verf\u00FCgbar
|
||||
windowBodyNewVersionNOTAval=Du benutzt die neueste Version
|
||||
tab2_Cb_AllowXciNszXcz=Erlaube XCI/NSZ/XCZ-Dateien-Verwendung f\u00FCr Tinfoil
|
||||
tab2_Cb_AllowXciNszXcz=Erlaube XCI- NSZ- XCZ-Dateien-Verwendung f\u00FCr Tinfoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=Von einigen Drittanbietern verwendet, welche XCI/NSZ/XCZ unterst\u00FCtzen, nutzt Tinfoil Transfer Protocol. Nicht \u00E4ndern, wenn unsicher.
|
||||
tab2_Lbl_Language=Sprache
|
||||
windowBodyRestartToApplyLang=Bitte die Applikation neustarten um die Einstellungen zu \u00FCbernehmen.
|
||||
|
|
|
@ -38,7 +38,7 @@ windowTitleNewVersionNOTAval=Aucune nouvelle version disponible
|
|||
windowTitleNewVersionUnknown=Impossible de v\u00E9rifier les nouvelles versions
|
||||
windowBodyNewVersionNOTAval=Vous utilisez la derni\u00E8re version
|
||||
windowBodyNewVersionUnknown=Une erreur s'est produite\nPeut-\u00EAtre des probl\u00E8mes de connexion Internet ou GitHub est en panne
|
||||
tab2_Cb_AllowXciNszXcz=Autoriser la s\u00E9lection de fichiers XCI/NSZ/XCZ pour TinFoil
|
||||
tab2_Cb_AllowXciNszXcz=Autoriser la s\u00E9lection de fichiers XCI / NSZ / XCZ pour TinFoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=Utilis\u00E9 par certaines applications tierces prenant en charge XCI/NSZ/XCZ et utilisant le protocole de transfert TinFoil. Ne changez pas en cas de doute.
|
||||
tab2_Lbl_Language=La langue
|
||||
|
||||
|
|
|
@ -38,6 +38,6 @@ windowTitleNewVersionNOTAval=\uC0C8\uB85C\uC6B4 \uBC84\uC804\uC774 \uC5C6\uC2B5\
|
|||
windowTitleNewVersionUnknown=\uC0C8 \uBC84\uC804\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
|
||||
windowBodyNewVersionUnknown=\uBB38\uC81C\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.\n\uC778\uD130\uB137\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uAC70\uB098 GitHub\uC774 \uB2E4\uC6B4\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
|
||||
windowBodyNewVersionNOTAval=\uCD5C\uC2E0 \uBC84\uC804\uC744 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4.
|
||||
tab2_Cb_AllowXciNszXcz=TinFoil\uC5D0 \uB300\uD55C XCI/NSZ/XCZ \uD30C\uC77C \uC120\uD0DD \uD5C8\uC6A9
|
||||
tab2_Cb_AllowXciNszXcz=TinFoil\uC5D0 \uB300\uD55C XCI / NSZ / XCZ \uD30C\uC77C \uC120\uD0DD \uD5C8\uC6A9
|
||||
tab2_Lbl_AllowXciNszXczDesc=XCI/NSZ/XCZ\uB97C \uC9C0\uC6D0\uD558\uACE0 TinFoil \uC804\uC1A1 \uD504\uB85C\uD1A0\uCF5C\uC744 \uC0AC\uC6A9\uD558\uB294 \uC77C\uBD80 \uD0C0\uC0AC \uC751\uC6A9 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C \uC0AC\uC6A9\uB429\uB2C8\uB2E4. \uD655\uC2E4\uD558\uC9C0 \uC54A\uC73C\uBA74 \uBCC0\uACBD\uD558\uC9C0 \uB9C8\uC2ED\uC2DC\uC624.
|
||||
tab2_Lbl_Language=\uC5B8\uC5B4
|
|
@ -38,10 +38,11 @@ windowTitleNewVersionNOTAval=\u041D\u0435\u0442 \u043D\u043E\u0432\u044B\u0445 \
|
|||
windowTitleNewVersionUnknown=\u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u044B\u0445 \u0432\u0435\u0440\u0441\u0438\u0439
|
||||
windowBodyNewVersionNOTAval=\u0412\u044B \u0443\u0436\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E
|
||||
windowBodyNewVersionUnknown=\u0427\u0442\u043E-\u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A.\n\u041C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043D\u0435\u0442 \u0438\u043D\u0442\u0435\u0440\u043D\u0435\u0442\u0430 \u0438\u043B\u0438 GitHub \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D.
|
||||
tab2_Cb_AllowXciNszXcz=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440 XCI/NSZ/XCZ \u0444\u0430\u0439\u043B\u043E\u0432 \u0434\u043B\u044F TinFoil
|
||||
tab2_Cb_AllowXciNszXcz=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440 XCI / NSZ / XCZ \u0444\u0430\u0439\u043B\u043E\u0432 \u0434\u043B\u044F TinFoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u043C\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442 XCI, NSZ, XCZ \u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044E\u0442 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 TinFoil. \u041D\u0435 \u043C\u0435\u043D\u044F\u0439\u0442\u0435 \u0435\u0441\u043B\u0438 \u043D\u0435 \u0443\u0432\u0435\u0440\u0435\u043D\u044B.
|
||||
tab2_Lbl_Language=\u042F\u0437\u044B\u043A
|
||||
windowBodyRestartToApplyLang=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0447\u0442\u043E\u0431\u044B \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0432\u0441\u0442\u0443\u043F\u0438\u043B\u0438 \u0432 \u0441\u0438\u043B\u0443.
|
||||
tab2_Cb_GLshowNspOnly=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u044C \u0438\u0441\u043A\u043B\u044E\u0447\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0444\u0430\u0439\u043B\u044B *.nsp \u0432 GoldLeaf.
|
||||
tab2_Cb_UseOldGlVersion=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0441\u0442\u0430\u0440\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E GoldLeaf
|
||||
btn_OpenSplitFile=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0440\u0430\u0437\u0431\u0438\u0442\u044B\u0439 NSP
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ windowTitleNewVersionNOTAval=No hay actualizaciones disponibles
|
|||
windowTitleNewVersionUnknown=No fue posible encontrar actualizaciones
|
||||
windowBodyNewVersionUnknown=Algo fall\u00F3\nLa conexi\u00F3n a internet no funciona correctamente, o GitHub est\u00E1 ca\u00EDdo
|
||||
windowBodyNewVersionNOTAval=Est\u00E1s usando la \u00FAltima versi\u00F3n
|
||||
tab2_Cb_AllowXciNszXcz=Permite la selecci\u00F3n de archivos XCI/NSZ/XCZ para Tinfoil
|
||||
tab2_Cb_AllowXciNszXcz=Permite la selecci\u00F3n de archivos XCI / NSZ / XCZ para Tinfoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=Usado por algunas aplicaciones de terceros que soportan XCI/NSZ/XCZ y que utilizan el protocolo de transferencia de Tinfoil. Si no est\u00E1 seguro no cambie la opci\u00F3n.
|
||||
tab2_Lbl_Language=Idioma
|
||||
windowBodyRestartToApplyLang=Por favor, reinicie el programa para aplicar los cambios.
|
||||
|
|
|
@ -38,9 +38,10 @@ windowTitleNewVersionNOTAval=\u041D\u0435\u043C\u0430\u0454 \u043D\u043E\u0432\u
|
|||
windowTitleNewVersionUnknown=\u041D\u0435\u043C\u043E\u0436\u043B\u0438\u0432\u043E \u043F\u0435\u0440\u0435\u0432\u0456\u0440\u0438\u0442\u0438 \u043D\u0430\u044F\u0432\u043D\u0456\u0441\u0442\u044C \u043D\u043E\u0432\u0438\u0445 \u0432\u0435\u0440\u0441\u0456\u0439
|
||||
windowBodyNewVersionNOTAval=\u0412\u0438 \u0432\u0436\u0435 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454\u0442\u0435 \u043E\u0441\u0442\u0430\u043D\u043D\u044E \u0432\u0435\u0440\u0441\u0456\u044E
|
||||
windowBodyNewVersionUnknown=\u0429\u043E\u0441\u044C \u043F\u0456\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A.\n\u041C\u043E\u0436\u043B\u0438\u0432\u043E, \u0456\u043D\u0442\u0435\u0440\u043D\u0435\u0442 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439, \u0430\u0431\u043E GitHub \u043D\u0435 \u043F\u0440\u0430\u0446\u044E\u0454.
|
||||
tab2_Cb_AllowXciNszXcz=\u0414\u043E\u0437\u0432\u043E\u043B\u0438\u0442\u0438 \u0432\u0438\u0431\u0456\u0440 XCI/NSZ/XCZ \u0444\u0430\u0439\u043B\u0456\u0432 \u0434\u043B\u044F \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u0443 TinFoil
|
||||
tab2_Cb_AllowXciNszXcz=\u0414\u043E\u0437\u0432\u043E\u043B\u0438\u0442\u0438 \u0432\u0438\u0431\u0456\u0440 XCI / NSZ / XCZ \u0444\u0430\u0439\u043B\u0456\u0432 \u0434\u043B\u044F \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u043D\u043D\u044F \u0443 TinFoil
|
||||
tab2_Lbl_AllowXciNszXczDesc=\u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0454\u0442\u044C\u0441\u044F \u0434\u043E\u0434\u0430\u0442\u043A\u0430\u043C\u0438, \u0449\u043E \u043C\u0430\u044E\u0442\u044C \u043F\u0456\u0434\u0442\u0440\u0438\u043C\u043A\u0443 XCI, NSZ, XCZ \u0456 \u0432\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u044E\u0442\u044C \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0456 TinFoil. \u041D\u0435 \u0437\u043C\u0456\u043D\u044E\u0439\u0442\u0435, \u044F\u043A\u0449\u043E \u043D\u0435 \u0432\u043F\u0435\u0432\u043D\u0435\u043D\u0456.
|
||||
tab2_Lbl_Language=\u041C\u043E\u0432\u0430
|
||||
windowBodyRestartToApplyLang=\u0411\u0443\u0434\u044C \u043B\u0430\u0441\u043A\u0430, \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0456\u0442\u044C \u0434\u043E\u0434\u0430\u0442\u043E\u043A \u0449\u043E\u0431 \u0437\u043C\u0456\u043D\u0438 \u0432\u0441\u0442\u0443\u043F\u0438\u043B\u0438 \u0432 \u0441\u0438\u043B\u0443.
|
||||
tab2_Cb_GLshowNspOnly=\u0412\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0430\u0442\u0438 \u0432\u0438\u043A\u043B\u044E\u0447\u043D\u043E *.nsp \u0444\u0430\u0439\u043B\u0438 \u0443 GoldLeaf.
|
||||
tab2_Cb_UseOldGlVersion=\u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0432\u0430\u0442\u0438 \u0441\u0442\u0430\u0440\u0443 \u0432\u0435\u0440\u0441\u0456\u044E GoldLeaf
|
||||
tab2_Cb_UseOldGlVersion=\u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u043E\u0432\u0443\u0432\u0430\u0442\u0438 \u0441\u0442\u0430\u0440\u0443 \u0432\u0435\u0440\u0441\u0456\u044E GoldLeaf
|
||||
btn_OpenSplitFile=\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0440\u043E\u0437\u0431\u0438\u0442\u0438\u0439 NSP
|
Loading…
Add table
Add a link
Reference in a new issue