Solve - #87. Break LogPrinterGui

This commit is contained in:
Dmitry Isaenko 2021-08-09 22:47:52 +03:00
parent 79c519b1f3
commit 1176ad9e83
32 changed files with 1348 additions and 738 deletions

View file

@ -0,0 +1,102 @@
/*
Copyright 2019-2021 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Controllers;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
public class BlockListViewController implements Initializable {
@FXML
private ListView<File> splitMergeListView;
private ObservableList<File> filesList;
private ResourceBundle resourceBundle;
private static class FileListCell extends ListCell<File>{
@Override
public void updateItem(File file, boolean isEmpty){
super.updateItem(file, isEmpty);
if (file == null || isEmpty){
setText(null);
return;
}
String fileName = file.getName();
setText(fileName);
}
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
setFilesListView();
filesList = splitMergeListView.getItems();
}
private void setFilesListView(){
splitMergeListView.setCellFactory(fileListView -> {
ListCell<File> item = new FileListCell();
setContextMenuToItem(item);
return item;
});
}
private <T> void setContextMenuToItem(ListCell<T> item){
ContextMenu contextMenu = new ContextMenu();
MenuItem deleteMenuItem = new MenuItem(resourceBundle.getString("tab1_table_contextMenu_Btn_BtnDelete"));
deleteMenuItem.setOnAction(actionEvent -> {
filesList.remove(item.getItem());
splitMergeListView.refresh();
});
MenuItem deleteAllMenuItem = new MenuItem(resourceBundle.getString("tab1_table_contextMenu_Btn_DeleteAll"));
deleteAllMenuItem.setOnAction(actionEvent -> {
filesList.clear();
splitMergeListView.refresh();
});
contextMenu.getItems().addAll(deleteMenuItem, deleteAllMenuItem);
item.setContextMenu(contextMenu);
}
public void add(File file){
if (filesList.contains(file))
return;
filesList.add(file);
}
public void addAll(List<File> files){
for (File file : files) {
add(file);
}
}
public ObservableList<File> getItems(){ return filesList; }
public void clear(){
filesList.clear();
splitMergeListView.refresh();
}
}

View file

@ -46,7 +46,7 @@ public class NSLMainController implements Initializable {
private Tab GamesTabHolder, RCMTabHolder, SMTabHolder; private Tab GamesTabHolder, RCMTabHolder, SMTabHolder;
@FXML @FXML
private GamesController GamesTabController; // Accessible from Mediator | todo: incapsulate private GamesController GamesTabController;
@FXML @FXML
private SettingsController SettingsTabController; private SettingsController SettingsTabController;
@FXML @FXML
@ -69,30 +69,32 @@ public class NSLMainController implements Initializable {
MediatorControl.getInstance().setController(this); MediatorControl.getInstance().setController(this);
if (AppPreferences.getInstance().getAutoCheckUpdates()){ if (AppPreferences.getInstance().getAutoCheckUpdates()){
Task<List<String>> updTask = new UpdatesChecker(); checkForUpdates();
updTask.setOnSucceeded(event->{
List<String> result = updTask.getValue();
if (result != null){
if (!result.get(0).isEmpty()) {
SettingsTabController.getGenericSettings().setNewVersionLink(result.get(0));
ServiceWindow.getInfoNotification(
resourceBundle.getString("windowTitleNewVersionAval"),
resourceBundle.getString("windowTitleNewVersionAval") + ": " + result.get(0) + "\n\n" + result.get(1));
}
}
else
ServiceWindow.getInfoNotification(
resourceBundle.getString("windowTitleNewVersionUnknown"),
resourceBundle.getString("windowBodyNewVersionUnknown"));
});
Thread updates = new Thread(updTask);
updates.setDaemon(true);
updates.start();
} }
openLastOpenedTab(); openLastOpenedTab();
} }
private void checkForUpdates(){
Task<List<String>> updTask = new UpdatesChecker();
updTask.setOnSucceeded(event->{
List<String> result = updTask.getValue();
if (result != null){
if (!result.get(0).isEmpty()) {
SettingsTabController.getGenericSettings().setNewVersionLink(result.get(0));
ServiceWindow.getInfoNotification(
resourceBundle.getString("windowTitleNewVersionAval"),
resourceBundle.getString("windowTitleNewVersionAval") + ": " + result.get(0) + "\n\n" + result.get(1));
}
}
else
ServiceWindow.getInfoNotification(
resourceBundle.getString("windowTitleNewVersionUnknown"),
resourceBundle.getString("windowBodyNewVersionUnknown"));
});
Thread updates = new Thread(updTask);
updates.setDaemon(true);
updates.start();
}
/** /**
* Get resources * Get resources
* TODO: Find better solution; used in UsbCommunications() -> GL -> SelectFile command * TODO: Find better solution; used in UsbCommunications() -> GL -> SelectFile command

View file

@ -18,6 +18,7 @@
*/ */
package nsusbloader.Controllers; package nsusbloader.Controllers;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.*;
@ -33,11 +34,11 @@ import nsusbloader.MediatorControl;
import nsusbloader.ModelControllers.CancellableRunnable; import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.NSLDataTypes.EModule; import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.ServiceWindow; import nsusbloader.ServiceWindow;
import nsusbloader.Utilities.splitmerge.MergeTask; import nsusbloader.Utilities.splitmerge.SplitMergeTaskExecutor;
import nsusbloader.Utilities.splitmerge.SplitTask;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class SplitMergeController implements Initializable { public class SplitMergeController implements Initializable {
@ -53,40 +54,39 @@ public class SplitMergeController implements Initializable {
changeSaveToBtn, changeSaveToBtn,
convertBtn; convertBtn;
@FXML @FXML
private Label fileFolderLabelLbl, private Label saveToPathLbl,
fileFolderActualPathLbl,
saveToPathLbl,
statusLbl; statusLbl;
@FXML
private BlockListViewController BlockListViewController;
private ResourceBundle resourceBundle; private ResourceBundle resourceBundle;
private Region convertRegion; private Region convertRegion;
private Thread smThread; private Thread smThread;
private CancellableRunnable smTask; private Runnable smTask;
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle; this.resourceBundle = resourceBundle;
convertRegion = new Region(); convertRegion = new Region();
convertBtn.setGraphic(convertRegion); convertBtn.setGraphic(convertRegion);
convertBtn.disableProperty().bind(Bindings.isEmpty(BlockListViewController.getItems()));
splitRad.setOnAction((actionEvent -> { splitRad.setOnAction((actionEvent -> {
statusLbl.setText(""); statusLbl.setText("");
convertRegion.getStyleClass().clear(); convertRegion.getStyleClass().clear();
convertRegion.getStyleClass().add("regionSplitToOne"); convertRegion.getStyleClass().add("regionSplitToOne");
fileFolderLabelLbl.setText(resourceBundle.getString("tabSplMrg_Txt_File"));
selectFileFolderBtn.setText(resourceBundle.getString("tabSplMrg_Btn_SelectFile")); selectFileFolderBtn.setText(resourceBundle.getString("tabSplMrg_Btn_SelectFile"));
fileFolderActualPathLbl.setText(""); BlockListViewController.clear();
convertBtn.setDisable(true);
})); }));
mergeRad.setOnAction((actionEvent -> { mergeRad.setOnAction((actionEvent -> {
statusLbl.setText(""); statusLbl.setText("");
convertRegion.getStyleClass().clear(); convertRegion.getStyleClass().clear();
convertRegion.getStyleClass().add("regionOneToSplit"); convertRegion.getStyleClass().add("regionOneToSplit");
fileFolderLabelLbl.setText(resourceBundle.getString("tabSplMrg_Txt_Folder"));
selectFileFolderBtn.setText(resourceBundle.getString("tabSplMrg_Btn_SelectFolder")); selectFileFolderBtn.setText(resourceBundle.getString("tabSplMrg_Btn_SelectFolder"));
fileFolderActualPathLbl.setText(""); BlockListViewController.clear();
convertBtn.setDisable(true);
})); }));
if (AppPreferences.getInstance().getSplitMergeType() == 0) if (AppPreferences.getInstance().getSplitMergeType() == 0)
@ -110,32 +110,27 @@ public class SplitMergeController implements Initializable {
selectFileFolderBtn.setOnAction(actionEvent -> { selectFileFolderBtn.setOnAction(actionEvent -> {
statusLbl.setText(""); statusLbl.setText("");
List<File> alreadyAddedFiles = BlockListViewController.getItems();
if (splitRad.isSelected()) { if (splitRad.isSelected()) {
FileChooser fc = new FileChooser(); FileChooser fc = new FileChooser();
fc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFile")); fc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFile"));
if (! fileFolderActualPathLbl.getText().isEmpty()){ if (! alreadyAddedFiles.isEmpty()){
File temporaryFile = new File(fileFolderActualPathLbl.getText()).getParentFile(); String recentLocation = FilesHelper.getRealFolder(alreadyAddedFiles.get(0).getParentFile().getAbsolutePath());
if (temporaryFile != null && temporaryFile.exists()) fc.setInitialDirectory(new File(recentLocation));
fc.setInitialDirectory(temporaryFile);
else
fc.setInitialDirectory(new File(System.getProperty("user.home")));
} }
else else
fc.setInitialDirectory(new File(System.getProperty("user.home"))); fc.setInitialDirectory(new File(System.getProperty("user.home")));
File fileFile = fc.showOpenDialog(changeSaveToBtn.getScene().getWindow()); List<File> files = fc.showOpenMultipleDialog(changeSaveToBtn.getScene().getWindow());
if (fileFile == null) if (files == null || files.isEmpty())
return; return;
fileFolderActualPathLbl.setText(fileFile.getAbsolutePath()); this.BlockListViewController.addAll(files);
} }
else{ else{
DirectoryChooser dc = new DirectoryChooser(); DirectoryChooser dc = new DirectoryChooser();
dc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFolder")); dc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFolder"));
if (! fileFolderActualPathLbl.getText().isEmpty()){ if (! alreadyAddedFiles.isEmpty()){
File temporaryFile = new File(fileFolderActualPathLbl.getText()); String recentLocation = FilesHelper.getRealFolder(alreadyAddedFiles.get(0).getParentFile().getAbsolutePath());
if (temporaryFile.exists()) dc.setInitialDirectory(new File(recentLocation));
dc.setInitialDirectory(temporaryFile);
else
dc.setInitialDirectory(new File(System.getProperty("user.home")));
} }
else else
dc.setInitialDirectory(new File(System.getProperty("user.home"))); dc.setInitialDirectory(new File(System.getProperty("user.home")));
@ -143,9 +138,8 @@ public class SplitMergeController implements Initializable {
File folderFile = dc.showDialog(changeSaveToBtn.getScene().getWindow()); File folderFile = dc.showDialog(changeSaveToBtn.getScene().getWindow());
if (folderFile == null) if (folderFile == null)
return; return;
fileFolderActualPathLbl.setText(folderFile.getAbsolutePath()); this.BlockListViewController.add(folderFile);
} }
convertBtn.setDisable(false);
}); });
convertBtn.setOnAction(actionEvent -> setConvertBtnAction()); convertBtn.setOnAction(actionEvent -> setConvertBtnAction());
@ -192,7 +186,7 @@ public class SplitMergeController implements Initializable {
* */ * */
private void stopBtnAction(){ private void stopBtnAction(){
if (smThread != null && smThread.isAlive()) { if (smThread != null && smThread.isAlive()) {
smTask.cancel(); smThread.interrupt();
} }
} }
/** /**
@ -209,9 +203,9 @@ public class SplitMergeController implements Initializable {
} }
if (splitRad.isSelected()) if (splitRad.isSelected())
smTask = new SplitTask(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); smTask = new SplitMergeTaskExecutor(true, BlockListViewController.getItems(), saveToPathLbl.getText());
else else
smTask = new MergeTask(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); smTask = new SplitMergeTaskExecutor(false, BlockListViewController.getItems(), saveToPathLbl.getText());
smThread = new Thread(smTask); smThread = new Thread(smTask);
smThread.setDaemon(true); smThread.setDaemon(true);
smThread.start(); smThread.start();
@ -230,14 +224,16 @@ public class SplitMergeController implements Initializable {
* */ * */
@FXML @FXML
private void handleDrop(DragEvent event) { private void handleDrop(DragEvent event) {
File fileDrpd = event.getDragboard().getFiles().get(0); List<File> files = event.getDragboard().getFiles();
File firstFile = files.get(0);
if (fileDrpd.isDirectory()) if (firstFile.isDirectory())
mergeRad.fire(); mergeRad.fire();
else else
splitRad.fire(); splitRad.fire();
fileFolderActualPathLbl.setText(fileDrpd.getAbsolutePath());
convertBtn.setDisable(false); this.BlockListViewController.addAll(files);
event.setDropCompleted(true); event.setDropCompleted(true);
event.consume(); event.consume();
} }

View file

@ -26,8 +26,8 @@ import java.io.File;
import java.util.HashMap; import java.util.HashMap;
public interface ILogPrinter { public interface ILogPrinter {
void print(String message, EMsgType type); void print(String message, EMsgType type) throws InterruptedException;
void updateProgress(Double value); void updateProgress(Double value) throws InterruptedException;
void update(HashMap<String, File> nspMap, EFileStatus status); void update(HashMap<String, File> nspMap, EFileStatus status);
void update(File file, EFileStatus status); void update(File file, EFileStatus status);
void updateOneLinerStatus(boolean status); void updateOneLinerStatus(boolean status);

View file

@ -32,9 +32,11 @@ public class LogPrinterGui implements ILogPrinter {
private final MessagesConsumer msgConsumer; private final MessagesConsumer msgConsumer;
private final BlockingQueue<String> msgQueue; private final BlockingQueue<String> msgQueue;
private final BlockingQueue<Double> progressQueue; private final BlockingQueue<Double> progressQueue;
private final HashMap<String, EFileStatus> statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap private final HashMap<String, EFileStatus> statusMap;
private final AtomicBoolean oneLinerStatus; private final AtomicBoolean oneLinerStatus;
/* TODO: Rewrite 'print()' implementation everywhere */
LogPrinterGui(EModule whoIsAsking){ LogPrinterGui(EModule whoIsAsking){
this.msgQueue = new LinkedBlockingQueue<>(); this.msgQueue = new LinkedBlockingQueue<>();
this.progressQueue = new LinkedBlockingQueue<>(); this.progressQueue = new LinkedBlockingQueue<>();
@ -47,38 +49,30 @@ public class LogPrinterGui implements ILogPrinter {
* This is what will print to textArea of the application. * This is what will print to textArea of the application.
* */ * */
@Override @Override
public void print(String message, EMsgType type){ public void print(String message, EMsgType type) throws InterruptedException{
try { switch (type){
switch (type){ case PASS:
case PASS: msgQueue.put("[ PASS ] "+message+"\n");
msgQueue.put("[ PASS ] "+message+"\n"); break;
break; case FAIL:
case FAIL: msgQueue.put("[ FAIL ] "+message+"\n");
msgQueue.put("[ FAIL ] "+message+"\n"); break;
break; case INFO:
case INFO: msgQueue.put("[ INFO ] "+message+"\n");
msgQueue.put("[ INFO ] "+message+"\n"); break;
break; case WARNING:
case WARNING: msgQueue.put("[ WARN ] "+message+"\n");
msgQueue.put("[ WARN ] "+message+"\n"); break;
break; default:
default: msgQueue.put(message);
msgQueue.put(message);
}
}
catch (InterruptedException ie){
ie.printStackTrace();
} }
} }
/** /**
* Update progress for progress bar * Update progress for progress bar
* */ * */
@Override @Override
public void updateProgress(Double value) { public void updateProgress(Double value) throws InterruptedException {
try { progressQueue.put(value);
progressQueue.put(value);
}
catch (InterruptedException ignored){} // TODO: Do something with this
} }
/** /**
* When we're done - update status * When we're done - update status

View file

@ -42,7 +42,7 @@ public class MessagesConsumer extends AnimationTimer {
private final NSTableViewController tableViewController; private final NSTableViewController tableViewController;
private final EModule appModuleType; private final EModule appModuleType;
private AtomicBoolean oneLinerStatus; private final AtomicBoolean oneLinerStatus;
private boolean isInterrupted; private boolean isInterrupted;
@ -50,7 +50,7 @@ public class MessagesConsumer extends AnimationTimer {
BlockingQueue<String> msgQueue, BlockingQueue<String> msgQueue,
BlockingQueue<Double> progressQueue, BlockingQueue<Double> progressQueue,
HashMap<String, EFileStatus> statusMap, HashMap<String, EFileStatus> statusMap,
AtomicBoolean oneLinerStatus) { AtomicBoolean oneLinerStatus){
this.appModuleType = appModuleType; this.appModuleType = appModuleType;
this.isInterrupted = false; this.isInterrupted = false;
@ -72,15 +72,15 @@ public class MessagesConsumer extends AnimationTimer {
} }
@Override @Override
public void handle(long l) { public void handle(long l){
ArrayList<String> messages = new ArrayList<>(); ArrayList<String> messages = new ArrayList<>();
int msgRecieved = msgQueue.drainTo(messages); int msgReceived = msgQueue.drainTo(messages);
if (msgRecieved > 0) if (msgReceived > 0)
messages.forEach(logsArea::appendText); messages.forEach(logsArea::appendText);
ArrayList<Double> progress = new ArrayList<>(); ArrayList<Double> progress = new ArrayList<>();
int progressRecieved = progressQueue.drainTo(progress); int progressReceived = progressQueue.drainTo(progress);
if (progressRecieved > 0) { if (progressReceived > 0) {
progress.forEach(prg -> { progress.forEach(prg -> {
if (prg != 1.0) if (prg != 1.0)
progressBar.setProgress(prg); progressBar.setProgress(prg);
@ -89,29 +89,31 @@ public class MessagesConsumer extends AnimationTimer {
}); });
} }
if (isInterrupted) { // It's safe 'cuz it's could't be interrupted while HashMap populating if (isInterrupted) // It's safe 'cuz it's could't be interrupted while HashMap populating
MediatorControl.getInstance().setBgThreadActive(false, appModuleType); updateElementsAndStop();
progressBar.setProgress(0.0); }
if (statusMap.size() > 0){ private void updateElementsAndStop(){
for (String key : statusMap.keySet()) MediatorControl.getInstance().setBgThreadActive(false, appModuleType);
tableViewController.setFileStatus(key, statusMap.get(key)); progressBar.setProgress(0.0);
}
switch (appModuleType){ if (statusMap.size() > 0){
case RCM: for (String key : statusMap.keySet())
MediatorControl.getInstance().getRcmController().setOneLineStatus(oneLinerStatus.get()); tableViewController.setFileStatus(key, statusMap.get(key));
break;
case NXDT:
MediatorControl.getInstance().getNxdtController().setOneLineStatus(oneLinerStatus.get());
break;
case SPLIT_MERGE_TOOL:
MediatorControl.getInstance().getSplitMergeController().setOneLineStatus(oneLinerStatus.get());
break;
}
this.stop();
} }
switch (appModuleType){
case RCM:
MediatorControl.getInstance().getRcmController().setOneLineStatus(oneLinerStatus.get());
break;
case NXDT:
MediatorControl.getInstance().getNxdtController().setOneLineStatus(oneLinerStatus.get());
break;
case SPLIT_MERGE_TOOL:
MediatorControl.getInstance().getSplitMergeController().setOneLineStatus(oneLinerStatus.get());
break;
}
this.stop();
} }
public void interrupt(){ public void interrupt(){

View file

@ -72,8 +72,8 @@ public class Rcm implements Runnable{
@Override @Override
public void run() { public void run() {
logPrinter.print("Selected: "+filePath, EMsgType.INFO); print("Selected: "+filePath, EMsgType.INFO);
logPrinter.print("=============== RCM ===============", EMsgType.INFO); print("=============== RCM ===============", EMsgType.INFO);
ECurrentOS ecurrentOS; ECurrentOS ecurrentOS;
String realOsName = System.getProperty("os.name").toLowerCase().replace(" ", ""); String realOsName = System.getProperty("os.name").toLowerCase().replace(" ", "");
@ -85,11 +85,11 @@ public class Rcm implements Runnable{
ecurrentOS = ECurrentOS.lin; ecurrentOS = ECurrentOS.lin;
else else
ecurrentOS = ECurrentOS.unsupported; ecurrentOS = ECurrentOS.unsupported;
logPrinter.print("Found your OS: "+System.getProperty("os.name"), EMsgType.PASS); print("Found your OS: "+System.getProperty("os.name"), EMsgType.PASS);
if (! ecurrentOS.equals(ECurrentOS.mac)){ if (! ecurrentOS.equals(ECurrentOS.mac)){
if (! RcmSmash.isSupported()){ if (! RcmSmash.isSupported()){
logPrinter.print("Unfortunately your platform '"+System.getProperty("os.name")+ print("Unfortunately your platform '"+System.getProperty("os.name")+
"' of '"+System.getProperty("os.arch")+"' is not supported :("+ "' of '"+System.getProperty("os.arch")+"' is not supported :("+
"\n But you could file a bug with request."+ "\n But you could file a bug with request."+
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
@ -124,14 +124,14 @@ public class Rcm implements Runnable{
// Send payload // Send payload
for (int i=0; i < fullPayload.length / 4096 ; i++){ for (int i=0; i < fullPayload.length / 4096 ; i++){
if (writeUsb(Arrays.copyOfRange(fullPayload, i*4096, (i+1)*4096))){ if (writeUsb(Arrays.copyOfRange(fullPayload, i*4096, (i+1)*4096))){
logPrinter.print("Failed to sent payload ["+i+"]"+ print("Failed to sent payload ["+i+"]"+
"\n\n Execution stopped.", EMsgType.FAIL); "\n\n Execution stopped.", EMsgType.FAIL);
usbConnect.close(); usbConnect.close();
logPrinter.close(); logPrinter.close();
return; return;
} }
} }
logPrinter.print("Information sent to NS.", EMsgType.PASS); print("Information sent to NS.", EMsgType.PASS);
if (ecurrentOS.equals(ECurrentOS.mac)){ if (ecurrentOS.equals(ECurrentOS.mac)){
if (smashMacOS()){ if (smashMacOS()){
@ -149,7 +149,7 @@ public class Rcm implements Runnable{
retval = RcmSmash.smashWindows(); retval = RcmSmash.smashWindows();
else { else {
// ( ?_?) // ( ?_?)
logPrinter.print("Failed to smash the stack since your OS is not supported. Please report this issue."+ print("Failed to smash the stack since your OS is not supported. Please report this issue."+
"\n\n Execution stopped and failed. And it's strange.", EMsgType.FAIL); "\n\n Execution stopped and failed. And it's strange.", EMsgType.FAIL);
usbConnect.close(); usbConnect.close();
logPrinter.close(); logPrinter.close();
@ -157,18 +157,27 @@ public class Rcm implements Runnable{
} }
if (retval != 0){ if (retval != 0){
logPrinter.print("Failed to smash the stack ("+retval+")"+ print("Failed to smash the stack ("+retval+")"+
"\n\n Execution stopped and failed.", EMsgType.FAIL); "\n\n Execution stopped and failed.", EMsgType.FAIL);
usbConnect.close(); usbConnect.close();
logPrinter.close(); logPrinter.close();
return; return;
} }
} }
logPrinter.print(".:: Payload complete ::.", EMsgType.PASS); print(".:: Payload complete ::.", EMsgType.PASS);
usbConnect.close(); usbConnect.close();
logPrinter.updateOneLinerStatus(true); logPrinter.updateOneLinerStatus(true);
logPrinter.close(); logPrinter.close();
} }
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException intr){
intr.printStackTrace();
}
}
/** /**
* Prepare the 'big' or full-size byte-buffer that is actually is a payload that we're about to use. * Prepare the 'big' or full-size byte-buffer that is actually is a payload that we're about to use.
* @return false for issues * @return false for issues
@ -179,7 +188,7 @@ public class Rcm implements Runnable{
// 126296 b <- biggest size per CTCaer; 16384 selected randomly as minimum threshold. It's probably wrong. // 126296 b <- biggest size per CTCaer; 16384 selected randomly as minimum threshold. It's probably wrong.
if (pldrFile.length() > 126296 || pldrFile.length() < 16384) { if (pldrFile.length() > 126296 || pldrFile.length() < 16384) {
logPrinter.print("File size of this payload looks wired. It's "+pldrFile.length()+" bytes."+ print("File size of this payload looks wired. It's "+pldrFile.length()+" bytes."+
"\n 1. Double-check that you're using the right payload." + "\n 1. Double-check that you're using the right payload." +
"\n 2. Please report this issue in case you're sure that you're doing everything right." + "\n 2. Please report this issue in case you're sure that you're doing everything right." +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
@ -194,7 +203,7 @@ public class Rcm implements Runnable{
totalSize += 4096; totalSize += 4096;
// Double-check // Double-check
if (totalSize > 0x30298){ if (totalSize > 0x30298){
logPrinter.print("File size of the payload is too big. Comparing to maximum size, it's greater to "+(totalSize - 0x30298)+" bytes!"+ print("File size of the payload is too big. Comparing to maximum size, it's greater to "+(totalSize - 0x30298)+" bytes!"+
"\n 1. Double-check that you're using the right payload." + "\n 1. Double-check that you're using the right payload." +
"\n 2. Please report this issue in case you're sure that you're doing everything right." + "\n 2. Please report this issue in case you're sure that you're doing everything right." +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); // Occurs: never. I'm too lazy to check. "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); // Occurs: never. I'm too lazy to check.
@ -209,7 +218,7 @@ public class Rcm implements Runnable{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pldrFile)); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pldrFile));
int readSize; int readSize;
if ((readSize = bis.read(dataPldFile)) != pldFileSize){ if ((readSize = bis.read(dataPldFile)) != pldFileSize){
logPrinter.print("Failed to retrieve data from payload file." + print("Failed to retrieve data from payload file." +
"\n Got only "+readSize+" bytes while "+pldFileSize+" expected." + "\n Got only "+readSize+" bytes while "+pldFileSize+" expected." +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
bis.close(); bis.close();
@ -218,7 +227,7 @@ public class Rcm implements Runnable{
bis.close(); bis.close();
} }
catch (Exception e){ catch (Exception e){
logPrinter.print("Failed to retrieve data from payload file: " +e.getMessage()+ print("Failed to retrieve data from payload file: " +e.getMessage()+
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
return true; return true;
} }
@ -241,7 +250,7 @@ public class Rcm implements Runnable{
IntBuffer readBufTransferred = IntBuffer.allocate(1); IntBuffer readBufTransferred = IntBuffer.allocate(1);
int result = LibUsb.bulkTransfer(handler, (byte) 0x81, readBuffer, readBufTransferred, 1000); int result = LibUsb.bulkTransfer(handler, (byte) 0x81, readBuffer, readBufTransferred, 1000);
if (result != LibUsb.SUCCESS) { if (result != LibUsb.SUCCESS) {
logPrinter.print("Unable to get device ID" + print("Unable to get device ID" +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); "\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
return true; return true;
} }
@ -251,7 +260,7 @@ public class Rcm implements Runnable{
StringBuilder idStrBld = new StringBuilder("Found device with ID: "); StringBuilder idStrBld = new StringBuilder("Found device with ID: ");
for (byte b: receivedBytes) for (byte b: receivedBytes)
idStrBld.append(String.format("%02x ", b)); idStrBld.append(String.format("%02x ", b));
logPrinter.print(idStrBld.toString(), EMsgType.PASS); print(idStrBld.toString(), EMsgType.PASS);
return false; return false;
} }
/** /**
@ -269,13 +278,13 @@ public class Rcm implements Runnable{
if (writeBufTransferred.get() == 4096) if (writeBufTransferred.get() == 4096)
return false; return false;
logPrinter.print("RCM Data transfer issue [write]" + print("RCM Data transfer issue [write]" +
"\n Requested: " + message.length + "\n Requested: " + message.length +
"\n Transferred: " + writeBufTransferred.get()+ "\n Transferred: " + writeBufTransferred.get()+
"\n\n Execution stopped.", EMsgType.FAIL); "\n\n Execution stopped.", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print("RCM Data transfer issue [write]" + print("RCM Data transfer issue [write]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result) + "\n Returned: " + UsbErrorCodes.getErrCode(result) +
"\n\n Execution stopped.", EMsgType.FAIL); "\n\n Execution stopped.", EMsgType.FAIL);
return true; return true;

View file

@ -38,8 +38,8 @@ public class NxdtTask extends CancellableRunnable {
@Override @Override
public void run() { public void run() {
logPrinter.print("Save to location: "+ saveToLocation, EMsgType.INFO); print("Save to location: "+ saveToLocation, EMsgType.INFO);
logPrinter.print("=============== nxdumptool ===============", EMsgType.INFO); print("=============== nxdumptool ===============", EMsgType.INFO);
UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter); UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter);
@ -54,13 +54,22 @@ public class NxdtTask extends CancellableRunnable {
new NxdtUsbAbi1(handler, logPrinter, saveToLocation, this); new NxdtUsbAbi1(handler, logPrinter, saveToLocation, this);
} }
catch (Exception e){ catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL); print(e.getMessage(), EMsgType.FAIL);
} }
logPrinter.print(".:: Complete ::.", EMsgType.PASS); print(".:: Complete ::.", EMsgType.PASS);
usbConnect.close(); usbConnect.close();
logPrinter.updateOneLinerStatus(true); logPrinter.updateOneLinerStatus(true);
logPrinter.close(); logPrinter.close();
} }
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
} }

View file

@ -119,7 +119,7 @@ class NxdtUsbAbi1 {
USBSTATUS_SUCCESS[9] = (byte)((endpointMaxPacketSize >> 8) & 0xFF); USBSTATUS_SUCCESS[9] = (byte)((endpointMaxPacketSize >> 8) & 0xFF);
} }
private void readLoop(){ private void readLoop() throws InterruptedException{
logPrinter.print("Awaiting for handshake", EMsgType.INFO); logPrinter.print("Awaiting for handshake", EMsgType.INFO);
try { try {
byte[] directive; byte[] directive;
@ -292,7 +292,7 @@ class NxdtUsbAbi1 {
return nspFile != null; return nspFile != null;
} }
private String getAbsoluteFilePath(String filename) throws Exception{ private String getAbsoluteFilePath(String filename) {
if (isRomFs(filename) && isWindows) // Since RomFS entry starts from '/' it should be replaced to '\'. if (isRomFs(filename) && isWindows) // Since RomFS entry starts from '/' it should be replaced to '\'.
return saveToPath + filename.replaceAll("/", "\\\\"); return saveToPath + filename.replaceAll("/", "\\\\");
return saveToPath + filename; return saveToPath + filename;

View file

@ -0,0 +1,178 @@
/*
Copyright 2019-2021 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.*;
import java.util.Arrays;
import java.util.concurrent.Callable;
public class MergeSubTask implements Callable<Boolean> {
private final int id;
private final String saveToPath;
private final MultithreadingPrintAdapter printAdapter;
private final File splitFile;
private File[] chunkFiles;
private long chunksTotalSize;
private File resultFile;
public MergeSubTask(int id, File splitFile, String saveToPath, MultithreadingPrintAdapter printAdapter){
this.id = id;
this.splitFile = splitFile;
this.saveToPath = saveToPath;
this.printAdapter = printAdapter;
}
@Override
public Boolean call(){
try{
collectChunks();
validateChunks();
sortChunks();
calculateChunksSizeSum();
createFile();
mergeChunksToFile();
validateFile();
return true;
}
catch (InterruptedException ie){
cleanup();
return false;
}
catch (Exception e){
e.printStackTrace();
try {
printAdapter.print("["+id+"] "+e.getMessage(), EMsgType.FAIL);
}
catch (InterruptedException ignore) {}
return false;
}
}
private void collectChunks(){
chunkFiles = splitFile.listFiles((file, s) -> s.matches("^[0-9][0-9]$"));
}
private void validateChunks() throws Exception{
if (chunkFiles == null || chunkFiles.length == 0){
throw new Exception("Selected folder doesn't have any chunks. Nothing to do here.");
}
}
private void sortChunks(){
Arrays.sort(chunkFiles);
}
private void calculateChunksSizeSum() throws InterruptedException{
StringBuilder builder = new StringBuilder("["+id+"] Next files will be merged in following order: ");
for (File cnk : chunkFiles){
builder.append(cnk.getName());
builder.append(" ");
chunksTotalSize += cnk.length();
}
printAdapter.print(builder.toString(), EMsgType.INFO);
}
private void createFile() throws Exception{
final String splitFileName = splitFile.getName();
resultFile = new File(saveToPath+File.separator+"!_"+splitFileName);
for (int i = 0; i < 50 ; i++){
if (interrupted())
throw new InterruptedException();
if (resultFile.exists()){
printAdapter.print("["+id+"] Trying to create a good new file...", EMsgType.WARNING);
resultFile = new File(saveToPath+File.separator+"!_"+i+"_"+splitFileName);
continue;
}
printAdapter.print("["+id+"] Save results to: "+resultFile.getAbsolutePath(), EMsgType.INFO);
return;
}
throw new Exception("Can't create new file.");
}
private void mergeChunksToFile() throws Exception{
if ( interrupted())
throw new InterruptedException();
try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(resultFile))){
BufferedInputStream bis;
byte[] chunk;
int readBytesCnt;
printAdapter.reportFileSize(chunksTotalSize);
for (File chunkFile : chunkFiles){
bis = new BufferedInputStream(new FileInputStream(chunkFile));
while (true){
chunk = new byte[4194240];
readBytesCnt = bis.read(chunk);
if (readBytesCnt < 4194240){
if (readBytesCnt > 0)
bos.write(chunk, 0, readBytesCnt);
break;
}
if (interrupted())
throw new InterruptedException();
bos.write(chunk);
printAdapter.updateProgressBySize(readBytesCnt);
}
bis.close();
}
}
}
private void validateFile() throws Exception{
if ( interrupted())
throw new Exception("Merge task interrupted!");
long resultFileSize = resultFile.length();
printAdapter.print("["+id+"] Total chunks size: " + chunksTotalSize
+"\n Merged file size: " + resultFileSize, EMsgType.INFO);
if (chunksTotalSize != resultFileSize)
throw new Exception("Sizes are different! Do NOT use this file for installations!");
printAdapter.print("["+id+"] Sizes are the same! Resulting file should be good!", EMsgType.PASS);
}
private void cleanup(){
boolean isDeleted = resultFile.delete();
try {
printAdapter.print(
"[" + id + "] Merge task interrupted and file "
+ (isDeleted ? "deleted." : "is NOT deleted."), EMsgType.FAIL);
}
catch (InterruptedException ignore) {}
}
private boolean interrupted(){
return Thread.interrupted(); // NOTE: it's not isInterrupted(); And it's handled properly for now.
}
}

View file

@ -1,169 +0,0 @@
/*
Copyright 2019-2020 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.*;
import java.util.Arrays;
public class MergeTask extends CancellableRunnable {
private final ILogPrinter logPrinter;
private final String saveToPath;
private final String filePath;
private File splitFile;
private File[] chunkFiles;
private long chunksTotalSize;
private File resultFile;
public MergeTask(String filePath, String saveToPath) {
this.filePath = filePath;
this.saveToPath = saveToPath;
logPrinter = Log.getPrinter(EModule.SPLIT_MERGE_TOOL);
}
@Override
public void run() {
try {
logPrinter.print("Merge file: " + filePath, EMsgType.INFO);
splitFile = new File(filePath);
collectChunks();
validateChunks();
sortChunks();
calculateChunksSizeSum();
createFile();
mergeChunksToFile();
validateFile();
logPrinter.print(".:: Merge complete ::.", EMsgType.INFO);
logPrinter.updateOneLinerStatus(true);
logPrinter.close();
}
catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL);
logPrinter.updateOneLinerStatus(false);
logPrinter.close();
}
}
private void collectChunks(){
chunkFiles = splitFile.listFiles((file, s) -> s.matches("^[0-9][0-9]$"));
}
private void validateChunks() throws Exception{
if (chunkFiles == null || chunkFiles.length == 0){
throw new Exception("Selected folder doesn't have any chunks. Nothing to do here.");
}
}
private void sortChunks(){
Arrays.sort(chunkFiles);
}
private void calculateChunksSizeSum(){
logPrinter.print("Next files will be merged in following order: ", EMsgType.INFO);
for (File cnk : chunkFiles){
logPrinter.print(" "+cnk.getName(), EMsgType.INFO);
chunksTotalSize += cnk.length();
}
}
private void createFile() throws Exception{
final String splitFileName = splitFile.getName();
resultFile = new File(saveToPath+File.separator+"!_"+splitFileName);
for (int i = 0; i < 50 ; i++){
if (isCancelled()){
throw new InterruptedException("Split task interrupted!");
}
if (resultFile.exists()){
logPrinter.print("Trying to create a good new file...", EMsgType.WARNING);
resultFile = new File(saveToPath+File.separator+"!_"+i+"_"+splitFileName);
continue;
}
logPrinter.print("Save results to: "+resultFile.getAbsolutePath(), EMsgType.INFO);
return;
}
throw new Exception("Can't create new file.");
}
private void mergeChunksToFile() throws Exception{
double chunkPercent = (4194240.0 / (chunksTotalSize / 100.0) / 100.0);
long totalSizeCnt = 0;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(resultFile));
BufferedInputStream bis;
byte[] chunk;
int readBytesCnt;
for (File chunkFile : chunkFiles){
bis = new BufferedInputStream(new FileInputStream(chunkFile));
while (true){
if (isCancelled()){
bos.close();
bis.close();
boolean isDeleted = resultFile.delete();
throw new InterruptedException("Merge task interrupted and file "
+ (isDeleted ? "deleted." : "is not deleted."));
}
chunk = new byte[4194240];
readBytesCnt = bis.read(chunk);
logPrinter.updateProgress(chunkPercent * totalSizeCnt);
totalSizeCnt++;
if (readBytesCnt < 4194240){
if (readBytesCnt > 0)
bos.write(chunk, 0, readBytesCnt);
break;
}
bos.write(chunk);
}
bis.close();
}
bos.close();
}
private void validateFile() throws Exception{
long resultFileSize = resultFile.length();
logPrinter.print("Total chunks size: " + chunksTotalSize, EMsgType.INFO);
logPrinter.print("Merged file size: " + resultFileSize, EMsgType.INFO);
if (chunksTotalSize != resultFileSize)
throw new Exception("Sizes are different! Do NOT use this file for installations!");
logPrinter.print("Sizes are the same! Resulting file should be good!", EMsgType.PASS);
}
}

View file

@ -0,0 +1,44 @@
/*
Copyright 2019-2021 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
public class MultithreadingPrintAdapter {
private final ILogPrinter printer;
private long totalFilesSize;
private long bytesComplete;
public MultithreadingPrintAdapter(ILogPrinter printer){
this.printer = printer;
}
public void print(String message, EMsgType type) throws InterruptedException{
printer.print(message, type);
}
public void reportFileSize(long fileSize){
totalFilesSize += fileSize;
}
public void updateProgressBySize(long chunkSize) throws InterruptedException{
bytesComplete += chunkSize;
printer.updateProgress((double) bytesComplete / (double) totalFilesSize);
}
}

View file

@ -0,0 +1,147 @@
/*
Copyright 2019-2020 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/*
* TODO: Kill this on application exit (?)
*/
public class SplitMergeTaskExecutor implements Runnable {
private final boolean isSplit;
private final List<File> files;
private final String saveToPath;
private final ILogPrinter logPrinter;
private final ExecutorService executorService;
private final MultithreadingPrintAdapter printAdapter;
public SplitMergeTaskExecutor(boolean isSplit, List<File> files, String saveToPath){
this.isSplit = isSplit;
this.files = files;
this.saveToPath = saveToPath;
this.logPrinter = Log.getPrinter(EModule.SPLIT_MERGE_TOOL);
this.executorService = Executors.newFixedThreadPool(
files.size(),
runnable -> {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
});
this.printAdapter = new MultithreadingPrintAdapter(logPrinter);
}
public void run(){
try {
List<Future<Boolean>> futuresResults = executorService.invokeAll(getSubTasksCollection());
boolean onelinerResult = true;
for (Future<Boolean> future : futuresResults){
onelinerResult &= future.get();
}
executorService.shutdown();
logPrinter.updateOneLinerStatus(onelinerResult);
}
catch (InterruptedException ie){
//ie.printStackTrace();
executorService.shutdownNow();
boolean interruptedSuccessfully = false;
try {
interruptedSuccessfully = executorService.awaitTermination(20, TimeUnit.SECONDS);
}
catch (InterruptedException awaitInterrupt){
print("Force interrupting task...", EMsgType.WARNING);
}
logPrinter.updateOneLinerStatus(false);
print((
isSplit?
"Split tasks interrupted ":
"Merge tasks interrupted ")+
(interruptedSuccessfully?
"successfully":
"with some issues"), EMsgType.WARNING);
}
catch (Exception e){
logPrinter.updateOneLinerStatus(false);
print(
isSplit?
"Split task failed: ":
"Merge task failed: "+e.getMessage(), EMsgType.FAIL);
e.printStackTrace();
}
print(
isSplit?
".:: Split complete ::.":
".:: Merge complete ::.", EMsgType.INFO);
logPrinter.close();
}
private List<Callable<Boolean>> getSubTasksCollection() throws InterruptedException{
List<Callable<Boolean>> subTasks = new ArrayList<>();
StringBuilder stringBuilder = new StringBuilder();
// TODO: Optimize?
if (isSplit){
stringBuilder.append("Split files:\n");
for (int i = 0; i < files.size(); i++){
File file = files.get(i);
stringBuilder.append("[");
stringBuilder.append(i);
stringBuilder.append("] ");
stringBuilder.append(file.getName());
stringBuilder.append("\n");
Callable<Boolean> task = new SplitSubTask(i, file, saveToPath, printAdapter);
subTasks.add(task);
}
}
else {
stringBuilder.append("Merge files:\n");
for (int i = 0; i < files.size(); i++){
File file = files.get(i);
stringBuilder.append("[");
stringBuilder.append(i);
stringBuilder.append("] ");
stringBuilder.append(file.getName());
stringBuilder.append("\n");
Callable<Boolean> task = new MergeSubTask(i, file, saveToPath, printAdapter);
subTasks.add(task);
}
}
logPrinter.print(stringBuilder.toString(), EMsgType.INFO);
return subTasks;
}
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
}

View file

@ -0,0 +1,186 @@
/*
Copyright 2019-2021 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.*;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
public class SplitSubTask implements Callable<Boolean> {
private final int id;
private final String saveToPath;
private final File file;
private File splitFile;
private long originalFileLen;
private final MultithreadingPrintAdapter printAdapter;
SplitSubTask(int id, File file, String saveToPath, MultithreadingPrintAdapter printAdapter){
this.id = id;
this.file = file;
this.saveToPath = saveToPath;
this.printAdapter = printAdapter;
}
@Override
public Boolean call(){
try {
createSplitFile();
splitFileToChunks();
validateSplitFile();
return true;
}
catch (InterruptedException | ExecutionException ie){
ie.printStackTrace();
cleanup();
return false;
}
catch (Exception e){
e.printStackTrace();
try {
printAdapter.print("["+id+"] "+e.getMessage(), EMsgType.FAIL);
}
catch (InterruptedException ignore) {}
return false;
}
}
private void createSplitFile() throws Exception{
if ( interrupted())
throw new Exception("Split task interrupted!");
splitFile = new File(saveToPath+File.separator+"!_"+file.getName());
for (int i = 0; i < 50; i++){
if (splitFile.mkdirs()){
printAdapter.print("["+id+"] Save results to: "+splitFile.getAbsolutePath(), EMsgType.INFO);
return;
}
if (splitFile.exists()){
printAdapter.print("["+id+"] Trying to create a good new folder...", EMsgType.WARNING);
splitFile = new File(saveToPath+File.separator+"!_"+i+"_"+file.getName());
continue;
}
throw new Exception("Folder " + splitFile.getAbsolutePath()
+ " could not be created. Not enough rights or something like that?");
}
throw new Exception("Can't create new file.");
}
private void splitFileToChunks() throws Exception{
try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))){
long counter;
originalFileLen = file.length();
printAdapter.reportFileSize(originalFileLen);
byte[] chunk;
int readBytesCnt;
main_loop:
for (int i = 0; ; i++){
String pathname = splitFile.getAbsolutePath()+File.separator+String.format("%02d", i);
BufferedOutputStream fragmentBos = new BufferedOutputStream(new FileOutputStream(pathname));
counter = 0;
while (counter < 1024){ // 0xffff0000 total
chunk = new byte[4194240];
if ((readBytesCnt = bis.read(chunk)) < 4194240){
if (readBytesCnt > 0)
fragmentBos.write(chunk, 0, readBytesCnt);
fragmentBos.close();
printAdapter.updateProgressBySize(readBytesCnt);
break main_loop;
}
if (interrupted())
throw new InterruptedException();
fragmentBos.write(chunk);
counter++;
printAdapter.updateProgressBySize(readBytesCnt);
}
fragmentBos.close();
}
}
}
private void validateSplitFile() throws Exception{
if (interrupted())
throw new Exception("Split task interrupted!");
printAdapter.print("["+id+"] Original file: "+splitFile.getAbsolutePath()+" (size: "+originalFileLen+")", EMsgType.INFO);
long totalChunksSize = 0;
File[] chunkFileArr = splitFile.listFiles();
if (chunkFileArr == null)
throw new Exception("Unable to check results. It means that something went wrong.");
Arrays.sort(chunkFileArr);
StringBuilder stringBuilder = new StringBuilder("["+id+"] Chunks");
for (File chunkFile : chunkFileArr) {
stringBuilder.append("\n");
stringBuilder.append(" ");
stringBuilder.append(chunkFile.getName());
stringBuilder.append(" size: ");
stringBuilder.append(chunkFile.length());
totalChunksSize += chunkFile.length();
}
stringBuilder.append("\n");
stringBuilder.append("Total chunks size: ");
stringBuilder.append(totalChunksSize);
printAdapter.print(stringBuilder.toString(), EMsgType.INFO);
if (originalFileLen != totalChunksSize)
throw new Exception("Sizes are different! Do NOT use this file for installations!");
printAdapter.print("["+id+"] Sizes are the same! Split file should be good!", EMsgType.PASS);
}
private void cleanup(){
boolean isDeleted = splitFile.delete();
File[] chunksToDelete = splitFile.listFiles();
if (! isDeleted && chunksToDelete != null){
isDeleted = true;
for (File chunkFile : chunksToDelete)
isDeleted &= chunkFile.delete();
isDeleted &= splitFile.delete();
}
try {
printAdapter.print(
"["+id+"] Split task interrupted and folder "
+ (isDeleted?"deleted.":"is NOT deleted.")
, EMsgType.FAIL);
}
catch (InterruptedException ignore) {}
}
private boolean interrupted(){
return Thread.interrupted(); // NOTE: it's not isInterrupted(); And it's handled properly for now.
}
}

View file

@ -1,173 +0,0 @@
/*
Copyright 2019-2020 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.splitmerge;
import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.*;
import java.util.Arrays;
public class SplitTask extends CancellableRunnable {
private final ILogPrinter logPrinter;
private final String saveToPath;
private final String filePath;
private File file;
private File splitFile;
private long originalFileLen;
public SplitTask(String filePath, String saveToPath){
this.filePath = filePath;
this.saveToPath = saveToPath;
this.logPrinter = Log.getPrinter(EModule.SPLIT_MERGE_TOOL);
}
@Override
public void run() {
try {
logPrinter.print("Split file: "+filePath, EMsgType.INFO);
this.file = new File(filePath);
createSplitFile();
splitFileToChunks();
validateSplitFile();
logPrinter.print(".:: Split complete ::.", EMsgType.INFO);
logPrinter.updateOneLinerStatus(true);
logPrinter.close();
}
catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL);
logPrinter.updateOneLinerStatus(false);
logPrinter.close();
}
}
private void createSplitFile() throws Exception{
splitFile = new File(saveToPath+File.separator+"!_"+file.getName());
for (int i = 0; i < 50 ; i++){
if (isCancelled()){
throw new InterruptedException("Split task interrupted!");
}
if (splitFile.mkdir()){
logPrinter.print("Save results to: "+splitFile.getAbsolutePath(), EMsgType.INFO);
return;
}
if (splitFile.exists()){
logPrinter.print("Trying to create a good new folder...", EMsgType.WARNING);
splitFile = new File(saveToPath+File.separator+"!_"+i+"_"+file.getName());
continue;
}
throw new Exception("Folder " + splitFile.getAbsolutePath()
+ " could not be created. Not enough rights or something like that?");
}
throw new Exception("Can't create new file.");
}
private void splitFileToChunks() throws Exception{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
long counter;
originalFileLen = file.length();
double chunkPercent = (4194240.0 / (originalFileLen / 100.0) / 100.0);
long totalSizeCnt = 0;
byte[] chunk;
int readBytesCnt;
main_loop:
for (int i = 0; ; i++){
String pathname = splitFile.getAbsolutePath()+File.separator+String.format("%02d", i);
BufferedOutputStream fragmentBos = new BufferedOutputStream(new FileOutputStream(new File(pathname)));
counter = 0;
while (counter < 1024){ // 0xffff0000 total
if (isCancelled()){
fragmentBos.close();
bis.close();
boolean isDeleted = splitFile.delete();
File[] chunksToDelete = splitFile.listFiles();
if (! isDeleted && chunksToDelete != null){
isDeleted = true;
for (File chunkFile : chunksToDelete)
isDeleted &= chunkFile.delete();
isDeleted &= splitFile.delete();
}
throw new InterruptedException("Split task interrupted and folder "
+ (isDeleted?"deleted.":"is not deleted."));
}
chunk = new byte[4194240];
if ((readBytesCnt = bis.read(chunk)) < 4194240){
if (readBytesCnt > 0)
fragmentBos.write(chunk, 0, readBytesCnt);
fragmentBos.close();
logPrinter.updateProgress(1.0);
break main_loop;
}
fragmentBos.write(chunk);
logPrinter.updateProgress(chunkPercent * totalSizeCnt);
counter++; // NOTE: here we have some redundancy of variables. It has to be fixed one day.
totalSizeCnt++;
}
fragmentBos.close();
}
bis.close();
}
private void validateSplitFile() throws Exception{
logPrinter.print("Original file size: "+originalFileLen, EMsgType.INFO);
long totalChunksSize = 0;
File[] chunkFileArr = splitFile.listFiles();
if (chunkFileArr == null)
throw new Exception("Unable to check results. It means that something went wrong.");
Arrays.sort(chunkFileArr);
for (File chunkFile : chunkFileArr) {
logPrinter.print("Chunk " + chunkFile.getName() + " size: " + chunkFile.length(), EMsgType.INFO);
totalChunksSize += chunkFile.length();
}
logPrinter.print("Total chunks size: " + totalChunksSize, EMsgType.INFO);
if (originalFileLen != totalChunksSize)
throw new Exception("Sizes are different! Do NOT use this file for installations!");
logPrinter.print("Sizes are the same! Split file should be good!", EMsgType.PASS);
}
}

View file

@ -18,8 +18,7 @@
*/ */
package nsusbloader.cli; package nsusbloader.cli;
import nsusbloader.Utilities.splitmerge.MergeTask; import nsusbloader.Utilities.splitmerge.SplitMergeTaskExecutor;
import nsusbloader.Utilities.splitmerge.SplitTask;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,7 +26,7 @@ import java.util.List;
public class MergeCli { public class MergeCli {
private String[] arguments; private final String[] arguments;
private String saveTo; private String saveTo;
private String[] splitFiles; private String[] splitFiles;
@ -97,12 +96,20 @@ public class MergeCli {
} }
private void runBackend() throws InterruptedException{ private void runBackend() throws InterruptedException{
for (String filePath : splitFiles){ Runnable mergeTask = new SplitMergeTaskExecutor(
Runnable mergeTask = new MergeTask(filePath, saveTo); false,
Thread thread = new Thread(mergeTask); getFilesFromStrings(),
thread.setDaemon(true); saveTo);
thread.start(); Thread thread = new Thread(mergeTask);
thread.join(); thread.setDaemon(true);
thread.start();
thread.join();
}
private List<File> getFilesFromStrings(){
ArrayList<File> realFiles = new ArrayList<>();
for (String splitFileString : splitFiles){
realFiles.add(new File(splitFileString));
} }
return realFiles;
} }
} }

View file

@ -18,16 +18,14 @@
*/ */
package nsusbloader.cli; package nsusbloader.cli;
import nsusbloader.Utilities.splitmerge.SplitTask; import nsusbloader.Utilities.splitmerge.SplitMergeTaskExecutor;
import java.io.File; import java.io.File;
import java.nio.file.Paths; import java.util.*;
import java.util.ArrayList;
import java.util.List;
public class SplitCli { public class SplitCli {
private String[] arguments; private final String[] arguments;
private String saveTo; private String saveTo;
private String[] files; private String[] files;
@ -95,12 +93,20 @@ public class SplitCli {
} }
private void runBackend() throws InterruptedException{ private void runBackend() throws InterruptedException{
for (String filePath : files){ Runnable splitTasks = new SplitMergeTaskExecutor(
Runnable splitTaks = new SplitTask(filePath, saveTo); true,
Thread thread = new Thread(splitTaks); getFilesFromStrings(),
thread.setDaemon(true); saveTo);
thread.start(); Thread thread = new Thread(splitTasks);
thread.join(); thread.setDaemon(true);
thread.start();
thread.join();
}
private List<File> getFilesFromStrings(){
ArrayList<File> realFiles = new ArrayList<>();
for (String fileString : files){
realFiles.add(new File(fileString));
} }
return realFiles;
} }
} }

View file

@ -90,7 +90,7 @@ public class NETCommunications extends CancellableRunnable {
if (! isValid || isCancelled() ) if (! isValid || isCancelled() )
return; return;
logPrinter.print("\tStart chain", EMsgType.INFO); print("\tStart chain", EMsgType.INFO);
final String handshakeContent = buildHandshakeContent(); final String handshakeContent = buildHandshakeContent();
@ -102,11 +102,11 @@ public class NETCommunications extends CancellableRunnable {
// Check if we should serve requests // Check if we should serve requests
if (this.doNotServe){ if (this.doNotServe){
logPrinter.print("List of files transferred. Replies won't be served.", EMsgType.PASS); print("List of files transferred. Replies won't be served.", EMsgType.PASS);
close(EFileStatus.UNKNOWN); close(EFileStatus.UNKNOWN);
return; return;
} }
logPrinter.print("Initiation files list has been sent to NS.", EMsgType.PASS); print("Initiation files list has been sent to NS.", EMsgType.PASS);
// Go transfer // Go transfer
serveRequestsLoop(); serveRequestsLoop();
@ -142,7 +142,7 @@ public class NETCommunications extends CancellableRunnable {
handshakeSocket.close(); handshakeSocket.close();
} }
catch (IOException uhe){ catch (IOException uhe){
logPrinter.print("Unable to connect to NS and send files list:\n " print("Unable to connect to NS and send files list:\n "
+ uhe.getMessage(), EMsgType.FAIL); + uhe.getMessage(), EMsgType.FAIL);
close(EFileStatus.UNKNOWN); close(EFileStatus.UNKNOWN);
return true; return true;
@ -175,13 +175,13 @@ public class NETCommunications extends CancellableRunnable {
} }
catch (Exception e){ catch (Exception e){
if (isCancelled()) if (isCancelled())
logPrinter.print("Interrupted by user.", EMsgType.INFO); print("Interrupted by user.", EMsgType.INFO);
else else
logPrinter.print(e.getMessage(), EMsgType.INFO); print(e.getMessage(), EMsgType.INFO);
close(EFileStatus.UNKNOWN); close(EFileStatus.UNKNOWN);
return; return;
} }
logPrinter.print("All transfers complete", EMsgType.PASS); print("All transfers complete", EMsgType.PASS);
close(EFileStatus.UPLOADED); close(EFileStatus.UPLOADED);
} }
/** /**
@ -199,7 +199,7 @@ public class NETCommunications extends CancellableRunnable {
if (! files.containsKey(reqFileName)){ if (! files.containsKey(reqFileName)){
writeToSocket(NETPacket.getCode404()); writeToSocket(NETPacket.getCode404());
logPrinter.print("File "+reqFileName+" doesn't exists or have 0 size. Returning 404", EMsgType.FAIL); print("File "+reqFileName+" doesn't exists or have 0 size. Returning 404", EMsgType.FAIL);
return; return;
} }
@ -208,13 +208,13 @@ public class NETCommunications extends CancellableRunnable {
if (! requestedFile.exists() || reqFileSize == 0){ // well.. tell 404 if file exists with 0 length is against standard, but saves time if (! requestedFile.exists() || reqFileSize == 0){ // well.. tell 404 if file exists with 0 length is against standard, but saves time
writeToSocket(NETPacket.getCode404()); writeToSocket(NETPacket.getCode404());
logPrinter.print("File "+requestedFile.getName()+" doesn't exists or have 0 size. Returning 404", EMsgType.FAIL); print("File "+requestedFile.getName()+" doesn't exists or have 0 size. Returning 404", EMsgType.FAIL);
logPrinter.update(requestedFile, EFileStatus.FAILED); logPrinter.update(requestedFile, EFileStatus.FAILED);
return; return;
} }
if (packet.get(0).startsWith("HEAD")){ if (packet.get(0).startsWith("HEAD")){
writeToSocket(NETPacket.getCode200(reqFileSize)); writeToSocket(NETPacket.getCode200(reqFileSize));
logPrinter.print("Replying for requested file: "+requestedFile.getName(), EMsgType.INFO); print("Replying for requested file: "+requestedFile.getName(), EMsgType.INFO);
return; return;
} }
if (packet.get(0).startsWith("GET")) { if (packet.get(0).startsWith("GET")) {
@ -237,7 +237,7 @@ public class NETCommunications extends CancellableRunnable {
if (fromRange > toRange){ // If start bytes greater then end bytes if (fromRange > toRange){ // If start bytes greater then end bytes
writeToSocket(NETPacket.getCode400()); writeToSocket(NETPacket.getCode400());
logPrinter.print("Requested range for " print("Requested range for "
+ file.getName() + file.getName()
+ " is incorrect. Returning 400", EMsgType.FAIL); + " is incorrect. Returning 400", EMsgType.FAIL);
logPrinter.update(file, EFileStatus.FAILED); logPrinter.update(file, EFileStatus.FAILED);
@ -254,7 +254,7 @@ public class NETCommunications extends CancellableRunnable {
if (rangeStr[1].isEmpty()) { // If Range not defined: like "Range: bytes=-" if (rangeStr[1].isEmpty()) { // If Range not defined: like "Range: bytes=-"
writeToSocket(NETPacket.getCode400()); writeToSocket(NETPacket.getCode400());
logPrinter.print("Requested range for " print("Requested range for "
+ file.getName() + file.getName()
+ " is incorrect (empty start & end). Returning 400", EMsgType.FAIL); + " is incorrect (empty start & end). Returning 400", EMsgType.FAIL);
logPrinter.update(file, EFileStatus.FAILED); logPrinter.update(file, EFileStatus.FAILED);
@ -267,7 +267,7 @@ public class NETCommunications extends CancellableRunnable {
} }
// If file smaller than 500 bytes // If file smaller than 500 bytes
writeToSocket(NETPacket.getCode416()); writeToSocket(NETPacket.getCode416());
logPrinter.print("File size requested for " print("File size requested for "
+ file.getName() + file.getName()
+ " while actual size of it: " + " while actual size of it: "
+ fileSize+". Returning 416", EMsgType.FAIL); + fileSize+". Returning 416", EMsgType.FAIL);
@ -275,7 +275,7 @@ public class NETCommunications extends CancellableRunnable {
} }
catch (NumberFormatException nfe){ catch (NumberFormatException nfe){
writeToSocket(NETPacket.getCode400()); writeToSocket(NETPacket.getCode400());
logPrinter.print("Requested range for " print("Requested range for "
+ file.getName() + file.getName()
+ " has incorrect format. Returning 400\n\t" + " has incorrect format. Returning 400\n\t"
+ nfe.getMessage(), EMsgType.FAIL); + nfe.getMessage(), EMsgType.FAIL);
@ -293,7 +293,7 @@ public class NETCommunications extends CancellableRunnable {
private void writeToSocket(String fileName, long start, long end) throws Exception{ private void writeToSocket(String fileName, long start, long end) throws Exception{
File file = files.get(fileName).getFile(); File file = files.get(fileName).getFile();
logPrinter.print("Reply to range: "+start+"-"+end, EMsgType.INFO); print("Reply to range: "+start+"-"+end, EMsgType.INFO);
writeToSocket(NETPacket.getCode206(files.get(fileName).getSize(), start, end)); writeToSocket(NETPacket.getCode206(files.get(fileName).getSize(), start, end));
try{ try{
@ -379,11 +379,11 @@ public class NETCommunications extends CancellableRunnable {
try { try {
if (serverSocket != null && ! serverSocket.isClosed()) { if (serverSocket != null && ! serverSocket.isClosed()) {
serverSocket.close(); serverSocket.close();
logPrinter.print("Closing server socket.", EMsgType.PASS); print("Closing server socket.", EMsgType.PASS);
} }
} }
catch (IOException ioe){ catch (IOException ioe){
logPrinter.print("Closing server socket failed. Sometimes it's not an issue.", EMsgType.WARNING); print("Closing server socket failed. Sometimes it's not an issue.", EMsgType.WARNING);
} }
HashMap<String, File> tempMap = new HashMap<>(); HashMap<String, File> tempMap = new HashMap<>();
@ -392,7 +392,15 @@ public class NETCommunications extends CancellableRunnable {
logPrinter.update(tempMap, status); logPrinter.update(tempMap, status);
logPrinter.print("\tEnd chain", EMsgType.INFO); print("\tEnd chain", EMsgType.INFO);
logPrinter.close(); logPrinter.close();
} }
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
} }

View file

@ -55,15 +55,21 @@ public class NetworkSetupValidator {
resolvePort(hostPortNum); resolvePort(hostPortNum);
} }
catch (Exception e){ catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL); try {
logPrinter.print(e.getMessage(), EMsgType.FAIL);
}
catch (InterruptedException ignore){}
valid = false; valid = false;
return; return;
} }
valid = true; valid = true;
} }
private void validateFiles(List<File> filesList) { private void validateFiles(List<File> filesList){
filesList.removeIf(f -> { filesList.removeIf(this::validator);
}
private boolean validator(File f){
try {
if (f.isFile()) if (f.isFile())
return false; return false;
@ -76,24 +82,27 @@ public class NetworkSetupValidator {
Arrays.sort(subFiles, Comparator.comparingInt(file -> Integer.parseInt(file.getName()))); Arrays.sort(subFiles, Comparator.comparingInt(file -> Integer.parseInt(file.getName())));
for (int i = subFiles.length - 2; i > 0 ; i--){ for (int i = subFiles.length - 2; i > 0; i--) {
if (subFiles[i].length() != subFiles[i-1].length()) { if (subFiles[i].length() != subFiles[i - 1].length()) {
logPrinter.print("NET: Exclude split file: "+f.getName()+ logPrinter.print("NET: Exclude split file: " + f.getName() +
"\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING); "\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING);
return true; return true;
} }
} }
long firstFileLength = subFiles[0].length(); long firstFileLength = subFiles[0].length();
long lastFileLength = subFiles[subFiles.length-1].length(); long lastFileLength = subFiles[subFiles.length - 1].length();
if (lastFileLength > firstFileLength){ if (lastFileLength > firstFileLength) {
logPrinter.print("NET: Exclude split file: "+f.getName()+ logPrinter.print("NET: Exclude split file: " + f.getName() +
"\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING); "\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING);
return true; return true;
} }
return false; return false;
}); }
catch (InterruptedException ie){
return false;
}
} }
private void encodeAndAddFilesToMap(List<File> filesList) throws UnsupportedEncodingException, FileNotFoundException { private void encodeAndAddFilesToMap(List<File> filesList) throws UnsupportedEncodingException, FileNotFoundException {
@ -108,7 +117,7 @@ public class NetworkSetupValidator {
} }
} }
private void resolveIp(String hostIPaddr) throws IOException{ private void resolveIp(String hostIPaddr) throws IOException, InterruptedException{
if (! hostIPaddr.isEmpty()){ if (! hostIPaddr.isEmpty()){
this.hostIP = hostIPaddr; this.hostIP = hostIPaddr;
logPrinter.print("NET: Host IP defined as: " + hostIP, EMsgType.PASS); logPrinter.print("NET: Host IP defined as: " + hostIP, EMsgType.PASS);
@ -124,7 +133,7 @@ public class NetworkSetupValidator {
throw new IOException("Try using 'Expert mode' and set IP manually. " + getAvaliableIpExamples()); throw new IOException("Try using 'Expert mode' and set IP manually. " + getAvaliableIpExamples());
} }
private boolean findIpUsingHost(String host) { private boolean findIpUsingHost(String host) throws InterruptedException{
try { try {
Socket scoketK; Socket scoketK;
scoketK = new Socket(); scoketK = new Socket();

View file

@ -59,17 +59,17 @@ public class GoldLeaf_05 extends TransferModule {
this.task = task; this.task = task;
status = EFileStatus.FAILED; status = EFileStatus.FAILED;
logPrinter.print("============= GoldLeaf v0.5 =============\n" + 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); " Only one file per time could be sent. In case you selected more the first one would be picked.", EMsgType.INFO);
if (nspMap.isEmpty()){ if (nspMap.isEmpty()){
logPrinter.print("For using this GoldLeaf version you have to add file to the table and select it for upload", EMsgType.INFO); print("For using this GoldLeaf version you have to add file to the table and select it for upload", EMsgType.INFO);
return; return;
} }
File nspFile = (File) nspMap.values().toArray()[0]; File nspFile = (File) nspMap.values().toArray()[0];
logPrinter.print("File for upload: "+nspFile.getAbsolutePath(), EMsgType.INFO); print("File for upload: "+nspFile.getAbsolutePath(), EMsgType.INFO);
if (!nspFile.getName().toLowerCase().endsWith(".nsp")) { if (!nspFile.getName().toLowerCase().endsWith(".nsp")) {
logPrinter.print("GL This file doesn't look like NSP", EMsgType.FAIL); print("GL This file doesn't look like NSP", EMsgType.FAIL);
return; return;
} }
PFSProvider pfsElement; PFSProvider pfsElement;
@ -77,11 +77,11 @@ public class GoldLeaf_05 extends TransferModule {
pfsElement = new PFSProvider(nspFile, logPrinter); pfsElement = new PFSProvider(nspFile, logPrinter);
} }
catch (Exception e){ catch (Exception e){
logPrinter.print("GL File provided has incorrect structure and won't be uploaded\n\t"+e.getMessage(), EMsgType.FAIL); print("GL File provided has incorrect structure and won't be uploaded\n\t"+e.getMessage(), EMsgType.FAIL);
status = EFileStatus.INCORRECT_FILE_FAILED; status = EFileStatus.INCORRECT_FILE_FAILED;
return; return;
} }
logPrinter.print("GL File structure validated and it will be uploaded", EMsgType.PASS); print("GL File structure validated and it will be uploaded", EMsgType.PASS);
try{ try{
if (nspFile.isDirectory()) if (nspFile.isDirectory())
@ -90,7 +90,7 @@ public class GoldLeaf_05 extends TransferModule {
this.raf = new RandomAccessFile(nspFile, "r"); this.raf = new RandomAccessFile(nspFile, "r");
} }
catch (IOException ioe){ catch (IOException ioe){
logPrinter.print("GL File not found\n\t"+ioe.getMessage(), EMsgType.FAIL); print("GL File not found\n\t"+ioe.getMessage(), EMsgType.FAIL);
return; return;
} }
@ -99,15 +99,15 @@ public class GoldLeaf_05 extends TransferModule {
// Go connect to GoldLeaf // Go connect to GoldLeaf
if (writeUsb(CMD_GLUC)) { if (writeUsb(CMD_GLUC)) {
logPrinter.print("GL Initiating GoldLeaf connection [1/2]", EMsgType.FAIL); print("GL Initiating GoldLeaf connection [1/2]", EMsgType.FAIL);
return; return;
} }
logPrinter.print("GL Initiating GoldLeaf connection: [1/2]", EMsgType.PASS); print("GL Initiating GoldLeaf connection: [1/2]", EMsgType.PASS);
if (writeUsb(CMD_ConnectionRequest)){ if (writeUsb(CMD_ConnectionRequest)){
logPrinter.print("GL Initiating GoldLeaf connection: [2/2]", EMsgType.FAIL); print("GL Initiating GoldLeaf connection: [2/2]", EMsgType.FAIL);
return; return;
} }
logPrinter.print("GL Initiating GoldLeaf connection: [2/2]", EMsgType.PASS); print("GL Initiating GoldLeaf connection: [2/2]", EMsgType.PASS);
while (true) { while (true) {
readByte = readUsb(); readByte = readUsb();
@ -143,7 +143,7 @@ public class GoldLeaf_05 extends TransferModule {
continue; continue;
} }
if (Arrays.equals(readByte, CMD_Finish)) { if (Arrays.equals(readByte, CMD_Finish)) {
logPrinter.print("GL Closing GoldLeaf connection: Transfer successful.", EMsgType.PASS); print("GL Closing GoldLeaf connection: Transfer successful.", EMsgType.PASS);
status = EFileStatus.UPLOADED; status = EFileStatus.UPLOADED;
break; break;
} }
@ -164,29 +164,29 @@ public class GoldLeaf_05 extends TransferModule {
* false if no issues * false if no issues
* */ * */
private boolean handleConnectionResponse(PFSProvider pfsElement){ private boolean handleConnectionResponse(PFSProvider pfsElement){
logPrinter.print("GL 'ConnectionResponse' command:", EMsgType.INFO); print("GL 'ConnectionResponse' command:", EMsgType.INFO);
if (writeUsb(CMD_GLUC)) { if (writeUsb(CMD_GLUC)) {
logPrinter.print(" [1/4]", EMsgType.FAIL); print(" [1/4]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [1/4]", EMsgType.PASS); print(" [1/4]", EMsgType.PASS);
if (writeUsb(CMD_NSPName)) { if (writeUsb(CMD_NSPName)) {
logPrinter.print(" [2/4]", EMsgType.FAIL); print(" [2/4]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [2/4]", EMsgType.PASS); print(" [2/4]", EMsgType.PASS);
if (writeUsb(pfsElement.getBytesNspFileNameLength())) { if (writeUsb(pfsElement.getBytesNspFileNameLength())) {
logPrinter.print(" [3/4]", EMsgType.FAIL); print(" [3/4]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [3/4]", EMsgType.PASS); print(" [3/4]", EMsgType.PASS);
if (writeUsb(pfsElement.getBytesNspFileName())) { if (writeUsb(pfsElement.getBytesNspFileName())) {
logPrinter.print(" [4/4]", EMsgType.FAIL); print(" [4/4]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [4/4]", EMsgType.PASS); print(" [4/4]", EMsgType.PASS);
return false; return false;
} }
@ -196,50 +196,50 @@ public class GoldLeaf_05 extends TransferModule {
* false if no issues * false if no issues
* */ * */
private boolean handleStart(PFSProvider pfsElement){ private boolean handleStart(PFSProvider pfsElement){
logPrinter.print("GL Handle 'Start' command:", EMsgType.INFO); print("GL Handle 'Start' command:", EMsgType.INFO);
if (writeUsb(CMD_GLUC)) { if (writeUsb(CMD_GLUC)) {
logPrinter.print(" [Prefix]", EMsgType.FAIL); print(" [Prefix]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [Prefix]", EMsgType.PASS); print(" [Prefix]", EMsgType.PASS);
if (writeUsb(CMD_NSPData)) { if (writeUsb(CMD_NSPData)) {
logPrinter.print(" [Command]", EMsgType.FAIL); print(" [Command]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [Command]", EMsgType.PASS); print(" [Command]", EMsgType.PASS);
if (writeUsb(pfsElement.getBytesCountOfNca())) { if (writeUsb(pfsElement.getBytesCountOfNca())) {
logPrinter.print(" [Sub-files count]", EMsgType.FAIL); print(" [Sub-files count]", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [Sub-files count]", EMsgType.PASS); print(" [Sub-files count]", EMsgType.PASS);
int ncaCount = pfsElement.getIntCountOfNca(); int ncaCount = pfsElement.getIntCountOfNca();
logPrinter.print(" [Information for "+ncaCount+" sub-files]", EMsgType.INFO); print(" [Information for "+ncaCount+" sub-files]", EMsgType.INFO);
for (int i = 0; i < ncaCount; i++){ for (int i = 0; i < ncaCount; i++){
logPrinter.print("File #"+i, EMsgType.INFO); print("File #"+i, EMsgType.INFO);
if (writeUsb(pfsElement.getNca(i).getNcaFileNameLength())) { if (writeUsb(pfsElement.getNca(i).getNcaFileNameLength())) {
logPrinter.print(" [1/4] Name length", EMsgType.FAIL); print(" [1/4] Name length", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [1/4] Name length", EMsgType.PASS); print(" [1/4] Name length", EMsgType.PASS);
if (writeUsb(pfsElement.getNca(i).getNcaFileName())) { if (writeUsb(pfsElement.getNca(i).getNcaFileName())) {
logPrinter.print(" [2/4] Name", EMsgType.FAIL); print(" [2/4] Name", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [2/4] Name", EMsgType.PASS); print(" [2/4] Name", EMsgType.PASS);
if (writeUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getBodySize()+pfsElement.getNca(i).getNcaOffset()).array())) { // offset. real. if (writeUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getBodySize()+pfsElement.getNca(i).getNcaOffset()).array())) { // offset. real.
logPrinter.print(" [3/4] Offset", EMsgType.FAIL); print(" [3/4] Offset", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [3/4] Offset", EMsgType.PASS); print(" [3/4] Offset", EMsgType.PASS);
if (writeUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getNca(i).getNcaSize()).array())) { // size if (writeUsb(ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(pfsElement.getNca(i).getNcaSize()).array())) { // size
logPrinter.print(" [4/4] Size", EMsgType.FAIL); print(" [4/4] Size", EMsgType.FAIL);
return true; return true;
} }
logPrinter.print(" [4/4] Size", EMsgType.PASS); print(" [4/4] Size", EMsgType.PASS);
} }
return false; return false;
} }
@ -254,18 +254,18 @@ public class GoldLeaf_05 extends TransferModule {
int requestedNcaID; int requestedNcaID;
if (isItRawRequest) { if (isItRawRequest) {
logPrinter.print("GL Handle 'Content' command", EMsgType.INFO); print("GL Handle 'Content' command", EMsgType.INFO);
byte[] readByte = readUsb(); byte[] readByte = readUsb();
if (readByte == null || readByte.length != 4) { if (readByte == null || readByte.length != 4) {
logPrinter.print(" [Read requested ID]", EMsgType.FAIL); print(" [Read requested ID]", EMsgType.FAIL);
return true; return true;
} }
requestedNcaID = ByteBuffer.wrap(readByte).order(ByteOrder.LITTLE_ENDIAN).getInt(); requestedNcaID = ByteBuffer.wrap(readByte).order(ByteOrder.LITTLE_ENDIAN).getInt();
logPrinter.print(" [Read requested ID = "+requestedNcaID+" ]", EMsgType.PASS); print(" [Read requested ID = "+requestedNcaID+" ]", EMsgType.PASS);
} }
else { else {
requestedNcaID = pfsElement.getNcaTicketID(); requestedNcaID = pfsElement.getNcaTicketID();
logPrinter.print("GL Handle 'Ticket' command (ID = "+requestedNcaID+" )", EMsgType.INFO); print("GL Handle 'Ticket' command (ID = "+requestedNcaID+" )", EMsgType.INFO);
} }
long realNcaOffset = pfsElement.getNca(requestedNcaID).getNcaOffset()+pfsElement.getBodySize(); long realNcaOffset = pfsElement.getNca(requestedNcaID).getNcaOffset()+pfsElement.getBodySize();
@ -317,8 +317,8 @@ public class GoldLeaf_05 extends TransferModule {
logPrinter.updateProgress(1.0); logPrinter.updateProgress(1.0);
//-----------------------------------------/ //-----------------------------------------/
} }
catch (IOException ioe){ catch (IOException | InterruptedException ioe){
logPrinter.print("GL Failed to read NCA ID "+requestedNcaID+". IO Exception:\n "+ioe.getMessage(), EMsgType.FAIL); print("GL Failed to read NCA ID "+requestedNcaID+". Exception:\n "+ioe.getMessage(), EMsgType.FAIL);
ioe.printStackTrace(); ioe.printStackTrace();
return true; return true;
} }
@ -345,18 +345,18 @@ public class GoldLeaf_05 extends TransferModule {
if (writeBufTransferred.get() == message.length) if (writeBufTransferred.get() == message.length)
return false; return false;
else { else {
logPrinter.print("GL Data transfer issue [write]\n Requested: "+message.length+"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL); print("GL Data transfer issue [write]\n Requested: "+message.length+"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
return true; return true;
} }
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [write]\n Returned: "+ UsbErrorCodes.getErrCode(result), EMsgType.FAIL); print("GL Data transfer issue [write]\n Returned: "+ UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
logPrinter.print("GL Execution stopped", EMsgType.FAIL); print("GL Execution stopped", EMsgType.FAIL);
return true; return true;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return true; return true;
} }
/** /**
@ -382,12 +382,12 @@ public class GoldLeaf_05 extends TransferModule {
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [read]\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL); print("GL Data transfer issue [read]\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
logPrinter.print("GL Execution stopped", EMsgType.FAIL); print("GL Execution stopped", EMsgType.FAIL);
return null; return null;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return null; return null;
} }
} }

View file

@ -69,7 +69,11 @@ class GoldLeaf_07 extends TransferModule {
// For using in CMD_SelectFile with SPEC:/ prefix // For using in CMD_SelectFile with SPEC:/ prefix
private File selectedFile; private File selectedFile;
GoldLeaf_07(DeviceHandle handler, LinkedHashMap<String, File> nspMap, CancellableRunnable task, ILogPrinter logPrinter, boolean nspFilter){ GoldLeaf_07(DeviceHandle handler,
LinkedHashMap<String, File> nspMap,
CancellableRunnable task,
ILogPrinter logPrinter,
boolean nspFilter){
super(handler, nspMap, task, logPrinter); super(handler, nspMap, task, logPrinter);
final byte CMD_GetDriveCount = 0x00; final byte CMD_GetDriveCount = 0x00;
@ -93,7 +97,7 @@ class GoldLeaf_07 extends TransferModule {
this.nspFilterForGl = nspFilter; this.nspFilterForGl = nspFilter;
logPrinter.print("============= GoldLeaf v0.7.x =============\n\t" + print("============= GoldLeaf v0.7.x =============\n\t" +
"VIRT:/ equals files added into the application\n\t" + "VIRT:/ equals files added into the application\n\t" +
"HOME:/ equals " "HOME:/ equals "
+System.getProperty("user.home"), EMsgType.INFO); +System.getProperty("user.home"), EMsgType.INFO);
@ -260,7 +264,7 @@ class GoldLeaf_07 extends TransferModule {
byte[] drivesCnt = intToArrLE(2); //2 byte[] drivesCnt = intToArrLE(2); //2
// Write count of drives // Write count of drives
if (writeGL_PASS(drivesCnt)) { if (writeGL_PASS(drivesCnt)) {
logPrinter.print("GL Handle 'ListDrives' command", EMsgType.FAIL); print("GL Handle 'ListDrives' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -316,7 +320,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(totalSize); command.add(totalSize);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetDriveInfo' command", EMsgType.FAIL); print("GL Handle 'GetDriveInfo' command", EMsgType.FAIL);
return true; return true;
} }
@ -332,7 +336,7 @@ class GoldLeaf_07 extends TransferModule {
byte[] specialPathCnt = intToArrLE(0); byte[] specialPathCnt = intToArrLE(0);
// Write count of special paths // Write count of special paths
if (writeGL_PASS(specialPathCnt)) { if (writeGL_PASS(specialPathCnt)) {
logPrinter.print("GL Handle 'SpecialPathCount' command", EMsgType.FAIL); print("GL Handle 'SpecialPathCount' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -354,13 +358,13 @@ class GoldLeaf_07 extends TransferModule {
if (path.equals("VIRT:/")) { if (path.equals("VIRT:/")) {
if (isGetDirectoryCount){ if (isGetDirectoryCount){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else { else {
if (writeGL_PASS(intToArrLE(nspMap.size()))) { if (writeGL_PASS(intToArrLE(nspMap.size()))) {
logPrinter.print("GL Handle 'GetFileCount' command Count = "+nspMap.size(), EMsgType.FAIL); print("GL Handle 'GetFileCount' command Count = "+nspMap.size(), EMsgType.FAIL);
return true; return true;
} }
} }
@ -401,7 +405,7 @@ class GoldLeaf_07 extends TransferModule {
// If somehow there are no folders, let's say 0; // If somehow there are no folders, let's say 0;
if (filesOrDirs == null){ if (filesOrDirs == null){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -415,20 +419,20 @@ class GoldLeaf_07 extends TransferModule {
this.recentFiles = filesOrDirs; this.recentFiles = filesOrDirs;
// Otherwise, let's tell how may folders are in there // Otherwise, let's tell how may folders are in there
if (writeGL_PASS(intToArrLE(filesOrDirs.length))) { if (writeGL_PASS(intToArrLE(filesOrDirs.length))) {
logPrinter.print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else if (path.startsWith("SPEC:/")){ else if (path.startsWith("SPEC:/")){
if (isGetDirectoryCount){ // If dir request then 0 dirs if (isGetDirectoryCount){ // If dir request then 0 dirs
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else if (selectedFile != null){ // Else it's file request, if we have selected then we will report 1. else if (selectedFile != null){ // Else it's file request, if we have selected then we will report 1.
if (writeGL_PASS(intToArrLE(1))) { if (writeGL_PASS(intToArrLE(1))) {
logPrinter.print("GL Handle 'GetFileCount' command Count = 1", EMsgType.FAIL); print("GL Handle 'GetFileCount' command Count = 1", EMsgType.FAIL);
return true; return true;
} }
} }
@ -482,7 +486,7 @@ class GoldLeaf_07 extends TransferModule {
// return proxyGetDirFile(true); // return proxyGetDirFile(true);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetDirectory' command.", EMsgType.FAIL); print("GL Handle 'GetDirectory' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -539,7 +543,7 @@ class GoldLeaf_07 extends TransferModule {
//if (proxyForGL) // TODO: NOTE: PROXY TAILS //if (proxyForGL) // TODO: NOTE: PROXY TAILS
// return proxyGetDirFile(false); // return proxyGetDirFile(false);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -550,7 +554,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7
command.add(fileNameBytes); command.add(fileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -562,7 +566,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7
command.add(fileNameBytes); command.add(fileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -593,7 +597,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(longToArrLE(fileDirElement.length())); command.add(longToArrLE(fileDirElement.length()));
} }
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -610,7 +614,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG! command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG!
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -623,7 +627,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(GL_OBJ_TYPE_FILE); command.add(GL_OBJ_TYPE_FILE);
command.add(longToArrLE(selectedFile.length())); command.add(longToArrLE(selectedFile.length()));
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -651,7 +655,7 @@ class GoldLeaf_07 extends TransferModule {
try { try {
if (currentFile.renameTo(newFile)){ if (currentFile.renameTo(newFile)){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Rename' command.", EMsgType.FAIL); print("GL Handle 'Rename' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -676,7 +680,7 @@ class GoldLeaf_07 extends TransferModule {
try { try {
if (fileToDel.delete()){ if (fileToDel.delete()){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Rename' command.", EMsgType.FAIL); print("GL Handle 'Rename' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -714,10 +718,10 @@ class GoldLeaf_07 extends TransferModule {
} }
if (result){ if (result){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Create' command.", EMsgType.FAIL); print("GL Handle 'Create' command.", EMsgType.FAIL);
return true; return true;
} }
//logPrinter.print("GL Handle 'Create' command.", EMsgType.PASS); //print("GL Handle 'Create' command.", EMsgType.PASS);
return false; return false;
} }
} }
@ -802,12 +806,12 @@ class GoldLeaf_07 extends TransferModule {
"\n Received: " + bytesRead); "\n Received: " + bytesRead);
// Let's tell as a command about our result. // Let's tell as a command about our result.
if (writeGL_PASS(longToArrLE(size))) { if (writeGL_PASS(longToArrLE(size))) {
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
return true; return true;
} }
// Let's bypass bytes we read total // Let's bypass bytes we read total
if (writeToUsb(chunk)) { if (writeToUsb(chunk)) {
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL); print("GL Handle 'ReadFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -822,12 +826,12 @@ class GoldLeaf_07 extends TransferModule {
return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead); return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead);
// Let's tell as a command about our result. // Let's tell as a command about our result.
if (writeGL_PASS(longToArrLE(size))) { if (writeGL_PASS(longToArrLE(size))) {
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
return true; return true;
} }
// Let's bypass bytes we read total // Let's bypass bytes we read total
if (writeToUsb(chunk)) { if (writeToUsb(chunk)) {
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL); print("GL Handle 'ReadFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -839,14 +843,14 @@ class GoldLeaf_07 extends TransferModule {
} }
catch (NullPointerException ignored){} catch (NullPointerException ignored){}
catch (IOException ioe_){ catch (IOException ioe_){
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
} }
try{ try{
splitReader.close(); splitReader.close();
} }
catch (NullPointerException ignored){} catch (NullPointerException ignored){}
catch (IOException ioe_){ catch (IOException ioe_){
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
} }
openReadFileNameAndPath = null; openReadFileNameAndPath = null;
randAccessFile = null; randAccessFile = null;
@ -888,7 +892,7 @@ class GoldLeaf_07 extends TransferModule {
byte[] transferredData; byte[] transferredData;
if ((transferredData = readGL_file()) == null){ if ((transferredData = readGL_file()) == null){
logPrinter.print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL); print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL);
return true; return true;
} }
try{ try{
@ -899,7 +903,7 @@ class GoldLeaf_07 extends TransferModule {
} }
// Report we're good // Report we're good
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'WriteFile' command", EMsgType.FAIL); print("GL Handle 'WriteFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -926,7 +930,7 @@ class GoldLeaf_07 extends TransferModule {
command.add(intToArrLE(selectedFileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(selectedFileNameBytes.length / 2)); // since GL 0.7
command.add(selectedFileNameBytes); command.add(selectedFileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'SelectFile' command", EMsgType.FAIL); print("GL Handle 'SelectFile' command", EMsgType.FAIL);
this.selectedFile = null; this.selectedFile = null;
return true; return true;
} }
@ -1006,13 +1010,13 @@ class GoldLeaf_07 extends TransferModule {
closeOpenedReadFilesGl(); // Could be a problem if GL glitches and slow down process. Or if user has extra-slow SD card. TODO: refactor closeOpenedReadFilesGl(); // Could be a problem if GL glitches and slow down process. Or if user has extra-slow SD card. TODO: refactor
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [read]\n Returned: " + print("GL Data transfer issue [read]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return null; return null;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return null; return null;
} }
private byte[] readGL_file(){ private byte[] readGL_file(){
@ -1035,13 +1039,13 @@ class GoldLeaf_07 extends TransferModule {
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [read]\n Returned: " + print("GL Data transfer issue [read]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return null; return null;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return null; return null;
} }
/** /**
@ -1066,10 +1070,10 @@ class GoldLeaf_07 extends TransferModule {
private boolean writeGL_FAIL(String reportToUImsg){ private boolean writeGL_FAIL(String reportToUImsg){
if (writeToUsb(Arrays.copyOf(CMD_GLCO_FAILURE, 4096))){ if (writeToUsb(Arrays.copyOf(CMD_GLCO_FAILURE, 4096))){
logPrinter.print(reportToUImsg, EMsgType.WARNING); print(reportToUImsg, EMsgType.WARNING);
return true; return true;
} }
logPrinter.print(reportToUImsg, EMsgType.FAIL); print(reportToUImsg, EMsgType.FAIL);
return false; return false;
} }
/** /**
@ -1091,7 +1095,7 @@ class GoldLeaf_07 extends TransferModule {
if (writeBufTransferred.get() == message.length) if (writeBufTransferred.get() == message.length)
return false; return false;
else { else {
logPrinter.print("GL Data transfer issue [write]\n Requested: " + print("GL Data transfer issue [write]\n Requested: " +
message.length + message.length +
"\n Transferred: " + "\n Transferred: " +
writeBufTransferred.get(), EMsgType.FAIL); writeBufTransferred.get(), EMsgType.FAIL);
@ -1100,13 +1104,13 @@ class GoldLeaf_07 extends TransferModule {
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [write]\n Returned: " + print("GL Data transfer issue [write]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return true; return true;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return true; return true;
} }

View file

@ -103,7 +103,7 @@ class GoldLeaf_08 extends TransferModule {
this.nspFilterForGl = nspFilter; this.nspFilterForGl = nspFilter;
logPrinter.print("============= GoldLeaf v0.8 =============\n\t" + print("============= GoldLeaf v0.8 =============\n\t" +
"VIRT:/ equals files added into the application\n\t" + "VIRT:/ equals files added into the application\n\t" +
"HOME:/ equals " "HOME:/ equals "
+System.getProperty("user.home"), EMsgType.INFO); +System.getProperty("user.home"), EMsgType.INFO);
@ -273,7 +273,7 @@ class GoldLeaf_08 extends TransferModule {
* */ * */
private boolean startOrEndFile(){ private boolean startOrEndFile(){
if (writeGL_PASS()){ if (writeGL_PASS()){
logPrinter.print("GL Handle 'StartFile' command", EMsgType.FAIL); print("GL Handle 'StartFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -288,7 +288,7 @@ class GoldLeaf_08 extends TransferModule {
byte[] drivesCnt = intToArrLE(2); //2 byte[] drivesCnt = intToArrLE(2); //2
// Write count of drives // Write count of drives
if (writeGL_PASS(drivesCnt)) { if (writeGL_PASS(drivesCnt)) {
logPrinter.print("GL Handle 'ListDrives' command", EMsgType.FAIL); print("GL Handle 'ListDrives' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -344,7 +344,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(totalSize); command.add(totalSize);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetDriveInfo' command", EMsgType.FAIL); print("GL Handle 'GetDriveInfo' command", EMsgType.FAIL);
return true; return true;
} }
@ -360,7 +360,7 @@ class GoldLeaf_08 extends TransferModule {
byte[] specialPathCnt = intToArrLE(0); byte[] specialPathCnt = intToArrLE(0);
// Write count of special paths // Write count of special paths
if (writeGL_PASS(specialPathCnt)) { if (writeGL_PASS(specialPathCnt)) {
logPrinter.print("GL Handle 'SpecialPathCount' command", EMsgType.FAIL); print("GL Handle 'SpecialPathCount' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -382,13 +382,13 @@ class GoldLeaf_08 extends TransferModule {
if (path.equals("VIRT:/")) { if (path.equals("VIRT:/")) {
if (isGetDirectoryCount){ if (isGetDirectoryCount){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else { else {
if (writeGL_PASS(intToArrLE(nspMap.size()))) { if (writeGL_PASS(intToArrLE(nspMap.size()))) {
logPrinter.print("GL Handle 'GetFileCount' command Count = "+nspMap.size(), EMsgType.FAIL); print("GL Handle 'GetFileCount' command Count = "+nspMap.size(), EMsgType.FAIL);
return true; return true;
} }
} }
@ -429,7 +429,7 @@ class GoldLeaf_08 extends TransferModule {
// If somehow there are no folders, let's say 0; // If somehow there are no folders, let's say 0;
if (filesOrDirs == null){ if (filesOrDirs == null){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -443,20 +443,20 @@ class GoldLeaf_08 extends TransferModule {
this.recentFiles = filesOrDirs; this.recentFiles = filesOrDirs;
// Otherwise, let's tell how may folders are in there // Otherwise, let's tell how may folders are in there
if (writeGL_PASS(intToArrLE(filesOrDirs.length))) { if (writeGL_PASS(intToArrLE(filesOrDirs.length))) {
logPrinter.print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else if (path.startsWith("SPEC:/")){ else if (path.startsWith("SPEC:/")){
if (isGetDirectoryCount){ // If dir request then 0 dirs if (isGetDirectoryCount){ // If dir request then 0 dirs
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL);
return true; return true;
} }
} }
else if (selectedFile != null){ // Else it's file request, if we have selected then we will report 1. else if (selectedFile != null){ // Else it's file request, if we have selected then we will report 1.
if (writeGL_PASS(intToArrLE(1))) { if (writeGL_PASS(intToArrLE(1))) {
logPrinter.print("GL Handle 'GetFileCount' command Count = 1", EMsgType.FAIL); print("GL Handle 'GetFileCount' command Count = 1", EMsgType.FAIL);
return true; return true;
} }
} }
@ -510,7 +510,7 @@ class GoldLeaf_08 extends TransferModule {
// return proxyGetDirFile(true); // return proxyGetDirFile(true);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetDirectory' command.", EMsgType.FAIL); print("GL Handle 'GetDirectory' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -567,7 +567,7 @@ class GoldLeaf_08 extends TransferModule {
//if (proxyForGL) // TODO: NOTE: PROXY TAILS //if (proxyForGL) // TODO: NOTE: PROXY TAILS
// return proxyGetDirFile(false); // return proxyGetDirFile(false);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -578,7 +578,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7
command.add(fileNameBytes); command.add(fileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -590,7 +590,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(fileNameBytes.length / 2)); // since GL 0.7
command.add(fileNameBytes); command.add(fileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'GetFile' command.", EMsgType.FAIL); print("GL Handle 'GetFile' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -621,7 +621,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(longToArrLE(fileDirElement.length())); command.add(longToArrLE(fileDirElement.length()));
} }
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -638,7 +638,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG! command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG!
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -651,7 +651,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(GL_OBJ_TYPE_FILE); command.add(GL_OBJ_TYPE_FILE);
command.add(longToArrLE(selectedFile.length())); command.add(longToArrLE(selectedFile.length()));
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'StatPath' command.", EMsgType.FAIL); print("GL Handle 'StatPath' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -679,7 +679,7 @@ class GoldLeaf_08 extends TransferModule {
try { try {
if (currentFile.renameTo(newFile)){ if (currentFile.renameTo(newFile)){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Rename' command.", EMsgType.FAIL); print("GL Handle 'Rename' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -704,7 +704,7 @@ class GoldLeaf_08 extends TransferModule {
try { try {
if (fileToDel.delete()){ if (fileToDel.delete()){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Rename' command.", EMsgType.FAIL); print("GL Handle 'Rename' command.", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -742,10 +742,10 @@ class GoldLeaf_08 extends TransferModule {
} }
if (result){ if (result){
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'Create' command.", EMsgType.FAIL); print("GL Handle 'Create' command.", EMsgType.FAIL);
return true; return true;
} }
//logPrinter.print("GL Handle 'Create' command.", EMsgType.PASS); //print("GL Handle 'Create' command.", EMsgType.PASS);
return false; return false;
} }
} }
@ -830,12 +830,12 @@ class GoldLeaf_08 extends TransferModule {
"\n Received: " + bytesRead); "\n Received: " + bytesRead);
// Let's tell as a command about our result. // Let's tell as a command about our result.
if (writeGL_PASS(longToArrLE(size))) { if (writeGL_PASS(longToArrLE(size))) {
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
return true; return true;
} }
// Let's bypass bytes we read total // Let's bypass bytes we read total
if (writeToUsb(chunk)) { if (writeToUsb(chunk)) {
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL); print("GL Handle 'ReadFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -850,12 +850,12 @@ class GoldLeaf_08 extends TransferModule {
return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead); return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead);
// Let's tell as a command about our result. // Let's tell as a command about our result.
if (writeGL_PASS(longToArrLE(size))) { if (writeGL_PASS(longToArrLE(size))) {
logPrinter.print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL);
return true; return true;
} }
// Let's bypass bytes we read total // Let's bypass bytes we read total
if (writeToUsb(chunk)) { if (writeToUsb(chunk)) {
logPrinter.print("GL Handle 'ReadFile' command", EMsgType.FAIL); print("GL Handle 'ReadFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -867,14 +867,14 @@ class GoldLeaf_08 extends TransferModule {
} }
catch (NullPointerException ignored){} catch (NullPointerException ignored){}
catch (IOException ioe_){ catch (IOException ioe_){
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
} }
try{ try{
splitReader.close(); splitReader.close();
} }
catch (NullPointerException ignored){} catch (NullPointerException ignored){}
catch (IOException ioe_){ catch (IOException ioe_){
logPrinter.print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
} }
openReadFileNameAndPath = null; openReadFileNameAndPath = null;
randAccessFile = null; randAccessFile = null;
@ -916,7 +916,7 @@ class GoldLeaf_08 extends TransferModule {
byte[] transferredData; byte[] transferredData;
if ((transferredData = readGL_file()) == null){ if ((transferredData = readGL_file()) == null){
logPrinter.print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL); print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL);
return true; return true;
} }
try{ try{
@ -927,7 +927,7 @@ class GoldLeaf_08 extends TransferModule {
} }
// Report we're good // Report we're good
if (writeGL_PASS()) { if (writeGL_PASS()) {
logPrinter.print("GL Handle 'WriteFile' command", EMsgType.FAIL); print("GL Handle 'WriteFile' command", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -957,7 +957,7 @@ class GoldLeaf_08 extends TransferModule {
command.add(intToArrLE(selectedFileNameBytes.length / 2)); // since GL 0.7 command.add(intToArrLE(selectedFileNameBytes.length / 2)); // since GL 0.7
command.add(selectedFileNameBytes); command.add(selectedFileNameBytes);
if (writeGL_PASS(command)) { if (writeGL_PASS(command)) {
logPrinter.print("GL Handle 'SelectFile' command", EMsgType.FAIL); print("GL Handle 'SelectFile' command", EMsgType.FAIL);
this.selectedFile = null; this.selectedFile = null;
return true; return true;
} }
@ -1033,13 +1033,13 @@ class GoldLeaf_08 extends TransferModule {
closeOpenedReadFilesGl(); // Could be a problem if GL glitches and slow down process. Or if user has extra-slow SD card. TODO: refactor closeOpenedReadFilesGl(); // Could be a problem if GL glitches and slow down process. Or if user has extra-slow SD card. TODO: refactor
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [read]\n Returned: " + print("GL Data transfer issue [read]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return null; return null;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return null; return null;
} }
private byte[] readGL_file(){ private byte[] readGL_file(){
@ -1060,13 +1060,13 @@ class GoldLeaf_08 extends TransferModule {
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [read]\n Returned: " + print("GL Data transfer issue [read]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return null; return null;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return null; return null;
} }
/** /**
@ -1091,10 +1091,10 @@ class GoldLeaf_08 extends TransferModule {
private boolean writeGL_FAIL(String reportToUImsg){ private boolean writeGL_FAIL(String reportToUImsg){
if (writeToUsb(Arrays.copyOf(CMD_GLCO_FAILURE, 4096))){ if (writeToUsb(Arrays.copyOf(CMD_GLCO_FAILURE, 4096))){
logPrinter.print(reportToUImsg, EMsgType.WARNING); print(reportToUImsg, EMsgType.WARNING);
return true; return true;
} }
logPrinter.print(reportToUImsg, EMsgType.FAIL); print(reportToUImsg, EMsgType.FAIL);
return false; return false;
} }
/** /**
@ -1116,7 +1116,7 @@ class GoldLeaf_08 extends TransferModule {
if (writeBufTransferred.get() == message.length) if (writeBufTransferred.get() == message.length)
return false; return false;
else { else {
logPrinter.print("GL Data transfer issue [write]\n Requested: " + print("GL Data transfer issue [write]\n Requested: " +
message.length + message.length +
"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL); "\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
return true; return true;
@ -1124,13 +1124,13 @@ class GoldLeaf_08 extends TransferModule {
case LibUsb.ERROR_TIMEOUT: case LibUsb.ERROR_TIMEOUT:
continue; continue;
default: default:
logPrinter.print("GL Data transfer issue [write]\n Returned: " + print("GL Data transfer issue [write]\n Returned: " +
UsbErrorCodes.getErrCode(result) + UsbErrorCodes.getErrCode(result) +
"\n GL Execution stopped", EMsgType.FAIL); "\n GL Execution stopped", EMsgType.FAIL);
return true; return true;
} }
} }
logPrinter.print("GL Execution interrupted", EMsgType.INFO); print("GL Execution interrupted", EMsgType.INFO);
return true; return true;
} }
} }

View file

@ -50,7 +50,7 @@ class TinFoil extends TransferModule {
TinFoil(DeviceHandle handler, LinkedHashMap<String, File> nspMap, CancellableRunnable task, ILogPrinter logPrinter){ TinFoil(DeviceHandle handler, LinkedHashMap<String, File> nspMap, CancellableRunnable task, ILogPrinter logPrinter){
super(handler, nspMap, task, logPrinter); super(handler, nspMap, task, logPrinter);
logPrinter.print("============= Tinfoil =============", EMsgType.INFO); print("============= Tinfoil =============", EMsgType.INFO);
if (! sendListOfFiles()) if (! sendListOfFiles())
return; return;
@ -69,25 +69,25 @@ class TinFoil extends TransferModule {
byte[] padding = new byte[8]; byte[] padding = new byte[8];
if (writeUsb(TUL0)) { if (writeUsb(TUL0)) {
logPrinter.print("TF Send list of files: handshake [1/4]", EMsgType.FAIL); print("TF Send list of files: handshake [1/4]", EMsgType.FAIL);
return false; return false;
} }
if (writeUsb(nspListNamesSize)) { // size of the list we can transfer if (writeUsb(nspListNamesSize)) { // size of the list we can transfer
logPrinter.print("TF Send list of files: list length [2/4]", EMsgType.FAIL); print("TF Send list of files: list length [2/4]", EMsgType.FAIL);
return false; return false;
} }
if (writeUsb(padding)) { if (writeUsb(padding)) {
logPrinter.print("TF Send list of files: padding [3/4]", EMsgType.FAIL); print("TF Send list of files: padding [3/4]", EMsgType.FAIL);
return false; return false;
} }
if (writeUsb(nspListNames)) { if (writeUsb(nspListNames)) {
logPrinter.print("TF Send list of files: list itself [4/4]", EMsgType.FAIL); print("TF Send list of files: list itself [4/4]", EMsgType.FAIL);
return false; return false;
} }
logPrinter.print("TF Send list of files complete.", EMsgType.PASS); print("TF Send list of files complete.", EMsgType.PASS);
return true; return true;
} }
@ -114,7 +114,7 @@ class TinFoil extends TransferModule {
* After we sent commands to NS, this chain starts * After we sent commands to NS, this chain starts
* */ * */
private boolean proceedCommands(){ private boolean proceedCommands(){
logPrinter.print("TF Awaiting for NS commands.", EMsgType.INFO); print("TF Awaiting for NS commands.", EMsgType.INFO);
try{ try{
byte[] deviceReply; byte[] deviceReply;
byte command; byte command;
@ -127,18 +127,18 @@ class TinFoil extends TransferModule {
switch (command){ switch (command){
case CMD_EXIT: case CMD_EXIT:
logPrinter.print("TF Transfer complete.", EMsgType.PASS); print("TF Transfer complete.", EMsgType.PASS);
return true; return true;
case CMD_FILE_RANGE_DEFAULT: case CMD_FILE_RANGE_DEFAULT:
case CMD_FILE_RANGE_ALTERNATIVE: case CMD_FILE_RANGE_ALTERNATIVE:
//logPrinter.print("TF Received 'FILE RANGE' command [0x0"+command+"].", EMsgType.PASS); //print("TF Received 'FILE RANGE' command [0x0"+command+"].", EMsgType.PASS);
if (fileRangeCmd()) if (fileRangeCmd())
return false; // catches exception return false; // catches exception
} }
} }
} }
catch (Exception e){ catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.INFO); print(e.getMessage(), EMsgType.INFO);
return false; return false;
} }
} }
@ -169,7 +169,7 @@ class TinFoil extends TransferModule {
String nspFileName = new String(receivedArray, StandardCharsets.UTF_8); String nspFileName = new String(receivedArray, StandardCharsets.UTF_8);
logPrinter.print(String.format("TF Reply to: %s" + print(String.format("TF Reply to: %s" +
"\n Offset: %-20d 0x%x" + "\n Offset: %-20d 0x%x" +
"\n Size: %-20d 0x%x", "\n Size: %-20d 0x%x",
nspFileName, nspFileName,
@ -188,28 +188,28 @@ class TinFoil extends TransferModule {
else else
sendNormalFile(nspFile, size, offset); sendNormalFile(nspFile, size, offset);
} catch (IOException ioe){ } catch (IOException ioe){
logPrinter.print("TF IOException:\n "+ioe.getMessage(), EMsgType.FAIL); print("TF IOException:\n "+ioe.getMessage(), EMsgType.FAIL);
ioe.printStackTrace(); ioe.printStackTrace();
return true; return true;
} catch (ArithmeticException ae){ } catch (ArithmeticException ae){
logPrinter.print("TF ArithmeticException (can't cast 'offset end' - 'offsets current' to 'integer'):" + print("TF ArithmeticException (can't cast 'offset end' - 'offsets current' to 'integer'):" +
"\n "+ae.getMessage(), EMsgType.FAIL); "\n "+ae.getMessage(), EMsgType.FAIL);
ae.printStackTrace(); ae.printStackTrace();
return true; return true;
} catch (NullPointerException npe){ } catch (NullPointerException npe){
logPrinter.print("TF NullPointerException (in some moment application didn't find something. Something important.):" + print("TF NullPointerException (in some moment application didn't find something. Something important.):" +
"\n "+npe.getMessage(), EMsgType.FAIL); "\n "+npe.getMessage(), EMsgType.FAIL);
npe.printStackTrace(); npe.printStackTrace();
return true; return true;
} }
catch (Exception defe){ catch (Exception defe){
logPrinter.print(defe.getMessage(), EMsgType.FAIL); print(defe.getMessage(), EMsgType.FAIL);
return true; return true;
} }
return false; return false;
} }
void sendSplitFile(File nspFile, long size, long offset) throws IOException, NullPointerException, ArithmeticException { void sendSplitFile(File nspFile, long size, long offset) throws Exception {
byte[] readBuffer; byte[] readBuffer;
long currentOffset = 0; long currentOffset = 0;
int chunk = 8388608; // = 8Mb; int chunk = 8388608; // = 8Mb;
@ -237,7 +237,7 @@ class TinFoil extends TransferModule {
logPrinter.updateProgress(1.0); logPrinter.updateProgress(1.0);
} }
void sendNormalFile(File nspFile, long size, long offset) throws IOException, NullPointerException, ArithmeticException { void sendNormalFile(File nspFile, long size, long offset) throws Exception {
byte[] readBuffer; byte[] readBuffer;
long currentOffset = 0; long currentOffset = 0;
int chunk = 8388608; int chunk = 8388608;
@ -278,17 +278,17 @@ class TinFoil extends TransferModule {
final byte[] twelveZeroBytes = new byte[12]; final byte[] twelveZeroBytes = new byte[12];
if (writeUsb(standardReplyBytes)){ // Send integer value of '1' in Little-endian format. if (writeUsb(standardReplyBytes)){ // Send integer value of '1' in Little-endian format.
logPrinter.print("TF Sending response failed [1/3]", EMsgType.FAIL); print("TF Sending response failed [1/3]", EMsgType.FAIL);
return true; return true;
} }
if(writeUsb(sizeAsBytes)) { // Send EXACTLY what has been received if(writeUsb(sizeAsBytes)) { // Send EXACTLY what has been received
logPrinter.print("TF Sending response failed [2/3]", EMsgType.FAIL); print("TF Sending response failed [2/3]", EMsgType.FAIL);
return true; return true;
} }
if(writeUsb(twelveZeroBytes)) { // kinda another one padding if(writeUsb(twelveZeroBytes)) { // kinda another one padding
logPrinter.print("TF Sending response failed [3/3]", EMsgType.FAIL); print("TF Sending response failed [3/3]", EMsgType.FAIL);
return true; return true;
} }
return false; return false;
@ -308,7 +308,7 @@ class TinFoil extends TransferModule {
while (! task.isCancelled() ) { while (! task.isCancelled() ) {
/* /*
if (varVar != 0) if (varVar != 0)
logPrinter.print("writeUsb() retry cnt: "+varVar, EMsgType.INFO); //NOTE: DEBUG print("writeUsb() retry cnt: "+varVar, EMsgType.INFO); //NOTE: DEBUG
varVar++; varVar++;
*/ */
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01 result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01
@ -317,7 +317,7 @@ class TinFoil extends TransferModule {
case LibUsb.SUCCESS: case LibUsb.SUCCESS:
if (writeBufTransferred.get() == message.length) if (writeBufTransferred.get() == message.length)
return false; return false;
logPrinter.print("TF Data transfer issue [write]" + print("TF Data transfer issue [write]" +
"\n Requested: "+message.length+ "\n Requested: "+message.length+
"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL); "\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
return true; return true;
@ -326,13 +326,13 @@ class TinFoil extends TransferModule {
//writeBufTransferred.clear(); // MUST BE HERE IF WE 'GET()' IT //writeBufTransferred.clear(); // MUST BE HERE IF WE 'GET()' IT
continue; continue;
default: default:
logPrinter.print("TF Data transfer issue [write]" + print("TF Data transfer issue [write]" +
"\n Returned: "+ UsbErrorCodes.getErrCode(result) + "\n Returned: "+ UsbErrorCodes.getErrCode(result) +
"\n (execution stopped)", EMsgType.FAIL); "\n (execution stopped)", EMsgType.FAIL);
return true; return true;
} }
} }
logPrinter.print("TF Execution interrupted", EMsgType.INFO); print("TF Execution interrupted", EMsgType.INFO);
return true; return true;
} }
/** /**

View file

@ -51,7 +51,7 @@ public abstract class TransferModule {
File[] subFiles = f.listFiles((file, name) -> name.matches("[0-9]{2}")); File[] subFiles = f.listFiles((file, name) -> name.matches("[0-9]{2}"));
if (subFiles == null || subFiles.length == 0) { if (subFiles == null || subFiles.length == 0) {
logPrinter.print("TransferModule: Exclude folder: " + f.getName(), EMsgType.WARNING); print("TransferModule: Exclude folder: " + f.getName(), EMsgType.WARNING);
return true; return true;
} }
@ -59,7 +59,7 @@ public abstract class TransferModule {
for (int i = subFiles.length - 2; i > 0 ; i--){ for (int i = subFiles.length - 2; i > 0 ; i--){
if (subFiles[i].length() != subFiles[i-1].length()) { if (subFiles[i].length() != subFiles[i-1].length()) {
logPrinter.print("TransferModule: Exclude split file: "+f.getName()+ print("TransferModule: Exclude split file: "+f.getName()+
"\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING); "\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING);
return true; return true;
} }
@ -69,7 +69,7 @@ public abstract class TransferModule {
long lastFileLength = subFiles[subFiles.length-1].length(); long lastFileLength = subFiles[subFiles.length-1].length();
if (lastFileLength > firstFileLength){ if (lastFileLength > firstFileLength){
logPrinter.print("TransferModule: Exclude split file: "+f.getName()+ print("TransferModule: Exclude split file: "+f.getName()+
"\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING); "\n Chunk sizes of the split file are not the same, but has to be.", EMsgType.WARNING);
return true; return true;
} }
@ -77,4 +77,13 @@ public abstract class TransferModule {
}); });
} }
public EFileStatus getStatus(){ return status; } public EFileStatus getStatus(){ return status; }
void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
} }

View file

@ -49,7 +49,7 @@ public class UsbCommunications extends CancellableRunnable {
@Override @Override
public void run() { public void run() {
logPrinter.print("\tStart", EMsgType.INFO); print("\tStart", EMsgType.INFO);
UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter); UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter);
@ -87,7 +87,15 @@ public class UsbCommunications extends CancellableRunnable {
*/ */
private void close(EFileStatus status){ private void close(EFileStatus status){
logPrinter.update(nspMap, status); logPrinter.update(nspMap, status);
logPrinter.print("\tEnd", EMsgType.INFO); print("\tEnd", EMsgType.INFO);
logPrinter.close(); logPrinter.close();
} }
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
} }

View file

@ -65,7 +65,10 @@ public class UsbConnect {
usbConnect.connected = true; usbConnect.connected = true;
} }
catch (Exception e){ catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL); try {
logPrinter.print(e.getMessage(), EMsgType.FAIL);
}
catch (InterruptedException ignore){}
usbConnect.close(); usbConnect.close();
} }
@ -89,7 +92,10 @@ public class UsbConnect {
} }
catch (Exception e){ catch (Exception e){
e.printStackTrace(); e.printStackTrace();
logPrinter.print(e.getMessage(), EMsgType.FAIL); try {
logPrinter.print(e.getMessage(), EMsgType.FAIL);
}
catch (InterruptedException ignore){}
usbConnect.close(); usbConnect.close();
} }
return usbConnect; return usbConnect;
@ -100,7 +106,7 @@ public class UsbConnect {
private UsbConnect(ILogPrinter logPrinter){ private UsbConnect(ILogPrinter logPrinter){
this.logPrinter = logPrinter; this.logPrinter = logPrinter;
this.connected = false; this.connected = false;
}; }
private void createContextAndInitLibUSB() throws Exception{ private void createContextAndInitLibUSB() throws Exception{
// Creating Context required by libusb. Optional? Consider removing. // Creating Context required by libusb. Optional? Consider removing.
@ -178,7 +184,7 @@ public class UsbConnect {
// Actually, there are no drivers in Linux kernel which uses this device. // Actually, there are no drivers in Linux kernel which uses this device.
returningValue = LibUsb.setAutoDetachKernelDriver(handlerNS, true); returningValue = LibUsb.setAutoDetachKernelDriver(handlerNS, true);
if (returningValue != LibUsb.SUCCESS) if (returningValue != LibUsb.SUCCESS)
logPrinter.print("Skip kernel driver attach & detach ("+UsbErrorCodes.getErrCode(returningValue)+")", EMsgType.INFO); print("Skip kernel driver attach & detach ("+UsbErrorCodes.getErrCode(returningValue)+")", EMsgType.INFO);
} }
/* /*
@ -230,7 +236,7 @@ public class UsbConnect {
returningValue = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE); returningValue = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE);
if (returningValue != LibUsb.SUCCESS) { if (returningValue != LibUsb.SUCCESS) {
logPrinter.print("Release interface failure: " + print("Release interface failure: " +
UsbErrorCodes.getErrCode(returningValue) + UsbErrorCodes.getErrCode(returningValue) +
" (sometimes it's not an issue)", EMsgType.WARNING); " (sometimes it's not an issue)", EMsgType.WARNING);
} }
@ -241,4 +247,13 @@ public class UsbConnect {
if (contextNS != null) if (contextNS != null)
LibUsb.exit(contextNS); LibUsb.exit(contextNS);
} }
private void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
catch (InterruptedException ie){
ie.printStackTrace();
}
}
} }

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.BlockListViewController">
<children>
<ListView fx:id="splitMergeListView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>

View file

@ -42,47 +42,42 @@
</GridPane> </GridPane>
</children> </children>
</VBox> </VBox>
<VBox fillWidth="false" spacing="5.0"> <HBox spacing="15.0" VBox.vgrow="ALWAYS">
<children> <children>
<RadioButton fx:id="splitRad" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_RadioBtn_Split"> <fx:include fx:id="BlockListView" source="BlockListView.fxml" HBox.hgrow="ALWAYS" VBox.vgrow="ALWAYS" />
<toggleGroup> <VBox spacing="5.0">
<ToggleGroup fx:id="splitMergeTogGrp" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="mergeRad" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_RadioBtn_Merge" toggleGroup="$splitMergeTogGrp" />
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</VBox>
<VBox spacing="5.0">
<children>
<HBox>
<children>
<Label fx:id="fileFolderLabelLbl" />
<Label fx:id="fileFolderActualPathLbl" />
</children>
</HBox>
<Button fx:id="selectFileFolderBtn" contentDisplay="TOP" mnemonicParsing="false" />
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</VBox>
<VBox spacing="5.0">
<children>
<HBox>
<children> <children>
<RadioButton fx:id="splitRad" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_RadioBtn_Split">
<toggleGroup>
<ToggleGroup fx:id="splitMergeTogGrp" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="mergeRad" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_RadioBtn_Merge" toggleGroup="$splitMergeTogGrp" />
<Button fx:id="selectFileFolderBtn" contentDisplay="TOP" mnemonicParsing="false">
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Button>
<Label text="%tabSplMrg_Lbl_SaveToLocation" /> <Label text="%tabSplMrg_Lbl_SaveToLocation" />
<Label fx:id="saveToPathLbl" /> <Label fx:id="saveToPathLbl" maxWidth="200.0" textOverrun="CENTER_WORD_ELLIPSIS" />
<Button fx:id="changeSaveToBtn" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_Btn_ChangeSaveToLocation" />
<Pane VBox.vgrow="ALWAYS" />
<VBox>
<children>
<HBox alignment="CENTER">
<children>
<Button fx:id="convertBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabSplMrg_Btn_Convert" />
</children>
</HBox>
</children>
</VBox>
</children> </children>
</HBox> </VBox>
<Button fx:id="changeSaveToBtn" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_Btn_ChangeSaveToLocation" />
</children> </children>
<VBox.margin> <VBox.margin>
<Insets left="15.0" right="15.0" /> <Insets left="15.0" right="15.0" />
</VBox.margin> </VBox.margin>
</VBox> </HBox>
<HBox alignment="CENTER"> <HBox alignment="CENTER">
<children> <children>
<Label fx:id="statusLbl" /> <Label fx:id="statusLbl" />
@ -91,16 +86,6 @@
<Insets left="15.0" right="15.0" /> <Insets left="15.0" right="15.0" />
</VBox.margin> </VBox.margin>
</HBox> </HBox>
<Pane VBox.vgrow="ALWAYS" />
<VBox>
<children>
<HBox alignment="CENTER">
<children>
<Button fx:id="convertBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabSplMrg_Btn_Convert" />
</children>
</HBox>
</children>
</VBox>
<padding> <padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding> </padding>

View file

@ -205,6 +205,7 @@
.table-view .table-cell{ .table-view .table-cell{
-fx-text-fill: #f7fafa; -fx-text-fill: #f7fafa;
} }
.table-row-cell, .table-row-cell:selected, .table-row-cell:filled:selected{ .table-row-cell, .table-row-cell:selected, .table-row-cell:filled:selected{
-fx-background-color: -fx-table-cell-border-color, #424242; -fx-background-color: -fx-table-cell-border-color, #424242;
-fx-background-insets: 0, 0 0 1 0; -fx-background-insets: 0, 0 0 1 0;
@ -223,7 +224,35 @@
-fx-padding: 0.0em; /* 0 */ -fx-padding: 0.0em; /* 0 */
-fx-table-cell-border-color: #6d8484; -fx-table-cell-border-color: #6d8484;
} }
// -========================== Context menu =====================- /* -========================== ListView =====================- */
.list-view {
-fx-background-color: #4f4f4f;
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-radius: 3;
-fx-border-color: #00ffc9;
-fx-border-radius: 3;
-fx-border-width: 2;
}
.list-cell, .list-cell:selected, .list-cell:filled:selected{
-fx-background-color: -fx-table-cell-border-color, #424242;
-fx-background-insets: 0, 0 0 1 0;
-fx-table-cell-border-color: #6d8484;
}
.list-cell:odd, .list-cell:odd:selected, .list-cell:odd:filled:selected{
-fx-background-color: -fx-table-cell-border-color, #4f4f4f;
-fx-background-insets: 0, 0 0 1 0;
-fx-table-cell-border-color: #6d8484;
}
.list-cell .text, .list-cell:odd .text{
-fx-fill: #f7fafa;
}
.list-cell:filled:selected .text, .list-cell:odd:filled:selected .text{
-fx-fill: #08f3ff;
}
/* -========================== Context menu =====================- */
.context-menu { .context-menu {
-fx-background-color: #2d2d2d; -fx-background-color: #2d2d2d;
-fx-cursor: hand; -fx-cursor: hand;
@ -234,7 +263,7 @@
.context-menu .menu-item:focused .label { .context-menu .menu-item:focused .label {
-fx-text-fill: white; -fx-text-fill: white;
} }
// -========================== Text Field =====================- /* -========================== Text Field =====================- */
.text-field { .text-field {
-fx-prompt-text-fill: #40596c; -fx-prompt-text-fill: #40596c;
-fx-border-color: #289de8; -fx-border-color: #289de8;

View file

@ -242,6 +242,35 @@
-fx-padding: 0.0em; /* 0 */ -fx-padding: 0.0em; /* 0 */
-fx-table-cell-border-color: #b0b0b0; -fx-table-cell-border-color: #b0b0b0;
} }
/* -========================== ListView =====================- */
.list-view {
-fx-background-color: #fefefe;
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-radius: 3;
-fx-border-color: #06b9bb;
-fx-border-radius: 3;
-fx-border-width: 2;
}
.list-cell, .list-cell:selected, .list-cell:filled:selected{
-fx-background-color: -fx-table-cell-border-color, #ebfffe;
-fx-background-insets: 0, 0 0 1 0;
-fx-table-cell-border-color: #b0b0b0;
}
.list-cell:odd, .list-cell:odd:selected, .list-cell:odd:filled:selected{
-fx-background-color: -fx-table-cell-border-color, #fefefe;
-fx-background-insets: 0, 0 0 1 0;
-fx-table-cell-border-color: #b0b0b0;
}
.list-cell .text, .list-cell:odd .text{
-fx-fill: #2c2c2c;
}
.list-cell:filled:selected .text, .list-cell:odd:filled:selected .text{
-fx-fill: #2c2c2c;
-fx-font-weight: bold
}
/* -========================= Separator ===================- */ /* -========================= Separator ===================- */
.separator *.line { .separator *.line {
-fx-border-style: solid; -fx-border-style: solid;

View file

@ -0,0 +1,86 @@
package nsusbloader.com.usb;
import nsusbloader.NSLMain;
import nsusbloader.Utilities.splitmerge.SplitMergeTaskExecutor;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MergeTest {
private List<File> files;
@TempDir
File testFilesLocation;
@TempDir
File saveToPath;
static Random random;
@BeforeAll
static void init(){
NSLMain.isCli = true;
MergeTest.random = new Random();
}
void makeSplittedFiles() throws Exception{
String parentLocation = testFilesLocation.getAbsolutePath();
this.files = new ArrayList<>();
for (int i = 0; i < 7; i++) {
files.add(createSplitFile(parentLocation, "TestFile4Merge_" + i));
}
}
File createSplitFile(String parent, String name) throws Exception{
Path file = Paths.get(parent, name);
File newlyCreatedSplitFile = Files.createDirectory(file).toFile();
Assertions.assertTrue(newlyCreatedSplitFile.exists());
Assertions.assertTrue(newlyCreatedSplitFile.canRead());
Assertions.assertTrue(newlyCreatedSplitFile.canWrite());
int chunksCount = random.nextInt(6 + 1) + 1; // At min = 1, max = 6
populateSplittedFile(newlyCreatedSplitFile, chunksCount);
return newlyCreatedSplitFile;
}
void populateSplittedFile(File splitFileContainer, int chunksCount) throws Exception{
int chunkSize = random.nextInt(8192 + 1) + 8192; // At min = 8192, max = 8192*2
for (int i = 0; i < chunksCount; i++){
File chunkFile = new File(splitFileContainer, String.format("%02d", i));
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(chunkFile))){
byte[] zero = new byte[chunkSize];
bos.write(zero);
}
Assertions.assertTrue(chunkFile.exists());
Assertions.assertTrue(chunkFile.canRead());
}
}
@DisplayName("Test test-files location for merge")
@Test
void testTempLocation(){
Assertions.assertTrue(testFilesLocation.isDirectory());
}
// @Disabled("Current test is not ready")
@DisplayName("Test merge functionality")
//@Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
@Test
void testMerge() throws Exception{
makeSplittedFiles();
SplitMergeTaskExecutor splitMergeTaskExecutor = new SplitMergeTaskExecutor(false, files, saveToPath.getAbsolutePath());
Thread thread = new Thread(splitMergeTaskExecutor);
thread.setDaemon(true);
thread.start();
thread.join();
}
}

View file

@ -0,0 +1,78 @@
package nsusbloader.com.usb;
import nsusbloader.NSLMain;
import nsusbloader.Utilities.splitmerge.SplitMergeTaskExecutor;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
class SplitTest {
private List<File> files;
@TempDir
File testFilesLocation;
@TempDir
File saveToPath;
static Random random;
@BeforeAll
static void init(){
NSLMain.isCli = true;
SplitTest.random = new Random();
}
void makeRegularFiles() throws Exception {
String parentLocation = testFilesLocation.getAbsolutePath();
Assertions.assertTrue(Files.exists(Paths.get(parentLocation)));
this.files = new ArrayList<>();
for (int i = 0; i < 7; i++) {
files.add(createRegularFile(parentLocation, "TestFile4Split_" + i));
}
}
File createRegularFile(String parent, String name) throws Exception{
Path file = Paths.get(parent, name);
File newlyCreatedFile = Files.createFile(file).toFile();
Assertions.assertTrue(newlyCreatedFile.exists());
Assertions.assertTrue(newlyCreatedFile.canRead());
Assertions.assertTrue(newlyCreatedFile.canWrite());
int randomValue = random.nextInt(8192 + 1) + 8192; // At min = 8192, max = 8192*2
fulfillFile(newlyCreatedFile, randomValue);
return newlyCreatedFile;
}
void fulfillFile(File file, int fileSize) throws Exception{
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){
byte[] zero = new byte[fileSize];
bos.write(zero);
}
}
@DisplayName("Test test-files location for split")
@Test
void testTempLocation(){
Assertions.assertTrue(testFilesLocation.isDirectory());
}
@DisplayName("Test split functionality")
//@Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
@Test
void testSplit() throws Exception{
makeRegularFiles();
SplitMergeTaskExecutor splitMergeTaskExecutor = new SplitMergeTaskExecutor(true, files, saveToPath.getAbsolutePath());
Thread thread = new Thread(splitMergeTaskExecutor);
thread.setDaemon(true);
thread.start();
thread.join();
}
}