diff --git a/nsul_nxdt_patch.diff b/nsul_nxdt_patch.diff index 5abd734..17f9275 100644 --- a/nsul_nxdt_patch.diff +++ b/nsul_nxdt_patch.diff @@ -1,296 +1,36 @@ diff --git a/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java b/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java -index 9e5fd9b..fcd33a3 100644 +index dd2a1bc..4a3d7fd 100644 --- a/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java +++ b/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java -@@ -22,6 +22,7 @@ import nsusbloader.COM.USB.UsbErrorCodes; - import nsusbloader.ModelControllers.ILogPrinter; - import nsusbloader.NSLDataTypes.EMsgType; - import org.usb4java.DeviceHandle; -+import org.usb4java.DeviceDescriptor; - import org.usb4java.LibUsb; +@@ -111,6 +111,9 @@ class NxdtUsbAbi1 { + DeviceInformation deviceInformation = DeviceInformation.build(handlerNS); + NsUsbEndpointDescriptor endpointInDescriptor = deviceInformation.getSimplifiedDefaultEndpointDescriptorIn(); + this.endpointMaxPacketSize = endpointInDescriptor.getwMaxPacketSize(); ++ ++ USBSTATUS_SUCCESS[8] = (byte)(endpointMaxPacketSize & 0xFF); ++ USBSTATUS_SUCCESS[9] = (byte)((endpointMaxPacketSize >> 8) & 0xFF); + } - import java.io.*; -@@ -40,9 +41,21 @@ class NxdtUsbAbi1 { - private final boolean isWindows; - private boolean isWindows10; - -+ private short endpointMaxPacketSize = 0; -+ - private static final int NXDT_MAX_DIRECTIVE_SIZE = 0x1000; - private static final int NXDT_FILE_CHUNK_SIZE = 0x800000; - private static final int NXDT_FILE_PROPERTIES_MAX_NAME_LENGTH = 0x300; -+ private static final int NXDT_USB_TIMEOUT = 5000; -+ -+ private static final short NXDT_USB_FS_BCD_REVISION = 0x0110; -+ private static final short NXDT_USB_FS_EP_MAX_PACKET_SIZE = 0x40; -+ -+ private static final short NXDT_USB_HS_BCD_REVISION = 0x0200; -+ private static final short NXDT_USB_HS_EP_MAX_PACKET_SIZE = 0x200; -+ -+ private static final short NXDT_USB_SS_BCD_REVISION = 0x0300; -+ private static final short NXDT_USB_SS_EP_MAX_PACKET_SIZE = 0x400; - - private static final byte ABI_VERSION = 1; - private static final byte[] MAGIC_NXDT = { 0x4e, 0x58, 0x44, 0x54 }; -@@ -77,8 +90,6 @@ class NxdtUsbAbi1 { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - -- private static final long W_MAX_PACKET_SIZE = 0x200; -- - public NxdtUsbAbi1(DeviceHandle handler, - ILogPrinter logPrinter, - String saveToPath, -@@ -174,7 +185,58 @@ class NxdtUsbAbi1 { + private void readLoop(){ +@@ -187,16 +190,8 @@ class NxdtUsbAbi1 { writeUsb(USBSTATUS_UNSUPPORTED_ABI); throw new Exception("ABI v"+versionABI+" is not supported in current version."); } -- writeUsb(USBSTATUS_SUCCESS); -+ -+ // Get endpoint max packet size -+ getEndpointMaxPacketSize(); -+ -+ // Send status response + endpoint max packet size -+ byte[] response = new byte[USBSTATUS_SUCCESS.length + 2]; -+ System.arraycopy(USBSTATUS_SUCCESS, 0, response, 0, USBSTATUS_SUCCESS.length); -+ response[USBSTATUS_SUCCESS.length] = (byte)(endpointMaxPacketSize & 0xFF); -+ response[USBSTATUS_SUCCESS.length + 1] = (byte)((endpointMaxPacketSize >> 8) & 0xFF); -+ -+ writeUsb(response); -+ } -+ -+ private void getEndpointMaxPacketSize() throws Exception{ -+ // Get device descriptor to determine the max packet size in use. We'll send it to the console. -+ // We'll get the device descriptor instead of an endpoint descriptor because it's a non-blocking call (the device descriptor is cached in memory by usb4java). -+ DeviceDescriptor deviceDescriptor = getDeviceDescriptor(); -+ -+ short bcdUsbRevision = deviceDescriptor.bcdUSB(); -+ byte usbRevisionUpper = (byte)((bcdUsbRevision >> 8) & 0xFF); -+ byte usbRevisionLower = (byte)(bcdUsbRevision & 0xFF); +- replyToHandshake(); +- } +- private void replyToHandshake() throws Exception{ +- // Send status response + endpoint max packet size +- ByteBuffer buffer = ByteBuffer.allocate(USBSTATUS_SUCCESS.length + 2).order(ByteOrder.LITTLE_ENDIAN); +- buffer.put(USBSTATUS_SUCCESS); +- buffer.putShort(endpointMaxPacketSize); +- byte[] response = buffer.array(); +- +- writeUsb(response); + -+ switch(bcdUsbRevision){ -+ case NXDT_USB_FS_BCD_REVISION: // USB 1.1 (Full Speed). -+ endpointMaxPacketSize = NXDT_USB_FS_EP_MAX_PACKET_SIZE; -+ break; -+ case NXDT_USB_HS_BCD_REVISION: // USB 2.0 (High Speed). -+ endpointMaxPacketSize = NXDT_USB_HS_EP_MAX_PACKET_SIZE; -+ break; -+ case NXDT_USB_SS_BCD_REVISION: // USB 3.0 (Super Speed). -+ endpointMaxPacketSize = NXDT_USB_SS_EP_MAX_PACKET_SIZE; -+ break; -+ default: -+ writeUsb(USBSTATUS_HOSTIOERROR); -+ throw new Exception("Invalid BCD USB release number \""+usbRevisionUpper+"."+usbRevisionLower+"\" in device descriptor!"); -+ } -+ -+ //logPrinter.print("USB revision: "+usbRevisionUpper+"."+usbRevisionLower+".", EMsgType.INFO); -+ //logPrinter.print("Max packet size: "+endpointMaxPacketSize+" b.", EMsgType.INFO); -+ } -+ -+ private DeviceDescriptor getDeviceDescriptor() throws Exception{ -+ int result; -+ DeviceDescriptor descriptor = new DeviceDescriptor(); -+ -+ result = LibUsb.getDeviceDescriptor(LibUsb.getDevice(handlerNS), descriptor); -+ if (result != LibUsb.SUCCESS){ -+ writeUsb(USBSTATUS_HOSTIOERROR); -+ throw new Exception("Failed to get device descriptor! Returned "+result+" ("+UsbErrorCodes.getErrCode(result)+")."); -+ } -+ -+ return descriptor; ++ writeUsb(USBSTATUS_SUCCESS); } private void handleSendFileProperties(byte[] message) throws Exception{ -@@ -188,6 +250,8 @@ class NxdtUsbAbi1 { - return; - } - -+ logPrinter.print("Receiving: '"+filename+"' ("+fileSize+" b)", EMsgType.INFO); -+ - // If RomFs related - if (isRomFs(filename)) { - if (isWindows) -@@ -198,7 +262,6 @@ class NxdtUsbAbi1 { - createPath(filename); - } - else { -- logPrinter.print("Receiving: '"+filename+"' ("+fileSize+" b)", EMsgType.INFO); - filename = saveToPath + filename; - } - -@@ -222,13 +285,11 @@ class NxdtUsbAbi1 { - if (fileSize == 0) - return; - -- if (isWindows10) -- dumpFileOnWindowsTen(fileToDump, fileSize); -- else -- dumpFile(fileToDump, fileSize); -+ dumpFile(fileToDump, fileSize); - - writeUsb(USBSTATUS_SUCCESS); - -+ //logPrinter.print("File transfer successfully finished!", EMsgType.INFO); - } - - private int getLEint(byte[] bytes, int fromOffset){ -@@ -258,63 +319,46 @@ class NxdtUsbAbi1 { - } - - private void dumpFile(File file, long size) throws Exception{ -- try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, false))) { -- byte[] readBuffer; -- long received = 0; -- int bufferSize; -- -- boolean zlt_expected = isAligned(size); -- -- while (received < size) { -- readBuffer = readUsbFile(); -- bos.write(readBuffer); -- bufferSize = readBuffer.length; -- received += bufferSize; -- logPrinter.updateProgress((received + bufferSize) / (size / 100.0) / 100.0); -- } -+ byte[] readBuffer; -+ long received = 0; -+ int chunkSize = NXDT_FILE_CHUNK_SIZE; - -- if (zlt_expected) { -- logPrinter.print("Finishing with ZLT packet request", EMsgType.INFO); -- readUsbFile(); -- } -- } finally { -- logPrinter.updateProgress(1.0); -- } -- } -+ boolean zltExpected = isAligned(size, endpointMaxPacketSize); -+ //logPrinter.print("ZLT packet expected: "+zlt_expected, EMsgType.INFO); - -- // @see https://bugs.openjdk.java.net/browse/JDK-8146538 -- private void dumpFileOnWindowsTen(File file, long size) throws Exception{ -- FileOutputStream fos = new FileOutputStream(file, true); -+ FileOutputStream fos = new FileOutputStream(file, false); -+ FileDescriptor fd = fos.getFD(); - - try (BufferedOutputStream bos = new BufferedOutputStream(fos)) { -- FileDescriptor fd = fos.getFD(); -- byte[] readBuffer; -- long received = 0; -- int bufferSize; -- -- boolean zlt_expected = isAligned(size); -+ while(true){ -+ // Check if we aren't expecting a ZLT packet and the whole file has already been received. -+ if (!zltExpected && received >= size) break; -+ -+ // Update chunk size if needed. -+ if (received < size && (long)chunkSize > (size - received)) chunkSize = (int)(size - received); -+ -+ // Read current chunk. Don't attempt to read more than we're supposed to by allocating a buffer with a size equal to the current chunk size. -+ // Immediately check if we're dealing with a ZLT packet afterwards. -+ readBuffer = readUsbFile(chunkSize); -+ if (readBuffer == null || readBuffer.length == 0) -+ { -+ //logPrinter.print("ZLT packet received.", EMsgType.INFO); -+ if (zltExpected && received >= size) break; -+ continue; -+ } - -- while (received < size) { -- readBuffer = readUsbFile(); - bos.write(readBuffer); -- fd.sync(); // Fixes flushing under Windows (unharmful for other OS) -- bufferSize = readBuffer.length; -- received += bufferSize; -+ if (isWindows10) fd.sync(); // Fixes flushing under Windows 10. See https://bugs.openjdk.java.net/browse/JDK-8146538 -+ received += readBuffer.length; - -- logPrinter.updateProgress((received + bufferSize) / (size / 100.0) / 100.0); -+ //logPrinter.print("Received "+readBuffer.length+" b. Got thus far: "+received+" b.", EMsgType.INFO); -+ logPrinter.updateProgress((double)received / (double)size); - } -- -- if (zlt_expected) { -- logPrinter.print("Finishing with ZLT packet request", EMsgType.INFO); -- readUsbFile(); -- } -- } finally { -- logPrinter.updateProgress(1.0); - } - } - /** Handle Zero-length terminator **/ -- private boolean isAligned(long size){ -- return ((size & (W_MAX_PACKET_SIZE - 1)) == 0); -+ private boolean isAligned(long size, long alignment){ -+ return ((size & (alignment - 1)) == 0); - } - - /** Sending any byte array to USB device **/ -@@ -326,7 +370,7 @@ class NxdtUsbAbi1 { - if ( parent.isCancelled() ) - throw new InterruptedException("Execution interrupted"); - -- int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050); -+ int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, NXDT_USB_TIMEOUT); - - if (result == LibUsb.SUCCESS) { - if (writeBufTransferred.get() == message.length) -@@ -338,7 +382,6 @@ class NxdtUsbAbi1 { - throw new Exception("Data transfer issue [write]" + - "\n Returned: " + UsbErrorCodes.getErrCode(result) + - "\n (execution stopped)"); -- - } - /** - * Reading what USB device responded (command). -@@ -374,29 +417,25 @@ class NxdtUsbAbi1 { - * @return byte array if data read successful - * 'null' if read failed - * */ -- private byte[] readUsbFile() throws Exception{ -- ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_FILE_CHUNK_SIZE); -+ private byte[] readUsbFile(int chunkSize) throws Exception{ -+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(chunkSize); - IntBuffer readBufTransferred = IntBuffer.allocate(1); -- int result; -- int countDown = 0; -- while (! parent.isCancelled() && countDown < 5) { -- result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000); - -- switch (result) { -- case LibUsb.SUCCESS: -- int trans = readBufTransferred.get(); -- byte[] receivedBytes = new byte[trans]; -- readBuffer.get(receivedBytes); -- return receivedBytes; -- case LibUsb.ERROR_TIMEOUT: -- countDown++; -- break; -- default: -- throw new Exception("Data transfer issue [read file]" + -- "\n Returned: " + UsbErrorCodes.getErrCode(result)+ -- "\n (execution stopped)"); -- } -+ if ( parent.isCancelled() ) -+ throw new InterruptedException(); -+ -+ int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, NXDT_USB_TIMEOUT); -+ -+ switch (result) { -+ case LibUsb.SUCCESS: -+ int trans = readBufTransferred.get(); -+ byte[] receivedBytes = new byte[trans]; -+ readBuffer.get(receivedBytes); -+ return receivedBytes; -+ default: -+ throw new Exception("Data transfer issue [read file]" + -+ "\n Returned: " + UsbErrorCodes.getErrCode(result)+ -+ "\n (execution stopped)"); - } -- throw new InterruptedException(); - } - } diff --git a/src/main/resources/NSLMain.fxml b/src/main/resources/NSLMain.fxml index a2d42d6..9114c3d 100644 --- a/src/main/resources/NSLMain.fxml