mirror of
https://github.com/developersu/ns-usbloader.git
synced 2025-05-21 18:55:23 -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();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue