diff --git a/src/main/java/nsusbloader/COM/NET/NETCommunications.java b/src/main/java/nsusbloader/COM/NET/NETCommunications.java index da241aa..f91cd6f 100644 --- a/src/main/java/nsusbloader/COM/NET/NETCommunications.java +++ b/src/main/java/nsusbloader/COM/NET/NETCommunications.java @@ -3,6 +3,7 @@ package nsusbloader.COM.NET; import javafx.concurrent.Task; import nsusbloader.NSLDataTypes.EFileStatus; import nsusbloader.ModelControllers.LogPrinter; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.NSLDataTypes.EMsgType; import nsusbloader.COM.Helpers.NSSplitReader; @@ -42,7 +43,7 @@ public class NETCommunications extends Task { // todo: thows IOException? else this.extras = ""; this.switchIP = switchIP; - this.logPrinter = new LogPrinter(); + this.logPrinter = new LogPrinter(EModule.USB_NET_TRANSFERS); this.nspMap = new HashMap<>(); this.nspFileSizes = new HashMap<>(); // Filter and remove empty/incorrect split-files diff --git a/src/main/java/nsusbloader/COM/USB/UsbCommunications.java b/src/main/java/nsusbloader/COM/USB/UsbCommunications.java index 44dc65a..014eb14 100644 --- a/src/main/java/nsusbloader/COM/USB/UsbCommunications.java +++ b/src/main/java/nsusbloader/COM/USB/UsbCommunications.java @@ -3,6 +3,7 @@ package nsusbloader.COM.USB; import javafx.concurrent.Task; import nsusbloader.ModelControllers.LogPrinter; import nsusbloader.NSLDataTypes.EFileStatus; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.NSLDataTypes.EMsgType; import org.usb4java.*; @@ -34,7 +35,7 @@ public class UsbCommunications extends Task { this.nspMap = new LinkedHashMap<>(); for (File f: nspList) nspMap.put(f.getName(), f); - this.logPrinter = new LogPrinter(); + this.logPrinter = new LogPrinter(EModule.USB_NET_TRANSFERS); } @Override diff --git a/src/main/java/nsusbloader/Controllers/FrontController.java b/src/main/java/nsusbloader/Controllers/FrontController.java index a7d71c8..9f99177 100644 --- a/src/main/java/nsusbloader/Controllers/FrontController.java +++ b/src/main/java/nsusbloader/Controllers/FrontController.java @@ -6,6 +6,7 @@ import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; +import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.layout.Region; import javafx.stage.DirectoryChooser; @@ -14,6 +15,7 @@ import nsusbloader.AppPreferences; import nsusbloader.COM.NET.NETCommunications; import nsusbloader.COM.USB.UsbCommunications; import nsusbloader.MediatorControl; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.ServiceWindow; import java.io.File; @@ -25,6 +27,8 @@ import java.util.ResourceBundle; public class FrontController implements Initializable { @FXML private Pane specialPane; + @FXML + private AnchorPane usbNetPane; @FXML private ChoiceBox choiceProtocol, choiceNetUsb; @@ -35,7 +39,7 @@ public class FrontController implements Initializable { @FXML private Button switchThemeBtn; @FXML - public NSTableViewController tableFilesListController; // Accessible from Mediator + public NSTableViewController tableFilesListController; // Accessible from Mediator (for drag-n-drop support) @FXML private Button selectNspBtn, selectSplitNspBtn, uploadStopBtn; @@ -167,7 +171,7 @@ public class FrontController implements Initializable { } - /********************************************************************************************************************/ + /*-****************************************************************************************************************-*/ /** * Functionality for selecting NSP button. * */ @@ -290,30 +294,30 @@ public class FrontController implements Initializable { * Called from mediator * TODO: remove shitcoding practices * */ - public void notifyTransmissionStarted(boolean isTransmissionStarted){ - if (isTransmissionStarted) { + public void notifyTransmThreadStarted(boolean isActive, EModule type){ + if (! type.equals(EModule.USB_NET_TRANSFERS)){ + usbNetPane.setDisable(isActive); + return; + } + if (isActive) { selectNspBtn.setDisable(true); selectSplitNspBtn.setDisable(true); - uploadStopBtn.setOnAction(e-> stopBtnAction()); - - uploadStopBtn.setText(resourceBundle.getString("btn_Stop")); - - btnUpStopImage.getStyleClass().remove("regionUpload"); + btnUpStopImage.getStyleClass().clear(); btnUpStopImage.getStyleClass().add("regionStop"); + uploadStopBtn.setOnAction(e-> stopBtnAction()); + uploadStopBtn.setText(resourceBundle.getString("btn_Stop")); uploadStopBtn.getStyleClass().remove("buttonUp"); uploadStopBtn.getStyleClass().add("buttonStop"); return; } selectNspBtn.setDisable(false); selectSplitNspBtn.setDisable(false); - uploadStopBtn.setOnAction(e-> uploadBtnAction()); - - uploadStopBtn.setText(resourceBundle.getString("btn_Upload")); - - btnUpStopImage.getStyleClass().remove("regionStop"); + btnUpStopImage.getStyleClass().clear(); btnUpStopImage.getStyleClass().add("regionUpload"); + uploadStopBtn.setOnAction(e-> uploadBtnAction()); + uploadStopBtn.setText(resourceBundle.getString("btn_Upload")); uploadStopBtn.getStyleClass().remove("buttonStop"); uploadStopBtn.getStyleClass().add("buttonUp"); } diff --git a/src/main/java/nsusbloader/Controllers/NSLMainController.java b/src/main/java/nsusbloader/Controllers/NSLMainController.java index 478bd42..c1f58a4 100644 --- a/src/main/java/nsusbloader/Controllers/NSLMainController.java +++ b/src/main/java/nsusbloader/Controllers/NSLMainController.java @@ -119,6 +119,10 @@ public class NSLMainController implements Initializable { public FrontController getFrontCtrlr(){ return FrontTabController; } + + public SplitMergeController getSmCtrlr(){ + return SplitMergeTabController; + } /** * Save preferences before exit * */ diff --git a/src/main/java/nsusbloader/Controllers/SplitMergeController.java b/src/main/java/nsusbloader/Controllers/SplitMergeController.java index 4d9cae5..de327c5 100644 --- a/src/main/java/nsusbloader/Controllers/SplitMergeController.java +++ b/src/main/java/nsusbloader/Controllers/SplitMergeController.java @@ -3,15 +3,14 @@ package nsusbloader.Controllers; import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.fxml.Initializable; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; -import javafx.scene.control.ToggleGroup; +import javafx.scene.control.*; import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import nsusbloader.AppPreferences; import nsusbloader.MediatorControl; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.ServiceWindow; import nsusbloader.Utilities.SplitMergeTool; @@ -22,6 +21,9 @@ import java.util.ResourceBundle; public class SplitMergeController implements Initializable { @FXML private ToggleGroup splitMergeTogGrp; + @FXML + private VBox smToolPane; + @FXML private RadioButton splitRad, mergeRad; @FXML @@ -31,16 +33,23 @@ public class SplitMergeController implements Initializable { @FXML private Label fileFolderLabelLbl, fileFolderActualPathLbl, - saveToPathLbl; + saveToPathLbl, + statusLbl; + + private ResourceBundle resourceBundle; private Region convertRegion; + private Task smTask; + private Thread smThread; @Override public void initialize(URL url, ResourceBundle resourceBundle) { + this.resourceBundle = resourceBundle; convertRegion = new Region(); convertBtn.setGraphic(convertRegion); splitRad.setOnAction((actionEvent -> { + statusLbl.setText(""); convertRegion.getStyleClass().clear(); convertRegion.getStyleClass().add("regionSplitToOne"); fileFolderLabelLbl.setText(resourceBundle.getString("tabSplMrg_Txt_File")); @@ -49,6 +58,7 @@ public class SplitMergeController implements Initializable { convertBtn.setDisable(true); })); mergeRad.setOnAction((actionEvent -> { + statusLbl.setText(""); convertRegion.getStyleClass().clear(); convertRegion.getStyleClass().add("regionOneToSplit"); fileFolderLabelLbl.setText(resourceBundle.getString("tabSplMrg_Txt_Folder")); @@ -74,6 +84,7 @@ public class SplitMergeController implements Initializable { })); selectFileFolderBtn.setOnAction(actionEvent -> { + statusLbl.setText(""); if (splitRad.isSelected()) { FileChooser fc = new FileChooser(); fc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFile")); @@ -102,51 +113,75 @@ public class SplitMergeController implements Initializable { } }); - convertBtn.setOnAction(actionEvent -> { - if (MediatorControl.getInstance().getTransferActive()) { - ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"), resourceBundle.getString("windowBodyPleaseFinishTransfersFirst")); - return; - } - - if (splitRad.isSelected()){ - updateProcess(true); - Task task = SplitMergeTool.splitFile(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); - task.setOnSucceeded(workerStateEvent -> this.updateProcess(false)); - Thread thread = new Thread(task); - thread.setDaemon(true); - thread.start(); - } - else{ - updateProcess(true); - Task task = SplitMergeTool.mergeFile(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); - task.setOnSucceeded(workerStateEvent -> this.updateProcess(false)); - Thread thread = new Thread(task); - thread.setDaemon(true); - thread.start(); - } - - }); + convertBtn.setOnAction(actionEvent -> setConvertBtnAction()); } - private void updateProcess(boolean isStart){ + public void notifySmThreadStarted(boolean isStart, EModule type){ + if (! type.equals(EModule.SPLIT_MERGE_TOOL)){ + smToolPane.setDisable(isStart); + return; + } if (isStart){ MediatorControl.getInstance().getContoller().logArea.clear(); - MediatorControl.getInstance().setTransferActive(true); // TODO: remove & rewrite to interrupt function - convertBtn.setDisable(true);// TODO: remove & rewrite to interrupt function splitRad.setDisable(true); mergeRad.setDisable(true); selectFileFolderBtn.setDisable(true); changeSaveToBtn.setDisable(true); + + convertBtn.setOnAction(e -> stopBtnAction()); + convertBtn.setText(resourceBundle.getString("btn_Stop")); + convertRegion.getStyleClass().clear(); + convertRegion.getStyleClass().add("regionStop"); return; } - MediatorControl.getInstance().setTransferActive(false); - convertBtn.setDisable(false);// TODO: remove & rewrite to interrupt function splitRad.setDisable(false); mergeRad.setDisable(false); selectFileFolderBtn.setDisable(false); changeSaveToBtn.setDisable(false); + + convertBtn.setOnAction(e -> setConvertBtnAction()); + convertBtn.setText(resourceBundle.getString("tabSplMrg_Btn_Convert")); + convertRegion.getStyleClass().clear(); + if (splitRad.isSelected()) + convertRegion.getStyleClass().add("regionSplitToOne"); + else + convertRegion.getStyleClass().add("regionOneToSplit"); } + /** + * It's button listener when convert-process in progress + * */ + private void stopBtnAction(){ + if (smThread != null && smThread.isAlive()) + smTask.cancel(false); + } + /** + * It's button listener when convert-process NOT in progress + * */ + private void setConvertBtnAction(){ + if (MediatorControl.getInstance().getTransferActive()) { + ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"), resourceBundle.getString("windowBodyPleaseFinishTransfersFirst")); + return; + } + + if (splitRad.isSelected()) + smTask = SplitMergeTool.splitFile(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); + else + smTask = SplitMergeTool.mergeFile(fileFolderActualPathLbl.getText(), saveToPathLbl.getText()); + smTask.setOnCancelled(event -> statusLbl.setText(resourceBundle.getString("failure_txt"))); + smTask.setOnSucceeded(event -> { + if (smTask.getValue()) + statusLbl.setText(resourceBundle.getString("done_txt")); + else + statusLbl.setText(resourceBundle.getString("failure_txt")); + }); + smThread = new Thread(smTask); + smThread.setDaemon(true); + smThread.start(); + } + /** + * Save application settings on exit + * */ public void updatePreferencesOnExit(){ if (splitRad.isSelected()) AppPreferences.getInstance().setSplitMergeType(0); diff --git a/src/main/java/nsusbloader/MediatorControl.java b/src/main/java/nsusbloader/MediatorControl.java index 2db197e..12d9c38 100644 --- a/src/main/java/nsusbloader/MediatorControl.java +++ b/src/main/java/nsusbloader/MediatorControl.java @@ -1,12 +1,13 @@ package nsusbloader; import nsusbloader.Controllers.NSLMainController; +import nsusbloader.NSLDataTypes.EModule; import java.util.concurrent.atomic.AtomicBoolean; public class MediatorControl { private AtomicBoolean isTransferActive = new AtomicBoolean(false); // Overcoded just for sure - private NSLMainController applicationController; + private NSLMainController mainCtrler; public static MediatorControl getInstance(){ return MediatorControlHold.INSTANCE; @@ -16,13 +17,14 @@ public class MediatorControl { private static final MediatorControl INSTANCE = new MediatorControl(); } public void setController(NSLMainController controller){ - this.applicationController = controller; + this.mainCtrler = controller; } - public NSLMainController getContoller(){ return this.applicationController; } + public NSLMainController getContoller(){ return this.mainCtrler; } - public synchronized void setTransferActive(boolean state) { - isTransferActive.set(state); - applicationController.getFrontCtrlr().notifyTransmissionStarted(state); + public synchronized void setBgThreadActive(boolean isActive, EModule appModuleType) { + isTransferActive.set(isActive); + mainCtrler.getFrontCtrlr().notifyTransmThreadStarted(isActive, appModuleType); + mainCtrler.getSmCtrlr().notifySmThreadStarted(isActive, appModuleType); } public synchronized boolean getTransferActive() { return this.isTransferActive.get(); } } diff --git a/src/main/java/nsusbloader/ModelControllers/LogPrinter.java b/src/main/java/nsusbloader/ModelControllers/LogPrinter.java index 4d0c34d..67cb326 100644 --- a/src/main/java/nsusbloader/ModelControllers/LogPrinter.java +++ b/src/main/java/nsusbloader/ModelControllers/LogPrinter.java @@ -1,6 +1,7 @@ package nsusbloader.ModelControllers; import nsusbloader.NSLDataTypes.EFileStatus; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.NSLDataTypes.EMsgType; import java.io.File; @@ -14,11 +15,11 @@ public class LogPrinter { private BlockingQueue progressQueue; private HashMap statusMap; // BlockingQueue for literally one object. TODO: read more books ; replace to hashMap - public LogPrinter(){ + public LogPrinter(EModule whoIsAsking){ this.msgQueue = new LinkedBlockingQueue<>(); this.progressQueue = new LinkedBlockingQueue<>(); this.statusMap = new HashMap<>(); - this.msgConsumer = new MessagesConsumer(this.msgQueue, this.progressQueue, this.statusMap); + this.msgConsumer = new MessagesConsumer(whoIsAsking, this.msgQueue, this.progressQueue, this.statusMap); this.msgConsumer.start(); } /** @@ -42,7 +43,8 @@ public class LogPrinter { default: msgQueue.put(message); } - }catch (InterruptedException ie){ + } + catch (InterruptedException ie){ ie.printStackTrace(); } } diff --git a/src/main/java/nsusbloader/ModelControllers/MessagesConsumer.java b/src/main/java/nsusbloader/ModelControllers/MessagesConsumer.java index e3fa778..a7384f4 100644 --- a/src/main/java/nsusbloader/ModelControllers/MessagesConsumer.java +++ b/src/main/java/nsusbloader/ModelControllers/MessagesConsumer.java @@ -7,6 +7,7 @@ import javafx.scene.control.TextArea; import nsusbloader.Controllers.NSTableViewController; import nsusbloader.MediatorControl; import nsusbloader.NSLDataTypes.EFileStatus; +import nsusbloader.NSLDataTypes.EModule; import java.util.ArrayList; import java.util.HashMap; @@ -20,10 +21,12 @@ public class MessagesConsumer extends AnimationTimer { private final ProgressBar progressBar; private final HashMap statusMap; private final NSTableViewController tableViewController; + private final EModule appModuleType; private boolean isInterrupted; - MessagesConsumer(BlockingQueue msgQueue, BlockingQueue progressQueue, HashMap statusMap){ + MessagesConsumer(EModule appModuleType, BlockingQueue msgQueue, BlockingQueue progressQueue, HashMap statusMap){ + this.appModuleType = appModuleType; this.isInterrupted = false; this.msgQueue = msgQueue; @@ -38,7 +41,7 @@ public class MessagesConsumer extends AnimationTimer { progressBar.setProgress(0.0); progressBar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS); - MediatorControl.getInstance().setTransferActive(true); + MediatorControl.getInstance().setBgThreadActive(true, appModuleType); } @Override @@ -60,7 +63,7 @@ public class MessagesConsumer extends AnimationTimer { } if (isInterrupted) { // It's safe 'cuz it's could't be interrupted while HashMap populating - MediatorControl.getInstance().setTransferActive(false); + MediatorControl.getInstance().setBgThreadActive(false, appModuleType); progressBar.setProgress(0.0); if (statusMap.size() > 0) diff --git a/src/main/java/nsusbloader/NSLDataTypes/EModule.java b/src/main/java/nsusbloader/NSLDataTypes/EModule.java new file mode 100644 index 0000000..48209d1 --- /dev/null +++ b/src/main/java/nsusbloader/NSLDataTypes/EModule.java @@ -0,0 +1,7 @@ +package nsusbloader.NSLDataTypes; + +public enum EModule { + USB_NET_TRANSFERS, + SPLIT_MERGE_TOOL, + RCM +} diff --git a/src/main/java/nsusbloader/Utilities/SplitMergeTool.java b/src/main/java/nsusbloader/Utilities/SplitMergeTool.java index 3682ed8..9481fad 100644 --- a/src/main/java/nsusbloader/Utilities/SplitMergeTool.java +++ b/src/main/java/nsusbloader/Utilities/SplitMergeTool.java @@ -2,205 +2,284 @@ package nsusbloader.Utilities; import javafx.concurrent.Task; import nsusbloader.ModelControllers.LogPrinter; +import nsusbloader.NSLDataTypes.EModule; import nsusbloader.NSLDataTypes.EMsgType; import java.io.*; import java.util.Arrays; public class SplitMergeTool { - // TODO: ADD ABILITY TO INTERRUPT PROCESS - public static Task splitFile(String filePath, String saveToPath){ - LogPrinter logPrinter = new LogPrinter(); - return new Task() { - @Override - protected Void call() { - File file = new File(filePath); - File folder = new File(saveToPath+File.separator+"!_"+file.getName()); - - logPrinter.print("Split file: "+filePath, EMsgType.INFO); - - for (int i = 0; i < 50; i++){ - if (! folder.mkdir()){ - if (folder.exists()){ - logPrinter.print("Trying to create a good new folder...", EMsgType.WARNING); - folder = new File(saveToPath+File.separator+"!_"+i+"_"+file.getName()); - continue; - } - else { // folder not created and not exists - return - logPrinter.print("Folder "+folder.getAbsolutePath()+" could not be created. Not enough rights or something like that?", EMsgType.FAIL); - logPrinter.close(); - return null; - } - } - logPrinter.print("Save results to: "+folder.getAbsolutePath(), EMsgType.INFO); - break; - } - - try{ - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); - - BufferedOutputStream fragmentBos; - - long counter; - - long 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++){ - fragmentBos = new BufferedOutputStream( - new FileOutputStream(new File(folder.getAbsolutePath()+File.separator+String.format("%02d", i))) - ); - - 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(); - 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(); - - //=============== let's check what we have ============== - logPrinter.print("Original file size: "+originalFileLen, EMsgType.INFO); - long totalChunksSize = 0; - File[] chunkFileArr = folder.listFiles(); - - if (chunkFileArr == null) { - logPrinter.print("Unable to check results. It means that something went wrong.", EMsgType.FAIL); - return null; - } - else { - 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) - logPrinter.print("Sizes are different! Do NOT use this file for installations!", EMsgType.FAIL); - else - logPrinter.print("Sizes are the same! Split file should be good!", EMsgType.PASS); - } - } - catch (Exception e){ - e.printStackTrace(); - logPrinter.print("Error: "+e.getMessage(), EMsgType.FAIL); - } - logPrinter.print("Split task complete!", EMsgType.INFO); - logPrinter.close(); - - return null; - } - }; + public static Task splitFile(String filePath, String saveToPath){ + return new SplitTask(filePath, saveToPath); }; - // TODO: CHECK IF FILE WE'RE ABOUT TO CREATE IS EXISTS !!! - // TODO: not here: Add RECENT on current session level selection of the 'Select file/select folder' ? Already done ? - - public static Task mergeFile(String filePath, String saveToPath){ - LogPrinter logPrinter = new LogPrinter(); - - return new Task() { - @Override - protected Void call() { - logPrinter.print("Merge file: "+filePath, EMsgType.INFO); - - File folder = new File(filePath); - - long cnkTotalSize = 0; - - File[] chunkFiles = folder.listFiles((file, s) -> s.matches("^[0-9][0-9]$")); - - if (chunkFiles == null){ - logPrinter.print("Selected folder doesn't have any chunks. Nothing to do here.", EMsgType.FAIL); - logPrinter.close(); - return null; - } - - Arrays.sort(chunkFiles); - - logPrinter.print("Next files will be merged in following order: ", EMsgType.INFO); - for (File cnk : chunkFiles){ - logPrinter.print(" "+cnk.getName(), EMsgType.INFO); - cnkTotalSize += cnk.length(); - } - - double chunkPercent = (4194240.0 / (cnkTotalSize / 100.0) / 100.0); - long totalSizeCnt = 0; - - File resultFile = new File(saveToPath+File.separator+"!_"+folder.getName()); - - logPrinter.print("Save results to: "+resultFile.getAbsolutePath(), EMsgType.INFO); - try { - BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(resultFile)); - - BufferedInputStream bis; - byte[] chunk; - int readBytesCnt; - - for (File cnk : chunkFiles){ - bis = new BufferedInputStream(new FileInputStream(cnk)); - while (true){ - 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(); - //=============== let's check what we have ============== - long resultFileSize = resultFile.length(); - logPrinter.print("Total chunks size: " + cnkTotalSize, EMsgType.INFO); - logPrinter.print("Merged file size: " + resultFileSize, EMsgType.INFO); - - if (cnkTotalSize != resultFileSize) - logPrinter.print("Sizes are different! Do NOT use this file for installations!", EMsgType.FAIL); - else - logPrinter.print("Sizes are the same! Split file should be good!", EMsgType.PASS); - } - catch (Exception e){ - e.printStackTrace(); - logPrinter.print("Error: "+e.getMessage(), EMsgType.FAIL); - } - - logPrinter.print("Merge task complete!", EMsgType.INFO); - logPrinter.close(); - return null; - } - }; + public static Task mergeFile(String filePath, String saveToPath){ + return new MergeTask(filePath, saveToPath); } } + +class SplitTask extends Task{ + + private LogPrinter logPrinter; + private String saveToPath; + private String filePath; + + SplitTask(String filePath, String saveToPath){ + this.filePath = filePath; + this.saveToPath = saveToPath; + logPrinter = new LogPrinter(EModule.SPLIT_MERGE_TOOL); + } + + @Override + protected Boolean call() { + File file = new File(filePath); + File folder = new File(saveToPath+File.separator+"!_"+file.getName()); + + logPrinter.print("Split file: "+filePath, EMsgType.INFO); + + for (int i = 0; ; i++){ + if (this.isCancelled()){ + logPrinter.print("Split task interrupted!", EMsgType.PASS); + logPrinter.close(); + return false; + } + if (! folder.mkdir()){ + if (folder.exists()){ + if (i >= 50){ + logPrinter.print("Can't create new file.", EMsgType.FAIL); + logPrinter.close(); + return false; + } + logPrinter.print("Trying to create a good new folder...", EMsgType.WARNING); + folder = new File(saveToPath+File.separator+"!_"+i+"_"+file.getName()); + continue; + } + else { // folder not created and not exists - return + logPrinter.print("Folder "+folder.getAbsolutePath()+" could not be created. Not enough rights or something like that?", EMsgType.FAIL); + logPrinter.close(); + return false; + } + } + logPrinter.print("Save results to: "+folder.getAbsolutePath(), EMsgType.INFO); + break; + } + + try{ + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + + BufferedOutputStream fragmentBos; + + long counter; + + long 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++){ + fragmentBos = new BufferedOutputStream( + new FileOutputStream(new File(folder.getAbsolutePath()+File.separator+String.format("%02d", i))) + ); + + counter = 0; + + while (counter < 1024){ // 0xffff0000 total + + if (this.isCancelled()){ + fragmentBos.close(); + bis.close(); + boolean isDeleted = folder.delete(); + File[] chArrToDel = folder.listFiles(); + if (! isDeleted && chArrToDel != null){ + isDeleted = true; + for (File chunkFile : chArrToDel) + isDeleted &= chunkFile.delete(); + isDeleted &= folder.delete(); + } + logPrinter.print("Split task interrupted and folder "+(isDeleted?"deleted.":"is not deleted."), EMsgType.PASS); + logPrinter.close(); + return false; + } + + 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(); + + //=============== let's check what we have ============== + logPrinter.print("Original file size: "+originalFileLen, EMsgType.INFO); + long totalChunksSize = 0; + File[] chunkFileArr = folder.listFiles(); + + if (chunkFileArr == null) { + logPrinter.print("Unable to check results. It means that something went wrong.", EMsgType.FAIL); + return false; + } + else { + 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) + logPrinter.print("Sizes are different! Do NOT use this file for installations!", EMsgType.FAIL); + else + logPrinter.print("Sizes are the same! Split file should be good!", EMsgType.PASS); + } + } + catch (Exception e){ + e.printStackTrace(); + logPrinter.print("Error: "+e.getMessage(), EMsgType.FAIL); + } + logPrinter.print("Split task complete!", EMsgType.INFO); + logPrinter.close(); + + return true; + } +} + +class MergeTask extends Task { + + private LogPrinter logPrinter; + private String saveToPath; + private String filePath; + + MergeTask(String filePath, String saveToPath) { + this.filePath = filePath; + this.saveToPath = saveToPath; + logPrinter = new LogPrinter(EModule.SPLIT_MERGE_TOOL); + } + @Override + protected Boolean call() { + logPrinter.print("Merge file: "+filePath, EMsgType.INFO); + + File folder = new File(filePath); + + long cnkTotalSize = 0; + + File[] chunkFiles = folder.listFiles((file, s) -> s.matches("^[0-9][0-9]$")); + + if (chunkFiles == null){ + logPrinter.print("Selected folder doesn't have any chunks. Nothing to do here.", EMsgType.FAIL); + logPrinter.close(); + return false; + } + + Arrays.sort(chunkFiles); + + logPrinter.print("Next files will be merged in following order: ", EMsgType.INFO); + for (File cnk : chunkFiles){ + logPrinter.print(" "+cnk.getName(), EMsgType.INFO); + cnkTotalSize += cnk.length(); + } + + double chunkPercent = (4194240.0 / (cnkTotalSize / 100.0) / 100.0); + long totalSizeCnt = 0; + + File resultFile = new File(saveToPath+File.separator+"!_"+folder.getName()); + //******* + for (int i = 0; ; i++){ + if (this.isCancelled()){ + logPrinter.print("Split task interrupted!", EMsgType.PASS); + logPrinter.close(); + return false; + } + + if (resultFile.exists()){ + if (i >= 50){ + logPrinter.print("Can't create new file.", EMsgType.FAIL); + logPrinter.close(); + return false; + } + + logPrinter.print("Trying to create a good new file...", EMsgType.WARNING); + resultFile = new File(saveToPath+File.separator+"!_"+i+"_"+folder.getName()); + continue; + } + logPrinter.print("Save results to: "+resultFile.getAbsolutePath(), EMsgType.INFO); + break; + } + //******* + + try { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(resultFile)); + + BufferedInputStream bis; + byte[] chunk; + int readBytesCnt; + + for (File cnk : chunkFiles){ + bis = new BufferedInputStream(new FileInputStream(cnk)); + while (true){ + + if (this.isCancelled()){ + bos.close(); + bis.close(); + boolean isDeleted = resultFile.delete(); + logPrinter.print("Split task interrupted and file "+(isDeleted?"deleted.":"is not deleted."), EMsgType.PASS); + logPrinter.close(); + return false; + } + + 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(); + //=============== let's check what we have ============== + long resultFileSize = resultFile.length(); + logPrinter.print("Total chunks size: " + cnkTotalSize, EMsgType.INFO); + logPrinter.print("Merged file size: " + resultFileSize, EMsgType.INFO); + + if (cnkTotalSize != resultFileSize){ + logPrinter.print("Sizes are different! Do NOT use this file for installations!", EMsgType.FAIL); + return false; + } + logPrinter.print("Sizes are the same! Split file should be good!", EMsgType.PASS); + } + catch (Exception e){ + e.printStackTrace(); + logPrinter.print("Error: "+e.getMessage(), EMsgType.FAIL); + } + + logPrinter.print("Merge task complete!", EMsgType.INFO); + logPrinter.close(); + return true; + } +} \ No newline at end of file diff --git a/src/main/resources/FrontTab.fxml b/src/main/resources/FrontTab.fxml index c0383c9..6cf6935 100644 --- a/src/main/resources/FrontTab.fxml +++ b/src/main/resources/FrontTab.fxml @@ -15,7 +15,7 @@ - + diff --git a/src/main/resources/NSLMain.fxml b/src/main/resources/NSLMain.fxml index 05c6355..8d54217 100644 --- a/src/main/resources/NSLMain.fxml +++ b/src/main/resources/NSLMain.fxml @@ -23,6 +23,16 @@ + + + + + + + + + + @@ -47,16 +57,6 @@ - - - - - - - - - - diff --git a/src/main/resources/SplitMergeTab.fxml b/src/main/resources/SplitMergeTab.fxml index 6c142ef..9677b23 100644 --- a/src/main/resources/SplitMergeTab.fxml +++ b/src/main/resources/SplitMergeTab.fxml @@ -10,7 +10,7 @@ - + @@ -52,6 +52,12 @@