diff --git a/pom.xml b/pom.xml
index d39d2f5..750b8a8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,7 +50,7 @@
UTF-8
yyyyMMdd.HHmmss
19.0.2.1
- 11
+ 17
@@ -205,7 +205,7 @@
maven-compiler-plugin
3.10.1
- 11
+ 17
@@ -274,7 +274,7 @@
%PWD%/jdk
- 11.0.0
+ 17.0.0
${project.version}.0.0
diff --git a/src/main/java/nsusbloader/com/usb/TransferModule.java b/src/main/java/nsusbloader/com/usb/TransferModule.java
index b8e35e9..9ea4694 100644
--- a/src/main/java/nsusbloader/com/usb/TransferModule.java
+++ b/src/main/java/nsusbloader/com/usb/TransferModule.java
@@ -31,14 +31,17 @@ public abstract class TransferModule {
protected static final byte IN_EP = (byte) 0x81;
protected static final byte OUT_EP = (byte) 0x01;
- EFileStatus status = EFileStatus.UNKNOWN;
+ protected EFileStatus status = EFileStatus.UNKNOWN;
- LinkedHashMap nspMap;
- ILogPrinter logPrinter;
- DeviceHandle handlerNS;
- CancellableRunnable task;
+ protected LinkedHashMap nspMap;
+ protected ILogPrinter logPrinter;
+ protected DeviceHandle handlerNS;
+ protected CancellableRunnable task;
- TransferModule(DeviceHandle handler, LinkedHashMap nspMap, CancellableRunnable task, ILogPrinter printer){
+ protected TransferModule(DeviceHandle handler,
+ LinkedHashMap nspMap,
+ CancellableRunnable task,
+ ILogPrinter printer){
this.handlerNS = handler;
this.nspMap = nspMap;
this.task = task;
@@ -81,7 +84,7 @@ public abstract class TransferModule {
}
public EFileStatus getStatus(){ return status; }
- void print(String message, EMsgType type){
+ protected void print(String message, EMsgType type){
try {
logPrinter.print(message, type);
}
diff --git a/src/main/java/nsusbloader/com/usb/UsbCommunications.java b/src/main/java/nsusbloader/com/usb/UsbCommunications.java
index e426d0c..203f217 100644
--- a/src/main/java/nsusbloader/com/usb/UsbCommunications.java
+++ b/src/main/java/nsusbloader/com/usb/UsbCommunications.java
@@ -24,6 +24,7 @@ import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EFileStatus;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
+import nsusbloader.com.usb.gl.GoldLeaf_111;
import org.usb4java.*;
import java.io.*;
diff --git a/src/main/java/nsusbloader/com/usb/gl/Converters.java b/src/main/java/nsusbloader/com/usb/gl/Converters.java
new file mode 100644
index 0000000..71a6d44
--- /dev/null
+++ b/src/main/java/nsusbloader/com/usb/gl/Converters.java
@@ -0,0 +1,53 @@
+/*
+ Copyright 2019-2025 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 .
+ */
+package nsusbloader.com.usb.gl;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class Converters {
+ /**
+ * Convert INT (Little endian) value to bytes-array representation
+ * */
+ public static byte[] intToArrLE(int value){
+ return ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN)
+ .putInt(value)
+ .array();
+ }
+ /**
+ * Convert LONG (Little endian) value to bytes-array representation
+ * */
+ public static byte[] longToArrLE(long value){
+ return ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN)
+ .putLong(value)
+ .array();
+ }
+ /**
+ * Convert bytes-array to INT value (Little endian)
+ * */
+ public static int arrToIntLE(byte[] byteArrayWithInt, int intStartPosition){
+ return ByteBuffer.wrap(byteArrayWithInt).order(ByteOrder.LITTLE_ENDIAN).getInt(intStartPosition);
+ }
+ /**
+ * Convert bytes-array to LONG value (Little endian)
+ * */
+ public static long arrToLongLE(byte[] byteArrayWithLong, int intStartPosition){
+ return ByteBuffer.wrap(byteArrayWithLong).order(ByteOrder.LITTLE_ENDIAN).getLong(intStartPosition);
+ }
+}
diff --git a/src/main/java/nsusbloader/com/usb/GoldLeaf_111.java b/src/main/java/nsusbloader/com/usb/gl/GoldLeaf_111.java
similarity index 76%
rename from src/main/java/nsusbloader/com/usb/GoldLeaf_111.java
rename to src/main/java/nsusbloader/com/usb/gl/GoldLeaf_111.java
index c5c68c4..57a8139 100644
--- a/src/main/java/nsusbloader/com/usb/GoldLeaf_111.java
+++ b/src/main/java/nsusbloader/com/usb/gl/GoldLeaf_111.java
@@ -16,31 +16,33 @@
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see .
*/
-package nsusbloader.com.usb;
+package nsusbloader.com.usb.gl;
import javafx.application.Platform;
import javafx.stage.FileChooser;
-import libKonogonka.RainbowDump;
import nsusbloader.MediatorControl;
import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.com.helpers.NSSplitReader;
+import nsusbloader.com.usb.TransferModule;
+import nsusbloader.com.usb.UsbErrorCodes;
import org.usb4java.DeviceHandle;
import org.usb4java.LibUsb;
import java.io.*;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
+import static nsusbloader.com.usb.gl.Converters.*;
+
/**
* GoldLeaf 1.1.1 processing
*/
-class GoldLeaf_111 extends TransferModule {
+public class GoldLeaf_111 extends TransferModule {
// CMD
private final static byte[] CMD_GLCO_FAILURE =
Arrays.copyOf(new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, (byte) 0xAD, (byte) 0xDE}, 4096); // used @ writeToUsb_GLCMD
@@ -48,8 +50,8 @@ class GoldLeaf_111 extends TransferModule {
new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00}; // used @ writeToUsb_GLCMD
// System.out.println((356 & 0x1FF) | ((1 + 100) & 0x1FFF) << 9); // 52068 // 0x00 0x00 0xCB 0x64
- private final byte[] GL_OBJ_TYPE_FILE = new byte[]{0x01, 0x00, 0x00, 0x00};
- private final byte[] GL_OBJ_TYPE_DIR = new byte[]{0x02, 0x00, 0x00, 0x00};
+ private final byte[] GL_OBJECT_TYPE_FILE = new byte[]{0x01, 0x00, 0x00, 0x00};
+ private final byte[] GL_OBJECT_TYPE_DIR = new byte[]{0x02, 0x00, 0x00, 0x00};
private final boolean nspFilter;
@@ -72,59 +74,20 @@ class GoldLeaf_111 extends TransferModule {
// For using in CMD_SelectFile with SPEC:/ prefix
private File selectedFile;
- private final CancellableRunnable task;
-
- private enum GL_CMD {
- CMD_GetDriveCount((byte) 1),
- CMD_GetDriveInfo((byte) 2),
- CMD_StatPath((byte) 3),
- CMD_GetFileCount((byte) 4),
- CMD_GetFile((byte) 5),
- CMD_GetDirectoryCount((byte) 6),
- CMD_GetDirectory((byte) 7),
- CMD_StartFile((byte) 8),
- CMD_ReadFile((byte) 9),
- CMD_WriteFile((byte) 10),
- CMD_EndFile((byte) 11),
- CMD_Create((byte) 12),
- CMD_Delete((byte) 13),
- CMD_Rename((byte) 14),
- CMD_GetSpecialPathCount((byte) 15),
- CMD_GetSpecialPath((byte) 16),
- CMD_SelectFile((byte) 17),
- CMD_UNKNOWN((byte) 255);
-
- private final byte id;
-
- GL_CMD(byte id) {
- this.id = id;
- }
-
- public static GL_CMD get(byte id) {
- for(GL_CMD cmd : values()) {
- if(cmd.id == id)
- return cmd;
- }
- return CMD_UNKNOWN;
- }
- }
-
- GoldLeaf_111(DeviceHandle handler,
- LinkedHashMap nspMap,
- CancellableRunnable task,
- ILogPrinter logPrinter,
- boolean nspFilter) {
+ public GoldLeaf_111(DeviceHandle handler,
+ LinkedHashMap nspMap,
+ CancellableRunnable task,
+ ILogPrinter logPrinter,
+ boolean nspFilter) {
super(handler, nspMap, task, logPrinter);
- this.task = task;
this.nspFilter = nspFilter;
print("=========== GoldLeaf v1.1.1 ===========\n\t" +
"VIRT:/ equals files added into the application\n\t" +
- "HOME:/ equals "
- +System.getProperty("user.home"), EMsgType.INFO);
+ "HOME:/ equals " +homePath, EMsgType.INFO);
- // Let's collect file names to the array to simplify our life
+ // Let's collect file names to the array (simplifies flow)
nspMapKeySetIndexes = nspMap.keySet().toArray(new String[0]);
// Calculate size of VIRT:/ drive
@@ -152,90 +115,88 @@ class GoldLeaf_111 extends TransferModule {
return;
//RainbowDump.hexDumpUTF8(readByte); // DEBUG
- System.out.println("\tâ: "+GL_CMD.get(readByte[4])); // FIXME: DEBUG
+ //System.out.println("\tâ "+ GoldleafCmd.get(readByte[4]));
if (notGLCI(readByte))
continue;
- switch (GL_CMD.get(readByte[4])) {
- case CMD_GetDriveCount:
+ switch (GoldleafCmd.get(readByte[4])) {
+ case GetDriveCount:
if (getDriveCount())
break main_loop;
break;
- case CMD_GetDriveInfo:
+ case GetDriveInfo:
if (getDriveInfo(arrToIntLE(readByte,8)))
break main_loop;
break;
- case CMD_GetSpecialPathCount:
+ case GetSpecialPathCount:
if (getSpecialPathCount())
break main_loop;
break;
- case CMD_GetSpecialPath:
+ case GetSpecialPath:
if (getSpecialPath(arrToIntLE(readByte,8)))
break main_loop;
break;
- case CMD_GetDirectoryCount:
+ case GetDirectoryCount:
someLength1 = arrToIntLE(readByte, 8);
if (getDirectoryOrFileCount(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), true))
break main_loop;
break;
- case CMD_GetFileCount:
+ case GetFileCount:
someLength1 = arrToIntLE(readByte, 8);
if (getDirectoryOrFileCount(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), false))
break main_loop;
break;
- case CMD_GetDirectory:
+ case GetDirectory:
someLength1 = arrToIntLE(readByte, 8);
if (getDirectory(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToIntLE(readByte, someLength1+12)))
break main_loop;
break;
- case CMD_GetFile:
+ case GetFile:
someLength1 = arrToIntLE(readByte, 8);
if (getFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToIntLE(readByte, someLength1+12)))
break main_loop;
break;
- case CMD_StatPath:
+ case StatPath:
someLength1 = arrToIntLE(readByte, 8);
if (statPath(new String(readByte, 12, someLength1, StandardCharsets.UTF_8)))
break main_loop;
break;
- case CMD_Rename:
+ case Rename:
someLength1 = arrToIntLE(readByte, 8);
someLength2 = arrToIntLE(readByte, 12+someLength1);
if (rename(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), // 8+4=12
new String(readByte, 12+someLength1+4, someLength2, StandardCharsets.UTF_8)))
break main_loop;
break;
- case CMD_Delete:
- RainbowDump.hexDumpUTF8(readByte); // TODO: DEBUG
- someLength1 = arrToIntLE(readByte, 12); // FIXME TEST ME!
- if (delete(new String(readByte, 16, someLength1, StandardCharsets.UTF_8)))
+ case Delete:
+ someLength1 = arrToIntLE(readByte, 8);
+ if (delete(new String(readByte, 12, someLength1, StandardCharsets.UTF_8)))
break main_loop;
break;
- case CMD_Create:
- someLength1 = arrToIntLE(readByte, 12); // FIXME TEST ME!
- if (create(new String(readByte, 16, someLength1, StandardCharsets.UTF_8), readByte[8]))
+ case Create:
+ someLength1 = arrToIntLE(readByte, 8);
+ if (create(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), readByte[8]))
break main_loop;
break;
- case CMD_ReadFile:
+ case ReadFile:
someLength1 = arrToIntLE(readByte, 8);
if (readFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8),
arrToLongLE(readByte, 12+someLength1),
arrToLongLE(readByte, 12+someLength1+8)))
break main_loop;
break;
- case CMD_WriteFile:
+ case WriteFile:
someLength1 = arrToIntLE(readByte, 8);
- //if (writeFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToLongLE(readByte, 12+someLength1)))
if (writeFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8)))
break main_loop;
break;
- case CMD_SelectFile:
+ case SelectFile:
if (selectFile())
break main_loop;
break;
- case CMD_StartFile:
- case CMD_EndFile:
+ case StartFile:
+ case EndFile:
if (startOrEndFile())
break main_loop;
break;
@@ -256,37 +217,6 @@ class GoldLeaf_111 extends TransferModule {
return ! "GLCI".equals(new String(inputBytes, 0, 4, StandardCharsets.US_ASCII));
}
- /**
- * Close files opened for read/write
- */
- private void closeOpenedReadFilesGl(){
- if (openReadFileNameAndPath != null){
- closeRAFandSplitReader();
- openReadFileNameAndPath = null;
- randAccessFile = null;
- splitReader = null;
- }
- }
- private void closeRAFandSplitReader(){
- closeRAF();
- try{
- splitReader.close();
- }
- catch (IOException ioe_){
- print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
- }
- catch (Exception ignored){}
- }
- private void closeRAF(){
- try{
- randAccessFile.close();
- }
- catch (IOException ioe_){
- print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
- }
- catch (Exception ignored){}
- }
-
/**
* Handle StartFile & EndFile
* NOTE: It's something internal for GL and used somehow by GL-PC-app, so just ignore this, at least for v0.8.
@@ -315,8 +245,7 @@ class GoldLeaf_111 extends TransferModule {
driveLabelLen,
driveLetter,
driveLetterLen,
- totalFreeSpace,
- totalSize;
+ totalFreeSpace;
long totalSizeLong;
if (driveNo == 0){ // 0 == VIRTUAL DRIVE
@@ -336,7 +265,7 @@ class GoldLeaf_111 extends TransferModule {
totalFreeSpace = Arrays.copyOfRange(longToArrLE(userHomeDir.getFreeSpace()), 0, 4);;
totalSizeLong = userHomeDir.getTotalSpace();
}
- totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4);
+ var totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4);
var command = Arrays.asList(
driveLabelLen,
@@ -367,24 +296,25 @@ class GoldLeaf_111 extends TransferModule {
* Handle GetDirectoryCount & GetFileCount
* @return true - failed, false - passed
* */
- private boolean getDirectoryOrFileCount(String path, boolean isGetDirectoryCount) {
- if (path.equals("VIRT:/")) {
+ private boolean getDirectoryOrFileCount(String glFileName, boolean isGetDirectoryCount) {
+ if (glFileName.equals("VIRT:/")) {
return isGetDirectoryCount ?
writeGL_PASS("GL Handle 'GetDirectoryCount' command") :
writeGL_PASS(intToArrLE(nspMap.size()), "GL Handle 'GetFileCount' command Count = " + nspMap.size());
}
- else if (path.startsWith("HOME:/")){
- // Let's make it normal path
- path = updateHomePath(path);
+ else if (glFileName.startsWith("HOME:/")){
+ var path = updateHomePath(glFileName);
var pathDir = new File(path);
- // Make sure it's exists and it's path
- if ((! pathDir.exists() ) || (! pathDir.isDirectory()) )
- return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [doesn't exist or not a folder]");
- // Save recent dir path
- this.recentPath = path;
- var filesOrDirs = getFilesOrDirs(isGetDirectoryCount, pathDir);
- // If somehow there are no folders, let's say 0;
+ if (notExistsOrDirectory(pathDir))
+ return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [doesn't exist or not a folder] "+ pathDir);
+
+ this.recentPath = path; // Save recent dir path
+ var filesOrDirs = isGetDirectoryCount ?
+ pathDir.list(this::isDirectoryAndNotHidden) :
+ pathDir.list(this::isFileAndNotHidden);
+
+ // If no folders, let's say 0;
if (filesOrDirs == null)
return writeGL_PASS("GL Handle 'GetDirectoryOrFileCount' command");
// Sorting is mandatory NOTE: Proxy tail
@@ -397,34 +327,15 @@ class GoldLeaf_111 extends TransferModule {
// Otherwise, let's tell how may folders are in there
return writeGL_PASS(intToArrLE(filesOrDirs.length), "GL Handle 'GetDirectoryOrFileCount' command");
}
- else if (path.startsWith("SPEC:/")){
+ else if (glFileName.startsWith("SPEC:/")){
if (isGetDirectoryCount) // If dir request then 0 dirs
return writeGL_PASS("GL Handle 'GetDirectoryCount' command");
else if (selectedFile != null) // Else it's file request, if we have selected then we will report 1.
return writeGL_PASS(intToArrLE(1), "GL Handle 'GetFileCount' command Count = 1");
- return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] (file) - "+path);
+ return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] (file) - "+glFileName);
}
// If requested drive is not VIRT and not HOME then reply error
- return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] "+(isGetDirectoryCount?"(dir) - ":"(file) - ")+path);
- }
- private String[] getFilesOrDirs(boolean isGetDirectoryCount, File pathDir) {
- String[] filesOrDirs;
- // Now collecting every folder or file inside
- if (isGetDirectoryCount){
- filesOrDirs = pathDir.list((current, name) -> {
- var dir = new File(current, name);
- return (dir.isDirectory() && ! dir.isHidden());
- });
- }
- else {
- filesOrDirs = pathDir.list((current, name) -> {
- var dir = new File(current, name);
- return (! dir.isDirectory() && nspFilter ?
- name.toLowerCase().endsWith(".nsp") :
- ! dir.isHidden());
- });
- }
- return filesOrDirs;
+ return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] "+(isGetDirectoryCount?"(dir) - ":"(file) - ")+glFileName);
}
/**
@@ -445,14 +356,11 @@ class GoldLeaf_111 extends TransferModule {
else {
var pathDir = new File(dirName);
// Make sure it's exists and it's path
- if ((! pathDir.exists() ) || (! pathDir.isDirectory()) )
+ if (notExistsOrDirectory(pathDir))
return writeGL_FAIL("GL Handle 'GetDirectory' command [doesn't exist or not a folder]");
this.recentPath = dirName;
// Now collecting every folder or file inside
- this.recentDirs = pathDir.list((current, name) -> {
- var dir = new File(current, name);
- return (dir.isDirectory() && ! dir.isHidden()); // TODO: FIX FOR WIN ?
- });
+ this.recentDirs = pathDir.list(this::isDirectoryAndNotHidden);
// Check that we still don't have any fuckups
if (this.recentDirs != null && this.recentDirs.length > subDirNo){
Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER);
@@ -472,11 +380,11 @@ class GoldLeaf_111 extends TransferModule {
* Handle GetFile
* @return true - failed, false - passed
* */
- private boolean getFile(String dirName, int subDirNo){
+ private boolean getFile(String glDirName, int subDirNo){
var command = new LinkedList();
- if (dirName.startsWith("HOME:/")) {
- dirName = updateHomePath(dirName);
+ if (glDirName.startsWith("HOME:/")) {
+ var dirName = updateHomePath(glDirName);
if (dirName.equals(recentPath) && recentFiles != null && recentFiles.length != 0){
var fileNameBytes = recentFiles[subDirNo].getBytes(StandardCharsets.UTF_8);
@@ -485,23 +393,10 @@ class GoldLeaf_111 extends TransferModule {
}
else {
var pathDir = new File(dirName);
- // Make sure it's exists and it's path
- if ((! pathDir.exists() ) || (! pathDir.isDirectory()) ) // TODO: CHECK AND REMOVE .exists() IF REDUNDANT
+ if (notExistsOrDirectory(pathDir))
writeGL_FAIL("GL Handle 'GetFile' command [doesn't exist or not a folder]");
this.recentPath = dirName;
- // Now collecting every folder or file inside
- if (nspFilter){
- this.recentFiles = pathDir.list((current, name) -> {
- var dir = new File(current, name);
- return (! dir.isDirectory() && name.toLowerCase().endsWith(".nsp"));
- });
- }
- else {
- this.recentFiles = pathDir.list((current, name) -> {
- var dir = new File(current, name);
- return (! dir.isDirectory() && (! dir.isHidden()));
- });
- }
+ this.recentFiles = pathDir.list(this::isFileAndNotHidden);
// Check that we still don't have any fuckups
if (this.recentFiles != null && this.recentFiles.length > subDirNo){
Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER);
@@ -514,14 +409,14 @@ class GoldLeaf_111 extends TransferModule {
}
return writeGL_PASS(command, "GL Handle 'GetFile' command.");
}
- else if (dirName.equals("VIRT:/") && (! nspMap.isEmpty())){ // thus nspMapKeySetIndexes also != 0
+ else if (glDirName.equals("VIRT:/") && (! nspMap.isEmpty())){ // thus nspMapKeySetIndexes also != 0
var fileNameBytes = nspMapKeySetIndexes[subDirNo].getBytes(StandardCharsets.UTF_8);
command.add(intToArrLE(fileNameBytes.length));
command.add(fileNameBytes);
return writeGL_PASS(command, "GL Handle 'GetFile' command.");
}
- else if (dirName.equals("SPEC:/") && (selectedFile != null)){
- byte[] fileNameBytes = selectedFile.getName().getBytes(StandardCharsets.UTF_8);
+ else if (glDirName.equals("SPEC:/") && (selectedFile != null)){
+ var fileNameBytes = selectedFile.getName().getBytes(StandardCharsets.UTF_8);
command.add(intToArrLE(fileNameBytes.length));
command.add(fileNameBytes);
return writeGL_PASS(command, "GL Handle 'GetFile' command.");
@@ -541,9 +436,9 @@ class GoldLeaf_111 extends TransferModule {
if (fileDirElement.exists()){
if (fileDirElement.isDirectory())
- command.add(GL_OBJ_TYPE_DIR);
+ command.add(GL_OBJECT_TYPE_DIR);
else {
- command.add(GL_OBJ_TYPE_FILE);
+ command.add(GL_OBJECT_TYPE_FILE);
command.add(longToArrLE(fileDirElement.length()));
}
return writeGL_PASS(command, "GL Handle 'StatPath' command for "+glFileName);
@@ -552,7 +447,7 @@ class GoldLeaf_111 extends TransferModule {
else if (glFileName.startsWith("VIRT:/")) {
var fileName = glFileName.replaceFirst("^.*?:/", "");
if (nspMap.containsKey(fileName)){
- command.add(GL_OBJ_TYPE_FILE); // THIS IS INT
+ command.add(GL_OBJECT_TYPE_FILE); // THIS IS INT
if (nspMap.get(fileName).isDirectory())
command.add(longToArrLE(splitFileSize.get(fileName))); // YES, THIS IS LONG!;
else
@@ -564,7 +459,7 @@ class GoldLeaf_111 extends TransferModule {
else if (glFileName.startsWith("SPEC:/")){
var fileName = glFileName.replaceFirst("^.*?:/", "");
if (selectedFile.getName().equals(fileName)){
- command.add(GL_OBJ_TYPE_FILE);
+ command.add(GL_OBJECT_TYPE_FILE);
command.add(longToArrLE(selectedFile.length()));
return writeGL_PASS(command, "GL Handle 'StatPath' command for "+glFileName);
}
@@ -577,7 +472,7 @@ class GoldLeaf_111 extends TransferModule {
* */
private boolean rename(String glFileName, String glNewFileName){
if (glFileName.startsWith("HOME:/")){
- // This shit takes too much time to explain, but such behaviour won't let GL to fail
+ // Prevent GL failures
this.recentPath = null;
this.recentFiles = null;
this.recentDirs = null;
@@ -590,7 +485,9 @@ class GoldLeaf_111 extends TransferModule {
return writeGL_PASS("GL Handle 'Rename' command.");
}
}
- catch (SecurityException ignored){}
+ catch (SecurityException se){
+ return writeGL_FAIL("GL Handle 'Rename' command failed:\n\t" +se.getMessage());
+ }
}
// For VIRT:/ and others we don't serve requests
return writeGL_FAIL("GL Handle 'Rename' command is not supported for virtual drive, selected files," +
@@ -600,48 +497,43 @@ class GoldLeaf_111 extends TransferModule {
* Handle 'Delete'
* @return true - failed, false - passed
* */
- private boolean delete(String fileName) {
- if (fileName.startsWith("HOME:/")) {
- fileName = updateHomePath(fileName);
+ private boolean delete(String glFileName) {
+ if (! glFileName.startsWith("HOME:/"))
+ return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory] "+glFileName);
- File fileToDel = new File(fileName);
- try {
- if (fileToDel.delete()){
- return writeGL_PASS("GL Handle 'Rename' command.");
- }
- }
- catch (SecurityException ignored){} // Ah, leave it
+ var file = new File(updateHomePath(glFileName));
+ try {
+ if (file.delete())
+ return writeGL_PASS("GL Handle 'Rename' command.");
}
- // For VIRT:/ and others we don't serve requests
- return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory]");
+ catch (SecurityException ignored){} // Ah, leave it
+
+ return writeGL_FAIL("GL Handle 'Create' command [unknown drive/read-only directory]");
}
/**
* Handle 'Create'
- * @param type 1 for file
- * 2 for folder
- * @param fileName full path including new file name in the end
+ * @param type 1 â file, 2 â folder
+ * @param glFileName full path including new file name in the end
* @return true - failed, false - passed
* */
- private boolean create(String fileName, byte type) {
- if (! fileName.startsWith("HOME:/")) // For VIRT:/ and others we don't serve requests
- return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory]");
+ private boolean create(String glFileName, byte type) {
+ if (! glFileName.startsWith("HOME:/")) // For VIRT:/ and others we don't serve requests
+ return writeGL_FAIL("GL Handle 'Create' command [not supported for virtual drive/wrong drive/read-only directory]"+glFileName);
- fileName = updateHomePath(fileName);
-
- boolean result = false;
+ var file = new File(updateHomePath(glFileName));
try {
- if (type == 1)
- result = new File(fileName).createNewFile();
- else if (type == 2)
- result = new File(fileName).mkdir();
+ boolean result = switch (type) {
+ case 1 -> file.createNewFile();
+ case 2 -> file.mkdir();
+ default -> false;
+ };
+
+ if (result)
+ return writeGL_PASS("GL Handle 'Create' command.");
}
catch (SecurityException | IOException ignored){}
- if (result) {
- return writeGL_PASS("GL Handle 'Create' command.");
- }
-
- return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory]");
+ return writeGL_FAIL("GL Handle 'Create' command [unknown drive/read-only directory]");
}
/**
@@ -655,16 +547,14 @@ class GoldLeaf_111 extends TransferModule {
//System.out.println("readFile "+glFileName+"\t"+offset+"\t"+size+"\n");
var fileName = glFileName.replaceFirst("^.*?:/", "");
- if (glFileName.startsWith("VIRT:/")){ // Could have split-file
+ if (glFileName.startsWith("VIRT:/")){ // Could have split-file
// Let's find out which file requested
var fNamePath = nspMap.get(fileName).getAbsolutePath(); // NOTE: 6 = "VIRT:/".length
// If we don't have this file opened, let's open it
if (openReadFileNameAndPath == null || (! openReadFileNameAndPath.equals(fNamePath))) {
- // Try close what opened
- if (openReadFileNameAndPath != null)
+ if (openReadFileNameAndPath != null) // (Try to) close what opened
closeRAFandSplitReader();
- // Open what has to be opened
- try{
+ try{ // And open the rest
var tempFile = nspMap.get(fileName);
if (tempFile.isDirectory()) {
randAccessFile = null;
@@ -713,11 +603,11 @@ class GoldLeaf_111 extends TransferModule {
if (randAccessFile == null){
splitReader.seek(offset);
- bytesRead = splitReader.read(chunk); // Let's find out how many bytes we got
+ bytesRead = splitReader.read(chunk); // How many bytes we got?
}
else {
randAccessFile.seek(offset);
- bytesRead = randAccessFile.read(chunk); // Let's find out how many bytes we got
+ bytesRead = randAccessFile.read(chunk); // How many bytes we got?
}
if (bytesRead != (int) size) // Let's check that we read expected size
@@ -741,7 +631,6 @@ class GoldLeaf_111 extends TransferModule {
/**
* Handle 'WriteFile'
* @param fileName full path including new file name in the end
- *
* @return true - failed, false - passed
* */
private boolean writeFile(String fileName) {
@@ -814,39 +703,56 @@ class GoldLeaf_111 extends TransferModule {
private String updateHomePath(String glPath){
if (isWindows)
glPath = glPath.replaceAll("/", "\\\\");
- glPath = homePath + glPath.substring(6); // Do not use replaceAll since it will consider \ as special directive
+ glPath = homePath + glPath.substring(6); // Better not using .replaceAll() since it will consider \ as special directive
return glPath;
}
- /**
- * Convert INT (Little endian) value to bytes-array representation
- * */
- private byte[] intToArrLE(int value){
- return ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN)
- .putInt(value)
- .array();
- }
- /**
- * Convert LONG (Little endian) value to bytes-array representation
- * */
- private byte[] longToArrLE(long value){
- return ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN)
- .putLong(value)
- .array();
- }
- /**
- * Convert bytes-array to INT value (Little endian)
- * */
- private int arrToIntLE(byte[] byteArrayWithInt, int intStartPosition){
- return ByteBuffer.wrap(byteArrayWithInt).order(ByteOrder.LITTLE_ENDIAN).getInt(intStartPosition);
- }
- /**
- * Convert bytes-array to LONG value (Little endian)
- * */
- private long arrToLongLE(byte[] byteArrayWithLong, int intStartPosition){
- return ByteBuffer.wrap(byteArrayWithLong).order(ByteOrder.LITTLE_ENDIAN).getLong(intStartPosition);
+
+ private boolean isFileAndNotHidden(File parent, String child){
+ var entry = new File(parent, child);
+ return (! entry.isDirectory()) && (nspFilter ?
+ child.toLowerCase().endsWith(".nsp") :
+ ! entry.isHidden());
}
- //------------------------------------------------------------------------------------------------------------------
+ private boolean isDirectoryAndNotHidden(File parent, String child){
+ var dir = new File(parent, child);
+ return (dir.isDirectory() && ! dir.isHidden());
+ }
+
+ private boolean notExistsOrDirectory(File pathDir){
+ return (! pathDir.exists() ) || (! pathDir.isDirectory());
+ }
+
+ /**
+ * Close files opened for read/write
+ */
+ private void closeOpenedReadFilesGl(){
+ if (openReadFileNameAndPath != null){
+ closeRAFandSplitReader();
+ openReadFileNameAndPath = null;
+ randAccessFile = null;
+ splitReader = null;
+ }
+ }
+ private void closeRAFandSplitReader(){
+ closeRAF();
+ try{
+ splitReader.close();
+ }
+ catch (IOException ioe_){
+ print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
+ }
+ catch (Exception ignored){}
+ }
+ private void closeRAF(){
+ try{
+ randAccessFile.close();
+ }
+ catch (IOException ioe_){
+ print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
+ }
+ catch (Exception ignored){}
+ }
/*----------------------------------------------------*/
/* GL READ/WRITE USB SPECIFIC */
/*----------------------------------------------------*/
diff --git a/src/main/java/nsusbloader/com/usb/gl/GoldleafCmd.java b/src/main/java/nsusbloader/com/usb/gl/GoldleafCmd.java
new file mode 100644
index 0000000..be6cf76
--- /dev/null
+++ b/src/main/java/nsusbloader/com/usb/gl/GoldleafCmd.java
@@ -0,0 +1,54 @@
+/*
+ Copyright 2019-2025 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 .
+ */
+package nsusbloader.com.usb.gl;
+
+public enum GoldleafCmd {
+ GetDriveCount((byte) 1),
+ GetDriveInfo((byte) 2),
+ StatPath((byte) 3),
+ GetFileCount((byte) 4),
+ GetFile((byte) 5),
+ GetDirectoryCount((byte) 6),
+ GetDirectory((byte) 7),
+ StartFile((byte) 8),
+ ReadFile((byte) 9),
+ WriteFile((byte) 10),
+ EndFile((byte) 11),
+ Create((byte) 12),
+ Delete((byte) 13),
+ Rename((byte) 14),
+ GetSpecialPathCount((byte) 15),
+ GetSpecialPath((byte) 16),
+ SelectFile((byte) 17),
+ CMD_UNKNOWN((byte) 255);
+
+ private final byte id;
+
+ GoldleafCmd(byte id) {
+ this.id = id;
+ }
+
+ public static GoldleafCmd get(byte id) {
+ for(GoldleafCmd cmd : values()) {
+ if(cmd.id == id)
+ return cmd;
+ }
+ return CMD_UNKNOWN;
+ }
+}
\ No newline at end of file