RCM (Fusée Gelée) support, numerous UI updates and a lot of things for version 2.

This commit is contained in:
Dmitry Isaenko 2020-02-10 02:19:39 +03:00
parent 3d3fb56f9e
commit 010c33c593
36 changed files with 1572 additions and 92 deletions

45
BUILD.md Normal file
View file

@ -0,0 +1,45 @@
### How to build this app
Java application:
* Install Maven
* Execute
`# mvn -B -DskipTests clean package`
**Building JNI libraries section**
First of all install JDK, GCC, make, kernel headers and whatever else (or use Gentoo <3 ).
Generate header (Optional! Already generated.):
```
$ cp NS-USBloader/src/main/java/nsusbloader/Utilities/RcmSmash.java .
$ javac -h . RcmSmash.java
```
**Build for Linux (amd64 Linux host):**
```
$ cd 'NS-USBloader/JNI sources/linux'
$ make install clean
```
**Build for Windows (on x86_64 host):**
[ This part should be updated ]
Install MinGW, msys (?) MinGW-w64 and JDK. Set JAVA_HOME, set PATH to match MinGW, MSYS, JDK/bin (and other?) environment variables.
x86: Install MinGw to C:\MinGW\
Update sources: set (uncomment) line 'BUILD_FOR_X86'
Set environment variables for MinGw:
* C:\MinGW\bin
* C:\MinGW\msys\1.0\bin
```
$ cd 'NS-USBloader/JNI sources/windows'
$ make x86
```
amd64: Install MinGw-w64
Update sources: remove line 'BUILD_FOR_X86'
```
$ make amd64
```

View file

@ -0,0 +1,33 @@
# Compiler
CC=gcc
# Flags
CFLAGS=-O2
MKDIR_P = mkdir -p
APP_NAME = smashlib.so
all: x86 amd64
x86:
$(MKDIR_P) ./x86
$(CC) ${CFLAGS} -m32 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" smashlib.c -o smashlib_x86.o
$(CC) ${CFLAGS} -m32 -shared -fPIC -o ./x86/${APP_NAME} smashlib_x86.o -lc
amd64:
$(MKDIR_P) ./amd64
$(CC) ${CFLAGS} -m64 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" smashlib.c -o smashlib_amd64.o
$(CC) ${CFLAGS} -m64 -shared -fPIC -o ./amd64/${APP_NAME} smashlib_amd64.o -lc
clean:
rm -rf \
smashlib_amd64.o \
smashlib_x86.o \
./x86 \
./amd64
install: x86 amd64
install ./x86/${APP_NAME} ../../src/main/resources/native/linux/x86/
install ./amd64/${APP_NAME} ../../src/main/resources/native/linux/amd64/
uninstall:
rm ../../src/main/resources/native/linux/x86/${APP_NAME}
rm ../../src/main/resources/native/linux/amd64/${APP_NAME}

View file

@ -0,0 +1,29 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class nsusbloader_Utilities_RcmSmash */
#ifndef _Included_nsusbloader_Utilities_RcmSmash
#define _Included_nsusbloader_Utilities_RcmSmash
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: nsusbloader_Utilities_RcmSmash
* Method: smashLinux
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashLinux
(JNIEnv *, jclass, jint, jint);
/*
* Class: nsusbloader_Utilities_RcmSmash
* Method: smashWindows
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashWindows
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

88
JNI sources/linux/smashlib.c Executable file
View file

@ -0,0 +1,88 @@
/* NS-USBloader - native libraries for 'special purposes'
* Copyright (C) 2020 Dmitry Isaenko
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/ch9.h>
#include <errno.h>
#include "nsusbloader_Utilities_RcmSmash.h"
struct usbdevfs_urb urb;
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashLinux
(JNIEnv * jni_env, jclass this_class, jint bus_id, jint device_addr){
int ret_value;
char *usb_path = (char*)malloc(24 * sizeof(char));
sprintf(usb_path, "/dev/bus/usb/%03d/%03d", bus_id, device_addr);
int fd = open(usb_path, O_RDWR);
if (fd == -1)
return -1;
struct usb_ctrlrequest* ctrl_req;
__u8* buf[0x7000+sizeof(ctrl_req)];
ctrl_req = (struct usb_ctrlrequest *) buf;
ctrl_req->bRequestType = 0x82;
ctrl_req->bRequest = USB_REQ_GET_STATUS;
ctrl_req->wValue = 0;
ctrl_req->wIndex = 0;
ctrl_req->wLength = 0x7000;
memset(&urb, 0, sizeof(urb));
urb.type = USBDEVFS_URB_TYPE_CONTROL;
urb.endpoint = USB_DIR_IN | 0;
urb.buffer = buf;
urb.buffer_length = sizeof(buf);
//Submit request
ret_value = ioctl(fd, USBDEVFS_SUBMITURB, &urb);
// If we failed on this step, it's a VERY bad sign. Nothing to do, let's report failure.
if (ret_value != 0)
return ret_value;
// Wait 1/4 sec
usleep(250000);
struct usbdevfs_urb urb1;
// Let's pick reply (everybody does it, right? In non-blocking manner.)
ret_value = ioctl(fd, USBDEVFS_REAPURBNDELAY, &urb1);
if (ret_value < 0){
if (errno == EAGAIN){ // In case of resource temporarily unavailable
// Wired.. so much time left. Let's cancel it!
ret_value = ioctl(fd, USBDEVFS_DISCARDURB, &urb);
// And wait a bit more..
usleep(40000);
// And try to pick reply. Yes, it's still possible. See /usr/src/linux/drivers/usb/core/devio.c
ret_value = ioctl(fd, USBDEVFS_REAPURBNDELAY, &urb1);
}
}
// Leftovers.
free(usb_path);
// Let's try to close device, but even if we fail with this, nvm.
close(fd); // So we won't even write returned value somewhere.
return 0;
}
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashWindows
(JNIEnv * jni_env, jclass this_class){
return -1;
}

View file

@ -0,0 +1,34 @@
# Compiler
CC32='C:/MinGW/bin/gcc'
CC64='C:/Program Files/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/gcc'
# Flags
CFLAGS=-O2
MKDIR_P=mkdir
APP_NAME=smashlib.dll
all: x86 amd64
#$(CC) ${CFLAGS} -m32 -c -fPIC -I "C:/MinGW/include/ddk" -I "${JAVA_HOME}/include" -I "${JAVA_HOME}/include/win32" smashlib.c -o ./x86/smashlib.o # MinGw-32 version
x86:
$(MKDIR_P) ./x86
export PATH="C/MinGW/bin/:${PATH}"
$(CC32) ${CFLAGS} -m32 -c -fPIC -I "C:/MinGW/include/ddk" -I "${JAVA_HOME}/include" -I "${JAVA_HOME}/include/win32" smashlib.c -o ./smashlib_x86.o
$(CC32) ${CFLAGS} -shared -o ./x86/${APP_NAME} ./smashlib_x86.o -lsetupapi -lhid -Wl,--add-stdcall-alias
#$(CC) ${CFLAGS} -m64 -c -fPIC -I "C:/MinGW/include/ddk" -I "${JAVA_HOME}/include" -I "${JAVA_HOME}/include/win32" smashlib.c -o ./amd64/smashlib.o # MinGw-32 version
amd64:
$(MKDIR_P) ./amd64
export PATH="C/Program Files/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/:${PATH}"
$(CC64) ${CFLAGS} -m64 -c -fPIC -I "${JAVA_HOME}/include" -I "${JAVA_HOME}/include/win32" smashlib.c -o ./smashlib_amd64.o
$(CC64) ${CFLAGS} -shared -o ./amd64/${APP_NAME} ./smashlib_amd64.o -lsetupapi -lhid -Wl,--add-stdcall-alias
clean:
rm -rf ./smashlib_x86.o ./smashlib_amd64.o ./x86 ./amd64
install: x86 amd64
install ./x86/${APP_NAME} ../../src/main/resources/native/windows/x86/
install ./amd64/${APP_NAME} ../../src/main/resources/native/windows/amd64/
uninstall:
rm ../../src/main/resources/native/windows/x86/${APP_NAME}
rm ../../src/main/resources/native/windows/amd64/${APP_NAME}

View file

@ -0,0 +1,29 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class nsusbloader_Utilities_RcmSmash */
#ifndef _Included_nsusbloader_Utilities_RcmSmash
#define _Included_nsusbloader_Utilities_RcmSmash
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: nsusbloader_Utilities_RcmSmash
* Method: smashLinux
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashLinux
(JNIEnv *, jclass, jint, jint);
/*
* Class: nsusbloader_Utilities_RcmSmash
* Method: smashWindows
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashWindows
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,168 @@
/*
* Derivative & modified code based on awesome example from here: https://www.velleman.eu/images/tmp/usbfind.c
* And MSDN documentation :)
*
* return
* -2 device not connected
* -1 Unable to open handler
* 0 maybe we're all set
*/
#ifdef __cplusplus
extern "C" {
#endif
#define _DEBUG
#define _BUILD_FOR_X86
#include <windows.h>
#include <tchar.h>
#include <setupapi.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#ifdef BUILD_FOR_X86
#include <ntddser.h>
#endif
#include "nsusbloader_Utilities_RcmSmash.h"
#define LIBUSB_IOCTL_GET_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
static GUID GUID_DEVINTERFACE_USB_DEVICE = {0xA5DCBF10L, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED}};
// NOTE: CHANGE TO NV DEVICE!
//static TCHAR VID_PID_PAIR[] = _T("vid_1a86&pid_7523"); // UNCOMMENT FOR TESTS
static TCHAR VID_PID_PAIR[] = _T("vid_0955&pid_7321"); // UNCOMMENT ON RELEASE
typedef struct
{
unsigned int timeout;
unsigned int recipient;
unsigned int index;
unsigned int status;
unsigned int ___zeroes_hold_0; // made it for better understanding. Literally useless.
unsigned int ___zeroes_hold_1; // Just consider each int as 4 bytes and calculate size =)
} simple_status_req;
int win32_magic(LPCSTR lpFileName){
unsigned char reqBuf[24] = {0};
simple_status_req* request;
request = (simple_status_req *) &reqBuf;
request->timeout = 1000;
request->recipient = 0x02;
request->index = 0;
request->status = 0;
#ifdef DEBUG
printf("Device path: %s\nStatus: %x\nIn buffer size: %d\nIn buffer content: ",
lpFileName,
LIBUSB_IOCTL_GET_STATUS,
sizeof(reqBuf) ); // Path and what is our IOCTL request looks like
for (int i = 0; i < sizeof(reqBuf); i++)
printf("%x ", reqBuf[i]);
printf("\n");
#endif
unsigned char outBuffer[28672];
OVERLAPPED ovrlpd;
memset(&ovrlpd, 0, sizeof(ovrlpd));
// Fucking finally let's open this
HANDLE handler = CreateFile(
lpFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if ( handler == INVALID_HANDLE_VALUE )
return -1;
BOOL ret_val = DeviceIoControl(
handler,
LIBUSB_IOCTL_GET_STATUS,
(LPVOID) &reqBuf,
24,
(LPVOID) &outBuffer,
28672,
NULL,
&ovrlpd
);
#ifdef DEBUG
printf("\nDeviceIoControl reports: %d\nLast Error Code: %d\n", ret_val, GetLastError());
#endif
Sleep(250);
DWORD bReceived = 0;
ret_val = GetOverlappedResult(handler, &ovrlpd, &bReceived, FALSE);
#ifdef DEBUG
if (! ret_val) {
// we won't report any issues since there is no workaround.
printf("\nLast Error Code: %d\n\n", GetLastError());
}
#endif
CloseHandle(handler);
return 0;
}
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashWindows
(JNIEnv * jnie_enb, jclass this_class) {
int found = 0;
int ret_val = -2;
HDEVINFO hDevInfo;
SP_DEVICE_INTERFACE_DATA DevIntfData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize, dwType, dwMemberIdx;
HKEY hKey;
BYTE lpData[1024];
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE){
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
while(GetLastError() != ERROR_NO_MORE_ITEMS) {
DevData.cbSize = sizeof(DevData);
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
DevIntfDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData)) {
if (NULL != _tcsstr((TCHAR*)DevIntfDetailData->DevicePath, VID_PID_PAIR)) {
found = 1;
ret_val = win32_magic(DevIntfDetailData->DevicePath);
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
if (found)
break;
// Continue looping
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, ++dwMemberIdx, &DevIntfData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
#ifdef DEBUG
printf("Returning value: %d\n", ret_val);
#endif
return ret_val;
}
JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashLinux
(JNIEnv * jnie_env, jclass this_class, jint bus_id, jint device_addr){
return -1;
}

View file

@ -4,8 +4,12 @@
[Support author](#support-this-app)
NS-USBloader is a PC-side installer for **[Adubbz/TinFoil (v0.2.1)](https://github.com/Adubbz/Tinfoil/)**, **[Huntereb/Awoo-Installer](https://github.com/Huntereb/Awoo-Installer)** (USB and Network supported) and **[XorTroll/GoldLeaf](https://github.com/XorTroll/Goldleaf)** (USB) NSP installer.
NS-USBloader is:
* A PC-side installer for **[Adubbz/TinFoil (v0.2.1)](https://github.com/Adubbz/Tinfoil/)**, **[Huntereb/Awoo-Installer](https://github.com/Huntereb/Awoo-Installer)** (USB and Network supported) and **[XorTroll/GoldLeaf](https://github.com/XorTroll/Goldleaf)** (USB) NSP installer.
Replacement for default **usb_install_pc.py**, **remote_install_pc.py**, **GoldTree**/**Quark**.
* This application also could be used as RCM payload on Windows, MacOS and Linux (supported arch: x86, x86_64).
* And of course it's a tool for split files!
* And also for merging split-files into one :)
[Click here for Android version ;)](https://github.com/developersu/ns-usbloader-mobile)
@ -23,6 +27,7 @@ Sometimes I add new posts about this project [on my home page](https://developer
* [OpenJFX](https://wiki.openjdk.java.net/display/OpenJFX/Main)
* [usb4java](https://mvnrepository.com/artifact/org.usb4java/usb4java)
* Few icons taken from: [materialdesignicons.com](http://materialdesignicons.com/)
* Information, ideas and data from ['fusee-launcher'](https://github.com/reswitched/fusee-launcher) application
#### List of awesome contributors!
@ -73,6 +78,12 @@ root # vim /etc/udev/rules.d/99-NS.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="3000", GROUP="plugdev"
root # udevadm control --reload-rules && udevadm trigger
```
4. For RCM part
```
root # vim /etc/udev/rules.d/99-NS-RCM.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="0955", ATTRS{idProduct}=="7321", GROUP="plugdev"
root # udevadm control --reload-rules && udevadm trigger
```
Please note: you may have to change 'plugdev' group from example above to the different one. It's depends on you linux distro.
@ -155,7 +166,6 @@ Upload somewhere (create PR, use pastebin/google drive/whatever else). [Create n
To convert files of any locale to readable format (and vise-versa) you can use this site [https://itpro.cz/juniconv/](https://itpro.cz/juniconv/)
#### TODO (maybe):
- [x] [Android support](https://github.com/developersu/ns-usbloader-mobile)
- [ ] File order sort (non-critical)

View file

@ -8,7 +8,7 @@
<name>NS-USBloader</name>
<artifactId>ns-usbloader</artifactId>
<version>1.1.0-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>
<url>https://github.com/developersu/ns-usbloader/</url>
<description>

View file

@ -123,7 +123,7 @@ public class AppPreferences {
public double getSceneWidth(){ return preferences.getDouble("WIND_WIDTH", 850.0); }
public void setSceneWidth(double value){ preferences.putDouble("WIND_WIDTH", value); }
public double getSceneHeight(){ return preferences.getDouble("WIND_HEIGHT", 475.0); }
public double getSceneHeight(){ return preferences.getDouble("WIND_HEIGHT", 525.0); }
public void setSceneHeight(double value){ preferences.putDouble("WIND_HEIGHT", value); }
// Split and Merge //
public int getSplitMergeType(){ return preferences.getInt("SM_TYPE", 0); }
@ -131,4 +131,7 @@ public class AppPreferences {
public String getSplitMergeRecent(){ return preferences.get("SM_RECENT", System.getProperty("user.home")); }
public void setSplitMergeRecent(String value){ preferences.put("SM_RECENT", value); }
// RCM //
public String getRecentRcm(int num){ return preferences.get(String.format("RCM_%02d", num), ""); }
public void setRecentRcm(int num, String value){ preferences.put(String.format("RCM_%02d", num), value); }
}

View file

@ -42,14 +42,14 @@ public class UsbCommunications extends Task<Void> {
protected Void call() {
logPrinter.print("\tStart chain", EMsgType.INFO);
UsbConnect usbConnect = new UsbConnect(logPrinter);
UsbConnect usbConnect = new UsbConnect(logPrinter, false);
if (! usbConnect.isConnected()){
close(EFileStatus.FAILED);
return null;
}
DeviceHandle handler = usbConnect.getHandlerNS();
DeviceHandle handler = usbConnect.getNsHandler();
TransferModule module;

View file

@ -4,20 +4,41 @@ import nsusbloader.ModelControllers.LogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import org.usb4java.*;
class UsbConnect {
private final int DEFAULT_INTERFACE = 0;
public class UsbConnect {
private int DEFAULT_INTERFACE;
private Context contextNS;
private DeviceHandle handlerNS;
private Device deviceNS;
private LogPrinter logPrinter;
private boolean connected;
private boolean connected; // TODO: replace to 'connectionFailure' and invert requests everywhere
UsbConnect(LogPrinter logPrinter){
public UsbConnect(LogPrinter logPrinter, boolean initForRCM){
this.logPrinter = logPrinter;
this.connected = false;
short VENDOR_ID;
short PRODUCT_ID;
if (initForRCM){
// CORRECT NV:
DEFAULT_INTERFACE = 1;
VENDOR_ID = 0x0955;
PRODUCT_ID = 0x7321;
/* // QA:
DEFAULT_INTERFACE = 0;
VENDOR_ID = 0x1a86;
PRODUCT_ID = 0x7523;
*/
}
else {
DEFAULT_INTERFACE = 0;
VENDOR_ID = 0x057E;
PRODUCT_ID = 0x3000;
}
int result;
// Creating Context required by libusb. Optional. TODO: Consider removing.
@ -28,7 +49,6 @@ class UsbConnect {
close();
return;
}
else
logPrinter.print("libusb initialization", EMsgType.PASS);
// Searching for NS in devices: obtain list of all devices
@ -39,11 +59,10 @@ class UsbConnect {
close();
return;
}
else
logPrinter.print("Get device list", EMsgType.PASS);
// Searching for NS in devices: looking for NS
DeviceDescriptor descriptor;
Device deviceNS = null;
deviceNS = null;
for (Device device: deviceList){
descriptor = new DeviceDescriptor(); // mmm.. leave it as is.
result = LibUsb.getDeviceDescriptor(device, descriptor);
@ -53,21 +72,20 @@ class UsbConnect {
close();
return;
}
if ((descriptor.idVendor() == 0x057E) && descriptor.idProduct() == 0x3000){
if ((descriptor.idVendor() == VENDOR_ID) && descriptor.idProduct() == PRODUCT_ID){
deviceNS = device;
logPrinter.print("Read file descriptors for USB devices", EMsgType.PASS);
break;
}
}
// Free device list.
if (deviceNS != null){
logPrinter.print("NS in connected USB devices found", EMsgType.PASS);
}
else {
if (deviceNS == null){
logPrinter.print("NS in connected USB devices not found", EMsgType.FAIL);
close();
return;
}
logPrinter.print("NS in connected USB devices found", EMsgType.PASS);
// Handle NS device
handlerNS = new DeviceHandle();
result = LibUsb.open(deviceNS, handlerNS);
@ -75,10 +93,11 @@ class UsbConnect {
logPrinter.print("Open NS USB device\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
if (result == LibUsb.ERROR_ACCESS)
logPrinter.print("Double check that you have administrator privileges (you're 'root') or check 'udev' rules set for this user (linux only)!\n\n" +
"Steps to set 'udev' rules:\n" +
String.format("Steps to set 'udev' rules:\n" +
"root # vim /etc/udev/rules.d/99-NS.rules\n" +
"SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"057e\", ATTRS{idProduct}==\"3000\", GROUP=\"plugdev\"\n" +
"root # udevadm control --reload-rules && udevadm trigger\n", EMsgType.INFO);
"SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", GROUP=\"plugdev\"\n" +
"root # udevadm control --reload-rules && udevadm trigger\n", VENDOR_ID, PRODUCT_ID)
, EMsgType.INFO);
// Let's make a bit dirty workaround since such shit happened
logPrinter.print("Requested context close", EMsgType.INFO);
LibUsb.exit(contextNS);
@ -107,6 +126,7 @@ class UsbConnect {
return;
}
*/
if ( ! initForRCM){
// Set configuration (soft reset if needed)
result = LibUsb.setConfiguration(handlerNS, 1); // 1 - configuration all we need
if (result != LibUsb.SUCCESS){
@ -114,9 +134,8 @@ class UsbConnect {
close();
return;
}
else
logPrinter.print("Set active configuration to device.", EMsgType.PASS);
}
// Claim interface
result = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE);
if (result != LibUsb.SUCCESS) {
@ -124,7 +143,6 @@ class UsbConnect {
close();
return;
}
else
logPrinter.print("Claim interface", EMsgType.PASS);
this.connected = true;
@ -134,23 +152,36 @@ class UsbConnect {
* Get USB status
* @return status of connection
*/
boolean isConnected() { return connected; }
public boolean isConnected() { return connected; }
/**
* Getter for handler
* @return DeviceHandle of NS
*/
DeviceHandle getHandlerNS(){ return handlerNS; }
public DeviceHandle getNsHandler(){ return handlerNS; }
/**
* Getter for 'Bus ID' where NS located found
*/
public int getNsBus(){
return LibUsb.getBusNumber(deviceNS);
}
/**
* Getter for 'Device address' where NS located at
*/
public int getNsAddress(){
return LibUsb.getDeviceAddress(deviceNS);
}
/**
* Correct exit
* */
void close(){
public void close(){
// Close handler in the end
if (handlerNS != null) {
// Try to release interface
int result = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE);
if (result != LibUsb.SUCCESS)
logPrinter.print("Release interface\n Returned: "+result+" (sometimes it's not an issue)", EMsgType.WARNING);
logPrinter.print("Release interface" +
"\n Returned: "+result+" (sometimes it's not an issue)", EMsgType.WARNING);
else
logPrinter.print("Release interface", EMsgType.PASS);

View file

@ -2,8 +2,8 @@ package nsusbloader.COM.USB;
import org.usb4java.LibUsb;
class UsbErrorCodes {
static String getErrCode(int value){
public class UsbErrorCodes {
public static String getErrCode(int value){
switch (value){
case LibUsb.ERROR_ACCESS:
return "ERROR_ACCESS";

View file

@ -7,7 +7,6 @@ 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;
import javafx.stage.FileChooser;
@ -25,8 +24,6 @@ import java.util.List;
import java.util.ResourceBundle;
public class FrontController implements Initializable {
@FXML
private Pane specialPane;
@FXML
private AnchorPane usbNetPane;
@ -52,7 +49,6 @@ public class FrontController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
specialPane.getStyleClass().add("special-pane-as-border"); // UI hacks
ObservableList<String> choiceProtocolList = FXCollections.observableArrayList("TinFoil", "GoldLeaf");
choiceProtocol.setItems(choiceProtocolList);
@ -195,7 +191,7 @@ public class FrontController implements Initializable {
else
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NSP ROM", "*.nsp"));
filesList = fileChooser.showOpenMultipleDialog(specialPane.getScene().getWindow());
filesList = fileChooser.showOpenMultipleDialog(usbNetPane.getScene().getWindow());
if (filesList != null && !filesList.isEmpty()) {
tableFilesListController.setFiles(filesList);
uploadStopBtn.setDisable(false);
@ -216,7 +212,7 @@ public class FrontController implements Initializable {
else
dirChooser.setInitialDirectory(new File(System.getProperty("user.home")));
splitFile = dirChooser.showDialog(specialPane.getScene().getWindow());
splitFile = dirChooser.showDialog(usbNetPane.getScene().getWindow());
if (splitFile != null && splitFile.getName().toLowerCase().endsWith(".nsp")) {
tableFilesListController.setFile(splitFile);

View file

@ -31,6 +31,8 @@ public class NSLMainController implements Initializable {
private SettingsController SettingsTabController;
@FXML
private SplitMergeController SplitMergeTabController;
@FXML
private RcmController RcmTabController;
@Override
public void initialize(URL url, ResourceBundle rb) {
@ -123,6 +125,8 @@ public class NSLMainController implements Initializable {
public SplitMergeController getSmCtrlr(){
return SplitMergeTabController;
}
public RcmController getRcmCtrlr(){ return RcmTabController; }
/**
* Save preferences before exit
* */
@ -147,5 +151,6 @@ public class NSLMainController implements Initializable {
);
SplitMergeTabController.updatePreferencesOnExit(); // NOTE: This shit above should be re-written to similar pattern
RcmTabController.updatePreferencesOnExit();
}
}

View file

@ -0,0 +1,257 @@
package nsusbloader.Controllers;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import nsusbloader.AppPreferences;
import nsusbloader.MediatorControl;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.ServiceWindow;
import nsusbloader.Utilities.RcmTask;
import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
public class RcmController implements Initializable {
@FXML
private ToggleGroup rcmToggleGrp;
@FXML
private VBox rcmToolPane;
@FXML
private RadioButton pldrRadio1,
pldrRadio2,
pldrRadio3,
pldrRadio4,
pldrRadio5;
@FXML
private Button injectPldBtn;
@FXML
private Label payloadFNameLbl1, payloadFPathLbl1,
payloadFNameLbl2, payloadFPathLbl2,
payloadFNameLbl3, payloadFPathLbl3,
payloadFNameLbl4, payloadFPathLbl4,
payloadFNameLbl5, payloadFPathLbl5;
@FXML
private Label statusLbl;
private ResourceBundle rb;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
this.rb = resourceBundle;
rcmToggleGrp.selectToggle(pldrRadio1);
pldrRadio1.setOnAction(e -> statusLbl.setText(""));
pldrRadio2.setOnAction(e -> statusLbl.setText(""));
pldrRadio3.setOnAction(e -> statusLbl.setText(""));
pldrRadio4.setOnAction(e -> statusLbl.setText(""));
pldrRadio5.setOnAction(e -> statusLbl.setText(""));
String recentRcm1 = AppPreferences.getInstance().getRecentRcm(1);
String recentRcm2 = AppPreferences.getInstance().getRecentRcm(2);
String recentRcm3 = AppPreferences.getInstance().getRecentRcm(3);
String recentRcm4 = AppPreferences.getInstance().getRecentRcm(4);
String recentRcm5 = AppPreferences.getInstance().getRecentRcm(5);
String myRegexp;
if (File.separator.equals("/"))
myRegexp = "^.+/";
else
myRegexp = "^.+\\\\";
if (! recentRcm1.isEmpty()) {
payloadFNameLbl1.setText(recentRcm1.replaceAll(myRegexp, ""));
payloadFPathLbl1.setText(recentRcm1);
}
if (! recentRcm2.isEmpty()) {
payloadFNameLbl2.setText(recentRcm2.replaceAll(myRegexp, ""));
payloadFPathLbl2.setText(recentRcm2);
}
if (! recentRcm3.isEmpty()) {
payloadFNameLbl3.setText(recentRcm3.replaceAll(myRegexp, ""));
payloadFPathLbl3.setText(recentRcm3);
}
if (! recentRcm4.isEmpty()) {
payloadFNameLbl4.setText(recentRcm4.replaceAll(myRegexp, ""));
payloadFPathLbl4.setText(recentRcm4);
}
if (! recentRcm5.isEmpty()) {
payloadFNameLbl5.setText(recentRcm5.replaceAll(myRegexp, ""));
payloadFPathLbl5.setText(recentRcm5);
}
injectPldBtn.setDisable(false); // TODO: write logic ?? Like in case PAYLOADER exist, button active. If not: not active?
injectPldBtn.setOnAction(actionEvent -> smash());
}
private void smash(){
statusLbl.setText("");
if (MediatorControl.getInstance().getTransferActive()) {
ServiceWindow.getErrorNotification(rb.getString("windowTitleError"), rb.getString("windowBodyPleaseFinishTransfersFirst"));
return;
}
Task<Boolean> RcmTask;
RadioButton selectedRadio = (RadioButton)rcmToggleGrp.getSelectedToggle();
switch (selectedRadio.getId()){
case "pldrRadio1":
RcmTask = new RcmTask(payloadFPathLbl1.getText());
break;
case "pldrRadio2":
RcmTask = new RcmTask(payloadFPathLbl2.getText());
break;
case "pldrRadio3":
RcmTask = new RcmTask(payloadFPathLbl3.getText());
break;
case "pldrRadio4":
RcmTask = new RcmTask(payloadFPathLbl4.getText());
break;
case "pldrRadio5":
RcmTask = new RcmTask(payloadFPathLbl5.getText());
break;
default:
return;
}
RcmTask.setOnSucceeded(event -> {
if (RcmTask.getValue())
statusLbl.setText(rb.getString("done_txt"));
else
statusLbl.setText(rb.getString("failure_txt"));
});
Thread RcmThread = new Thread(RcmTask);
RcmThread.setDaemon(true);
RcmThread.start();
}
@FXML
private void bntSelectPayloader(ActionEvent event){
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(rb.getString("btn_Select"));
File validator = new File(payloadFPathLbl1.getText()).getParentFile();
if (validator != null && validator.exists())
fileChooser.setInitialDirectory(validator);
else
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("bin", "*.bin"));
File payloadFile = fileChooser.showOpenDialog(payloadFPathLbl1.getScene().getWindow());
if (payloadFile != null) {
final Node btn = (Node)event.getSource();
switch (btn.getId()){
case "selPldBtn1":
payloadFNameLbl1.setText(payloadFile.getName());
payloadFPathLbl1.setText(payloadFile.getAbsolutePath());
rcmToggleGrp.selectToggle(pldrRadio1);
break;
case "selPldBtn2":
payloadFNameLbl2.setText(payloadFile.getName());
payloadFPathLbl2.setText(payloadFile.getAbsolutePath());
rcmToggleGrp.selectToggle(pldrRadio2);
break;
case "selPldBtn3":
payloadFNameLbl3.setText(payloadFile.getName());
payloadFPathLbl3.setText(payloadFile.getAbsolutePath());
rcmToggleGrp.selectToggle(pldrRadio3);
break;
case "selPldBtn4":
payloadFNameLbl4.setText(payloadFile.getName());
payloadFPathLbl4.setText(payloadFile.getAbsolutePath());
rcmToggleGrp.selectToggle(pldrRadio4);
break;
case "selPldBtn5":
payloadFNameLbl5.setText(payloadFile.getName());
payloadFPathLbl5.setText(payloadFile.getAbsolutePath());
rcmToggleGrp.selectToggle(pldrRadio5);
}
}
}
@FXML
private void bntResetPayloader(ActionEvent event){
final Node btn = (Node)event.getSource();
switch (btn.getId()){
case "resPldBtn1":
payloadFNameLbl1.setText("");
payloadFPathLbl1.setText("");
statusLbl.setText("");
break;
case "resPldBtn2":
payloadFNameLbl2.setText("");
payloadFPathLbl2.setText("");
statusLbl.setText("");
break;
case "resPldBtn3":
payloadFNameLbl3.setText("");
payloadFPathLbl3.setText("");
statusLbl.setText("");
break;
case "resPldBtn4":
payloadFNameLbl4.setText("");
payloadFPathLbl4.setText("");
statusLbl.setText("");
break;
case "resPldBtn5":
payloadFNameLbl5.setText("");
payloadFPathLbl5.setText("");
statusLbl.setText("");
}
}
@FXML
public void selectPldrPane(MouseEvent mouseEvent) {
final Node selectedPane = (Node)mouseEvent.getSource();
switch (selectedPane.getId()){
case "pldPane1":
pldrRadio1.fire();
break;
case "pldPane2":
pldrRadio2.fire();
break;
case "pldPane3":
pldrRadio3.fire();
break;
case "pldPane4":
pldrRadio4.fire();
break;
case "pldPane5":
pldrRadio5.fire();
break;
}
}
public void notifySmThreadStarted(boolean isStart, EModule type){
rcmToolPane.setDisable(isStart);
if (type.equals(EModule.RCM) && isStart){
MediatorControl.getInstance().getContoller().logArea.clear();
}
}
/**
* Save application settings on exit
* */
public void updatePreferencesOnExit(){
AppPreferences.getInstance().setRecentRcm(1, payloadFPathLbl1.getText());
AppPreferences.getInstance().setRecentRcm(2, payloadFPathLbl2.getText());
AppPreferences.getInstance().setRecentRcm(3, payloadFPathLbl3.getText());
AppPreferences.getInstance().setRecentRcm(4, payloadFPathLbl4.getText());
AppPreferences.getInstance().setRecentRcm(5, payloadFPathLbl5.getText());
}
}

View file

@ -88,10 +88,15 @@ public class SplitMergeController implements Initializable {
if (splitRad.isSelected()) {
FileChooser fc = new FileChooser();
fc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFile"));
if (fileFolderActualPathLbl.getText().isEmpty())
fc.setInitialDirectory(new File(System.getProperty("user.home")));
if (! fileFolderActualPathLbl.getText().isEmpty()){
File temporaryFile = new File(fileFolderActualPathLbl.getText()).getParentFile();
if (temporaryFile != null && temporaryFile.exists())
fc.setInitialDirectory(temporaryFile);
else
fc.setInitialDirectory(new File(fileFolderActualPathLbl.getText()).getParentFile());
fc.setInitialDirectory(new File(System.getProperty("user.home")));
}
else
fc.setInitialDirectory(new File(System.getProperty("user.home")));
File fileFile = fc.showOpenDialog(changeSaveToBtn.getScene().getWindow());
if (fileFile == null)
return;
@ -101,10 +106,16 @@ public class SplitMergeController implements Initializable {
else{
DirectoryChooser dc = new DirectoryChooser();
dc.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFolder"));
if (fileFolderActualPathLbl.getText().isEmpty())
dc.setInitialDirectory(new File(System.getProperty("user.home")));
if (! fileFolderActualPathLbl.getText().isEmpty()){
File temporaryFile = new File(fileFolderActualPathLbl.getText());
if (temporaryFile.exists())
dc.setInitialDirectory(temporaryFile);
else
dc.setInitialDirectory(new File(fileFolderActualPathLbl.getText()));
dc.setInitialDirectory(new File(System.getProperty("user.home")));
}
else
dc.setInitialDirectory(new File(System.getProperty("user.home")));
File folderFile = dc.showDialog(changeSaveToBtn.getScene().getWindow());
if (folderFile == null)
return;
@ -132,6 +143,8 @@ public class SplitMergeController implements Initializable {
convertBtn.setText(resourceBundle.getString("btn_Stop"));
convertRegion.getStyleClass().clear();
convertRegion.getStyleClass().add("regionStop");
convertBtn.getStyleClass().remove("buttonUp");
convertBtn.getStyleClass().add("buttonStop");
return;
}
splitRad.setDisable(false);
@ -142,6 +155,8 @@ public class SplitMergeController implements Initializable {
convertBtn.setOnAction(e -> setConvertBtnAction());
convertBtn.setText(resourceBundle.getString("tabSplMrg_Btn_Convert"));
convertRegion.getStyleClass().clear();
convertBtn.getStyleClass().remove("buttonStop");
convertBtn.getStyleClass().add("buttonUp");
if (splitRad.isSelected())
convertRegion.getStyleClass().add("regionSplitToOne");
else
@ -159,6 +174,7 @@ public class SplitMergeController implements Initializable {
* It's button listener when convert-process NOT in progress
* */
private void setConvertBtnAction(){
statusLbl.setText("");
if (MediatorControl.getInstance().getTransferActive()) {
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"), resourceBundle.getString("windowBodyPleaseFinishTransfersFirst"));
return;

View file

@ -25,6 +25,7 @@ public class MediatorControl {
isTransferActive.set(isActive);
mainCtrler.getFrontCtrlr().notifyTransmThreadStarted(isActive, appModuleType);
mainCtrler.getSmCtrlr().notifySmThreadStarted(isActive, appModuleType);
mainCtrler.getRcmCtrlr().notifySmThreadStarted(isActive, appModuleType);
}
public synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
}

View file

@ -13,7 +13,7 @@ import java.util.ResourceBundle;
public class NSLMain extends Application {
public static final String appVersion = "v1.1";
public static final String appVersion = "v2.0";
@Override
public void start(Stage primaryStage) throws Exception{

View file

@ -0,0 +1,105 @@
package nsusbloader.Utilities;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
public class JNIRcmLoader {
private JNIRcmLoader(){}
public static boolean load(){
String osName = System.getProperty("os.name").toLowerCase().replace(" ", "");
String osArch = System.getProperty("os.arch").toLowerCase().replace(" ", "");
String libPostfix;
if (osName.equals("linux")){
switch (osArch){
case "i386":
case "i586":
case "i686":
osArch = "x86";
break;
case "x86_64":
case "amd64":
osArch = "amd64";
break;
default:
return false;
}
libPostfix = "so";
}
else if (osName.contains("windows")){
osName = "windows";
libPostfix = "dll";
switch (osArch){
case "x86":
case "i386":
case "i586":
case "i686":
osArch = "x86";
break;
case "x86_64":
case "amd64":
osArch = "amd64";
break;
default:
return false;
}
}
else
return false;
final URL url_ = RcmSmash.class.getResource("/native/"+osName+"/"+osArch+"/smashlib."+libPostfix);
if (url_ == null)
return false;
String proto = url_.getProtocol();
File libraryFile;
if (proto.equals("file")){
// We can pick file from disk as is.
try {
libraryFile = new File(url_.toURI());
}
catch (URISyntaxException e){
e.printStackTrace();
return false;
}
}
else if (proto.equals("jar")){
// We have to export file to temp dir.
InputStream inStream = RcmSmash.class.getResourceAsStream("/native/"+osName+"/"+osArch+"/smashlib."+libPostfix);
if (inStream == null)
return false;
// Create temp folder
try{
File tmpDirFile = File.createTempFile("jni", null);
if (! tmpDirFile.delete())
return false;
if (! tmpDirFile.mkdirs())
return false;
libraryFile = new File(tmpDirFile, "smashlib."+libPostfix);
byte[] ioBuffer = new byte[8192];
FileOutputStream foStream = new FileOutputStream(libraryFile);
while (inStream.read(ioBuffer) != -1)
foStream.write(ioBuffer);
foStream.close();
inStream.close();
libraryFile.deleteOnExit();
tmpDirFile.deleteOnExit();
}
catch (IOException ioe){
ioe.printStackTrace();
return false;
}
}
else
return false;
//System.out.println("LIB LOCATION: "+libraryFile);
System.load(libraryFile.getAbsolutePath());
//System.out.println("LIB LOADED");
return true;
}
}

View file

@ -0,0 +1,17 @@
package nsusbloader.Utilities;
public class RcmSmash {
private static final boolean supported;
static {
supported = JNIRcmLoader.load();
}
private RcmSmash(){}
public static native int smashLinux(final int bus_id, final int device_addr);
public static native int smashWindows();
public static boolean isSupported() { return supported; }
}

View file

@ -0,0 +1,332 @@
package nsusbloader.Utilities;
/*
* Implementation of the 'Fusée Gelée' RCM payload that is inspired by 'fusee-launcher' application by ktemkin.
* Definitely uses ideas and even some code.
* Check original project: https://github.com/reswitched/fusee-launcher
*
* This code is not political. It could be used by anyone.
* Find details in LICENSE file in the root directory of this project.
**/
import javafx.concurrent.Task;
import nsusbloader.COM.USB.UsbConnect;
import nsusbloader.COM.USB.UsbErrorCodes;
import nsusbloader.ModelControllers.LogPrinter;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import org.usb4java.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
public class RcmTask extends Task<Boolean> {
private enum ECurrentOS {
win, lin, mac, unsupported
}
private LogPrinter logPrinter;
private String filePath;
private DeviceHandle handler;
private byte[] fullPayload;
private static final byte[] initSeq = { (byte) 0x98, (byte) 0x02, (byte) 0x03 };
private static final byte[] mezzo = {
(byte) 0x5c, (byte) 0x00, (byte) 0x9f, (byte) 0xe5, (byte) 0x5c, (byte) 0x10, (byte) 0x9f, (byte) 0xe5, (byte) 0x5c, (byte) 0x20, (byte) 0x9f, (byte) 0xe5, (byte) 0x01, (byte) 0x20, (byte) 0x42, (byte) 0xe0,
(byte) 0x0e, (byte) 0x00, (byte) 0x00, (byte) 0xeb, (byte) 0x48, (byte) 0x00, (byte) 0x9f, (byte) 0xe5, (byte) 0x10, (byte) 0xff, (byte) 0x2f, (byte) 0xe1, (byte) 0x00, (byte) 0x00, (byte) 0xa0, (byte) 0xe1,
(byte) 0x48, (byte) 0x00, (byte) 0x9f, (byte) 0xe5, (byte) 0x48, (byte) 0x10, (byte) 0x9f, (byte) 0xe5, (byte) 0x01, (byte) 0x29, (byte) 0xa0, (byte) 0xe3, (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0xeb,
(byte) 0x38, (byte) 0x00, (byte) 0x9f, (byte) 0xe5, (byte) 0x01, (byte) 0x19, (byte) 0xa0, (byte) 0xe3, (byte) 0x01, (byte) 0x00, (byte) 0x80, (byte) 0xe0, (byte) 0x34, (byte) 0x10, (byte) 0x9f, (byte) 0xe5,
(byte) 0x03, (byte) 0x28, (byte) 0xa0, (byte) 0xe3, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xeb, (byte) 0x20, (byte) 0x00, (byte) 0x9f, (byte) 0xe5, (byte) 0x10, (byte) 0xff, (byte) 0x2f, (byte) 0xe1,
(byte) 0x04, (byte) 0x30, (byte) 0x91, (byte) 0xe4, (byte) 0x04, (byte) 0x30, (byte) 0x80, (byte) 0xe4, (byte) 0x04, (byte) 0x20, (byte) 0x52, (byte) 0xe2, (byte) 0xfb, (byte) 0xff, (byte) 0xff, (byte) 0x1a,
(byte) 0x1e, (byte) 0xff, (byte) 0x2f, (byte) 0xe1, (byte) 0x00, (byte) 0xf0, (byte) 0x00, (byte) 0x40, (byte) 0x20, (byte) 0x00, (byte) 0x01, (byte) 0x40, (byte) 0x7c, (byte) 0x00, (byte) 0x01, (byte) 0x40,
(byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x40, (byte) 0x40, (byte) 0x0e, (byte) 0x01, (byte) 0x40, (byte) 0x00, (byte) 0x70, (byte) 0x01, (byte) 0x40
}; // 124 bytes
private static final byte[] sprayPttrn = { 0x00, 0x00, 0x01, 0x40};
public RcmTask(String filePath){
this.logPrinter = new LogPrinter(EModule.RCM);
this.filePath = filePath;
}
@Override
protected Boolean call() {
logPrinter.print("Selected: "+filePath, EMsgType.INFO);
logPrinter.print("=============== RCM ===============", EMsgType.INFO);
ECurrentOS ecurrentOS;
String realOsName = System.getProperty("os.name").toLowerCase().replace(" ", "");
if (realOsName.equals("macos") || realOsName.equals("macosx") || realOsName.equals("freebsd"))
ecurrentOS = ECurrentOS.mac;
else if (realOsName.contains("windows"))
ecurrentOS = ECurrentOS.win;
else if (realOsName.equals("linux"))
ecurrentOS = ECurrentOS.lin;
else
ecurrentOS = ECurrentOS.unsupported;
logPrinter.print("Found your OS: "+System.getProperty("os.name"), EMsgType.PASS);
if (! ecurrentOS.equals(ECurrentOS.mac)){
if (! RcmSmash.isSupported()){
logPrinter.print("Unfortunately your platform '"+System.getProperty("os.name")+
"' of '"+System.getProperty("os.arch")+"' is not supported :("+
"\n But you could file a bug with request."+
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
logPrinter.close();
return false;
}
}
if (preparePayload()){
logPrinter.close();
return false;
}
// === TEST THIS ===
// writeTestFile();
// =================
// Bring up USB connection
UsbConnect usbConnect = new UsbConnect(logPrinter, true);
if (! usbConnect.isConnected()){
logPrinter.close();
return false;
}
this.handler = usbConnect.getNsHandler();
// Get device ID and show it.
if (readUsbDeviceID()){
usbConnect.close();
logPrinter.close();
return false;
}
// Send payload
for (int i=0; i < fullPayload.length / 4096 ; i++){
if (writeUsb(Arrays.copyOfRange(fullPayload, i*4096, (i+1)*4096))){
logPrinter.print("Failed to sent payload ["+i+"]"+
"\n\n Execution stopped.", EMsgType.FAIL);
usbConnect.close();
logPrinter.close();
return false;
}
}
logPrinter.print("Information sent to NS.", EMsgType.PASS);
if (ecurrentOS.equals(ECurrentOS.mac)){
if (smashMacOS()){
usbConnect.close();
logPrinter.close();
return false;
}
}
else {
// JNI MAGIC HERE
int retval;
if (ecurrentOS.equals(ECurrentOS.lin))
retval = RcmSmash.smashLinux(usbConnect.getNsBus(), usbConnect.getNsAddress());
else if (ecurrentOS.equals(ECurrentOS.win))
retval = RcmSmash.smashWindows();
else {
// ( ?_?)
logPrinter.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);
usbConnect.close();
logPrinter.close();
return false;
}
if (retval != 0){
logPrinter.print("Failed to smash the stack ("+retval+")"+
"\n\n Execution stopped and failed.", EMsgType.FAIL);
usbConnect.close();
logPrinter.close();
return false;
}
logPrinter.print(".:: Payload complete ::.", EMsgType.PASS);
}
usbConnect.close();
logPrinter.close();
return true;
}
/**
* Prepare the 'big' or full-size byte-buffer that is actually is a payload that we're about to use.
* @return false for issues
* true for good result
* */
private boolean preparePayload(){
File pldrFile = new File(filePath);
// 126296 b <- biggest size per CTCaer; 16384 selected randomly as minimum threshold. It's probably wrong.
if (pldrFile.length() > 126296 || pldrFile.length() < 16384) {
logPrinter.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 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);
return true;
}
// Get payload file size
int pldFileSize = (int) pldrFile.length();
// Get full payload array size
int totalSize = 4328 + pldFileSize + 8640;
totalSize += 4096 - (totalSize % 4096);
if ((totalSize / 4096 % 2) == 0) // Flip buffer story to get 0x40009000 (hi) buf to always smash with 0x7000 (dec: 28672)
totalSize += 4096;
// Double-check
if (totalSize > 0x30298){
logPrinter.print("File size of the payload is too bit. Comparing to maximum size, it's greater to "+(totalSize - 0x30298)+" bytes!"+
"\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\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL); // Occurs: never. I'm too lazy to check.
return true;
}
// Define holder of 'everything payload'
fullPayload = new byte[totalSize];
// Prepare array to store file payload.
byte[] dataPldFile = new byte[pldFileSize];
try{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pldrFile));
int readSize;
if ((readSize = bis.read(dataPldFile)) != pldFileSize){
logPrinter.print("Failed to retrieve data from payload file." +
"\n Got only "+readSize+" bytes while "+pldFileSize+" expected." +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
bis.close();
return true;
}
bis.close();
}
catch (Exception e){
logPrinter.print("Failed to retrieve data from payload file: " +e.getMessage()+
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
return true;
}
// Trust me
System.arraycopy(initSeq, 0, fullPayload, 0, 3);
System.arraycopy(mezzo, 0, fullPayload, 680, 124);
System.arraycopy(dataPldFile, 0, fullPayload, 4328, 16384);
for (int i = 0; i < 2160; i++)
System.arraycopy(sprayPttrn, 0, fullPayload, 20712+i*4, 4);
System.arraycopy(dataPldFile, 16384, fullPayload, 29352, pldFileSize-16384);
return false;
}
/**
* Read device ID in the early beginning
* @return false if NO issues
* true if issues
* */
private boolean readUsbDeviceID(){
ByteBuffer readBuffer = ByteBuffer.allocateDirect(16);
IntBuffer readBufTransferred = IntBuffer.allocate(1);
int result = LibUsb.bulkTransfer(handler, (byte) 0x81, readBuffer, readBufTransferred, 1000);
if (result != LibUsb.SUCCESS) {
logPrinter.print("Unable to get device ID" +
"\n\n Nothing has been sent to NS. Execution stopped.", EMsgType.FAIL);
return true;
}
int trans = readBufTransferred.get();
byte[] receivedBytes = new byte[trans];
readBuffer.get(receivedBytes);
StringBuilder idStrBld = new StringBuilder("Found device with ID: ");
for (byte b: receivedBytes)
idStrBld.append(String.format("%02x ", b));
logPrinter.print(idStrBld.toString(), EMsgType.PASS);
return false;
}
/**
* Sending byte array to USB device
* @return 'false' if no issues
* 'true' if errors happened
* */
private boolean writeUsb(byte[] message){
ByteBuffer writeBuffer = ByteBuffer.allocateDirect(4096);
writeBuffer.put(message);
IntBuffer writeBufTransferred = IntBuffer.allocate(1);
int result = LibUsb.bulkTransfer(handler, (byte) 0x01, writeBuffer, writeBufTransferred, 5050);
if (result == LibUsb.SUCCESS) {
if (writeBufTransferred.get() == 4096)
return false;
logPrinter.print("RCM Data transfer issue [write]" +
"\n Requested: " + message.length +
"\n Transferred: " + writeBufTransferred.get()+
"\n\n Execution stopped.", EMsgType.FAIL);
return true;
}
logPrinter.print("RCM Data transfer issue [write]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result) +
"\n\n Execution stopped.", EMsgType.FAIL);
return true;
}
/**
* MacOS version of RcmSmash class
* */
boolean smashMacOS(){
// Release interface
int result = LibUsb.releaseInterface(handler, 1);
if (result != LibUsb.SUCCESS) {
logPrinter.print("Release interface failed" +
"\n Returned: " + result, EMsgType.FAIL);
return true;
}
logPrinter.print("Release interface 1.", EMsgType.PASS);
// Claim interface
result = LibUsb.claimInterface(handler, 0);
if (result != LibUsb.SUCCESS) {
logPrinter.print("Claim interface 0." +
"\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
return true;
}
logPrinter.print("Claim interface", EMsgType.PASS);
ByteBuffer writeBuffer = ByteBuffer.allocateDirect(28672); //writeBuffer.order() equals BIG_ENDIAN; 28672
result = LibUsb.controlTransfer(handler, (byte) 0x82, LibUsb.REQUEST_GET_STATUS, (short) 0, (short) 0, writeBuffer, 1000);
if (result < 0){
logPrinter.print("Failed to smash the stack ("+UsbErrorCodes.getErrCode(result)+")"+
"\n\n Execution stopped and failed.", EMsgType.FAIL);
return true;
}
logPrinter.print("Payload complete!", EMsgType.PASS);
return false;
}
//*****************************************************************************************************************/
/*
private void writeTestFile(){
try {
File testFile = new File("/tmp/dmTests.bin");
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(testFile)
);
bos.write(fullPayload);
bos.close();
}
catch (Exception e){ e.printStackTrace(); }
// ------------------ TEST THIS p.2 ----------------------
writeUsbTest(fullPayload);
}
private boolean writeUsbTest(byte[] message){
for (int i=0; i < message.length / 0x1000 ;i++){
try {
File testFile = new File(String.format("/tmp/cnk_%02d.bin", i));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(testFile)
);
bos.write(Arrays.copyOfRange(message, i*4096, (i+1)*4096));
bos.close();
}
catch (Exception e){ e.printStackTrace(); }
}
return false;
}
*/
}

View file

@ -4,6 +4,7 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.AnchorPane?>
@ -39,7 +40,7 @@
<RowConstraints vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Pane fx:id="specialPane" GridPane.columnIndex="1" />
<Separator prefWidth="200.0" styleClass="strangeSeparator" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets bottom="2.0" />

View file

@ -22,6 +22,14 @@
<graphic>
<SVGPath content="M21,19V17H8V19H21M21,13V11H8V13H21M8,7H21V5H8V7M4,5V7H6V5H4M3,5A1,1 0 0,1 4,4H6A1,1 0 0,1 7,5V7A1,1 0 0,1 6,8H4A1,1 0 0,1 3,7V5M4,11V13H6V11H4M3,11A1,1 0 0,1 4,10H6A1,1 0 0,1 7,11V13A1,1 0 0,1 6,14H4A1,1 0 0,1 3,13V11M4,17V19H6V17H4M3,17A1,1 0 0,1 4,16H6A1,1 0 0,1 7,17V19A1,1 0 0,1 6,20H4A1,1 0 0,1 3,19V17Z" />
</graphic>
</Tab>
<Tab closable="false">
<content>
<fx:include fx:id="RcmTab" source="RcmTab.fxml" VBox.vgrow="ALWAYS" />
</content>
<graphic>
<SVGPath content="M 5.2753906 0.9453125 C 3.4702091 0.94491305 2.0128532 1.7453477 1.0566406 2.9082031 C 0.10042811 4.0710585 -0.40065633 5.5585011 -0.55664062 7.0488281 C -0.71262492 8.5391552 -0.52822452 10.042928 0.0078125 11.292969 C 0.54008474 12.534229 1.4899019 13.5834 2.8300781 13.826172 L 2.828125 13.837891 L 4.2050781 13.837891 L 4.6484375 11.080078 L 5.3496094 11.080078 L 5.9257812 13.837891 L 7.4042969 13.837891 L 7.4042969 13.753906 L 6.703125 10.685547 C 7.49408 10.281262 7.9297095 9.5624699 8.0097656 8.5292969 C 8.0610016 7.8485775 7.9209243 7.3118876 7.5878906 6.9179688 C 7.254857 6.5240499 6.7748288 6.3176076 6.1503906 6.296875 L 4.0371094 6.2910156 L 3.0976562 12.150391 C 2.4734416 12.023142 1.945837 11.518943 1.5625 10.625 C 1.1696133 9.7087867 0.99863233 8.4506302 1.1269531 7.2246094 C 1.2552739 5.9985885 1.6798073 4.8135983 2.3632812 3.9824219 C 3.0467553 3.1512454 3.9413986 2.6383771 5.2734375 2.6386719 L 20.007812 2.640625 C 20.496454 2.6407331 20.818797 2.788345 21.136719 3.0976562 C 21.454641 3.4069676 21.743658 3.910529 21.949219 4.5761719 C 22.36034 5.9074576 22.421621 7.8407685 22.128906 9.7714844 C 21.836191 11.7022 21.195943 13.639966 20.339844 15.023438 C 19.483744 16.406908 18.498727 17.154297 17.46875 17.154297 L -0.59375 17.154297 L -0.59375 18.845703 L 17.46875 18.845703 C 19.298148 18.845703 20.755291 17.568872 21.779297 15.914062 C 22.803302 14.259253 23.481257 12.145818 23.802734 10.025391 C 24.124212 7.904966 24.093647 5.7854271 23.566406 4.078125 C 23.302786 3.2244739 22.911503 2.4618437 22.318359 1.8847656 C 21.725216 1.3076876 20.907952 0.94941793 20.007812 0.94921875 L 5.2753906 0.9453125 z M 11.574219 6.1875 C 10.831297 6.1702229 10.207831 6.4450285 9.7050781 7.0117188 C 9.2055276 7.578409 8.8809744 8.3951633 8.7304688 9.4628906 L 8.5527344 10.712891 C 8.5207119 10.975503 8.5072674 11.234984 8.5136719 11.494141 C 8.5328854 12.254335 8.7132962 12.848871 9.0527344 13.277344 C 9.3921725 13.705817 9.8729047 13.927585 10.494141 13.941406 C 11.217848 13.962139 11.814426 13.735112 12.285156 13.261719 C 12.759089 12.78487 13.038539 12.137296 13.125 11.318359 L 11.775391 11.328125 C 11.698537 11.846439 11.565182 12.208239 11.373047 12.412109 C 11.180912 12.612524 10.923036 12.704777 10.599609 12.6875 C 10.080845 12.663312 9.8371182 12.277623 9.8691406 11.53125 C 9.8723429 11.403399 9.8965748 11.131448 9.9414062 10.716797 L 10.113281 9.4160156 C 10.190135 8.7145637 10.339592 8.209426 10.560547 7.8984375 C 10.781502 7.5839935 11.081823 7.4334439 11.462891 7.4472656 C 11.956037 7.4645428 12.209143 7.763238 12.21875 8.34375 L 12.208984 8.8574219 L 13.595703 8.8613281 C 13.595703 7.9974711 13.421311 7.3393799 13.072266 6.8867188 C 12.723221 6.4306022 12.224275 6.1978663 11.574219 6.1875 z M 14.869141 6.2910156 L 13.658203 13.837891 L 15.037109 13.837891 L 15.353516 11.847656 L 15.753906 8.5976562 L 16.28125 13.837891 L 17.21875 13.837891 L 19.361328 8.7675781 L 18.755859 11.748047 L 18.419922 13.837891 L 19.802734 13.837891 L 21.017578 6.2910156 L 19.201172 6.2910156 L 17.054688 11.716797 L 16.646484 6.2910156 L 14.869141 6.2910156 z M 5.2148438 7.5605469 L 6.09375 7.5664062 C 6.4491994 7.5940497 6.6336754 7.8344483 6.6464844 8.2871094 C 6.6496866 8.7466813 6.5554161 9.1146416 6.3632812 9.3945312 C 6.1711464 9.6709655 5.9072524 9.8134016 5.5742188 9.8203125 L 4.8496094 9.8105469 L 5.2148438 7.5605469 z" />
</graphic>
</Tab>
<Tab closable="false">
<content>

View file

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?>
<ScrollPane fitToWidth="true" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.RcmController">
<VBox fx:id="rcmToolPane" spacing="15.0">
<Pane minHeight="-Infinity" prefHeight="10.0" style="-fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #ff1515 40%, transparent 45%);" />
<HBox alignment="CENTER">
<children>
<Label text="Fusée Gelée RCM">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
</children>
</HBox>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" percentWidth="90.0" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Separator prefWidth="200.0" styleClass="strangeSeparator" GridPane.columnIndex="1" />
</children>
</GridPane>
<VBox spacing="8.0">
<children>
<Label text="Payload: " />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="pldrRadio1" mnemonicParsing="false">
<toggleGroup>
<ToggleGroup fx:id="rcmToggleGrp" />
</toggleGroup></RadioButton>
<VBox fx:id="pldPane1" onMouseClicked="#selectPldrPane" HBox.hgrow="ALWAYS">
<children>
<HBox>
<children>
<Label fx:id="payloadFNameLbl1" />
</children>
</HBox>
<Label fx:id="payloadFPathLbl1" disable="true">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Button fx:id="selPldBtn1" mnemonicParsing="false" onAction="#bntSelectPayloader" styleClass="buttonSelect">
<graphic>
<SVGPath content="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" fill="#289de8" />
</graphic></Button>
<Button fx:id="resPldBtn1" mnemonicParsing="false" onAction="#bntResetPayloader" styleClass="buttonStop">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#fb582c" />
</graphic>
</Button>
</children>
</HBox>
<Separator prefWidth="200.0" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="pldrRadio2" mnemonicParsing="false" toggleGroup="$rcmToggleGrp" />
<VBox fx:id="pldPane2" onMouseClicked="#selectPldrPane" HBox.hgrow="ALWAYS">
<children>
<HBox>
<children>
<Label fx:id="payloadFNameLbl2" />
</children>
</HBox>
<Label fx:id="payloadFPathLbl2" disable="true">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Button fx:id="selPldBtn2" mnemonicParsing="false" onAction="#bntSelectPayloader" styleClass="buttonSelect">
<graphic>
<SVGPath content="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" fill="#289de8" />
</graphic></Button>
<Button fx:id="resPldBtn2" mnemonicParsing="false" onAction="#bntResetPayloader" styleClass="buttonStop">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#fb582c" />
</graphic>
</Button>
</children>
</HBox>
<Separator prefWidth="200.0" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="pldrRadio3" mnemonicParsing="false" toggleGroup="$rcmToggleGrp" />
<VBox fx:id="pldPane3" onMouseClicked="#selectPldrPane" HBox.hgrow="ALWAYS">
<children>
<HBox>
<children>
<Label fx:id="payloadFNameLbl3" />
</children>
</HBox>
<Label fx:id="payloadFPathLbl3" disable="true">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Button fx:id="selPldBtn3" mnemonicParsing="false" onAction="#bntSelectPayloader" styleClass="buttonSelect">
<graphic>
<SVGPath content="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" fill="#289de8" />
</graphic></Button>
<Button fx:id="resPldBtn3" mnemonicParsing="false" onAction="#bntResetPayloader" styleClass="buttonStop">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#fb582c" />
</graphic>
</Button>
</children>
</HBox>
<Separator prefWidth="200.0" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="pldrRadio4" mnemonicParsing="false" toggleGroup="$rcmToggleGrp" />
<VBox fx:id="pldPane4" onMouseClicked="#selectPldrPane" HBox.hgrow="ALWAYS">
<children>
<HBox>
<children>
<Label fx:id="payloadFNameLbl4" />
</children>
</HBox>
<Label fx:id="payloadFPathLbl4" disable="true">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Button fx:id="selPldBtn4" mnemonicParsing="false" onAction="#bntSelectPayloader" styleClass="buttonSelect">
<graphic>
<SVGPath content="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" fill="#289de8" />
</graphic></Button>
<Button fx:id="resPldBtn4" mnemonicParsing="false" onAction="#bntResetPayloader" styleClass="buttonStop">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#fb582c" />
</graphic>
</Button>
</children>
</HBox>
<Separator prefWidth="200.0" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="pldrRadio5" mnemonicParsing="false" toggleGroup="$rcmToggleGrp" />
<VBox fx:id="pldPane5" onMouseClicked="#selectPldrPane" HBox.hgrow="ALWAYS">
<children>
<HBox>
<children>
<Label fx:id="payloadFNameLbl5" />
</children>
</HBox>
<Label fx:id="payloadFPathLbl5" disable="true">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Button fx:id="selPldBtn5" mnemonicParsing="false" onAction="#bntSelectPayloader" styleClass="buttonSelect">
<graphic>
<SVGPath content="M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z" fill="#289de8" />
</graphic></Button>
<Button fx:id="resPldBtn5" mnemonicParsing="false" onAction="#bntResetPayloader" styleClass="buttonStop">
<graphic>
<SVGPath content="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" fill="#fb582c" />
</graphic>
</Button>
</children>
</HBox>
<Separator prefWidth="200.0" />
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</VBox>
<HBox alignment="CENTER">
<children>
<Label fx:id="statusLbl" />
</children>
</HBox>
<Pane VBox.vgrow="ALWAYS" />
<HBox alignment="CENTER">
<children>
<Button fx:id="injectPldBtn" contentDisplay="TOP" disable="true" mnemonicParsing="false" styleClass="buttonUp" text="%btn_InjectPayloader">
<graphic>
<SVGPath content="M 1 1 L 1 13.5 L 21 13.5 L 21 1 L 1 1 z M 26.226562 1.0683594 L 22 5.2949219 L 26.226562 9.5214844 L 27.226562 8.5214844 L 24.697266 6 L 31.158203 6 L 31.158203 20 L 32.566406 20 L 32.566406 4.5917969 L 24.697266 4.5917969 L 27.226562 2.0683594 L 26.226562 1.0683594 z M 2.515625 2.25 L 12.984375 2.25 C 12.993075 2.25 13 2.256995 13 2.265625 L 13 3.984375 C 12.999995 3.993026 12.993031 4 12.984375 4 L 2.515625 4 C 2.5069687 4 2.5 3.993031 2.5 3.984375 L 2.5 2.265625 C 2.5 2.256925 2.50697 2.25 2.515625 2.25 z M 2.515625 5.25 L 17.962891 5.25 C 17.971591 5.25 17.978516 5.256995 17.978516 5.265625 L 17.978516 6.984375 C 17.978516 6.993075 17.971521 7 17.962891 7 L 2.515625 7 C 2.5069687 6.99999 2.5 6.993031 2.5 6.984375 L 2.5 5.265625 C 2.5 5.256925 2.50697 5.25 2.515625 5.25 z M 2.515625 8.25 L 15.421875 8.25 C 15.430575 8.25 15.4375 8.256995 15.4375 8.265625 L 15.4375 9.984375 C 15.4375 9.993075 15.430505 10 15.421875 10 L 2.515625 10 C 2.5069687 9.99999 2.5 9.993031 2.5 9.984375 L 2.5 8.265625 C 2.5 8.256969 2.5069687 8.25 2.515625 8.25 z M 1 14.5 L 1 18 C 1 20 2 21 4 21 L 18 21 C 20 21 21 20 21 18 L 21 14.5 L 1 14.5 z M 5.8515625 16.001953 A 1.8950667 1.8950667 0 0 1 7.7480469 17.898438 A 1.8950667 1.8950667 0 0 1 5.8515625 19.792969 A 1.8950667 1.8950667 0 0 1 3.9570312 17.898438 A 1.8950667 1.8950667 0 0 1 5.8515625 16.001953 z" fill="#71e016" />
</graphic></Button>
</children>
</HBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</VBox>
</ScrollPane>

View file

@ -127,7 +127,7 @@
</VBox>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
<Insets bottom="5.0" left="15.0" right="15.0" top="5.0" />
</padding>
</VBox>
</ScrollPane>

View file

@ -4,22 +4,44 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox fx:id="smToolPane" spacing="25.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SplitMergeController">
<VBox fx:id="smToolPane" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.SplitMergeController">
<VBox spacing="15.0">
<children>
<Pane minHeight="-Infinity" prefHeight="10.0" style="-fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #00c8fc 40%, transparent 45%);" />
<HBox alignment="CENTER">
<children>
<Label text="%tabSplMrg_Lbl_SplitNMergeTitle">
<font>
<Font name="System Bold" size="15.0" />
</font></Label>
</font>
</Label>
</children>
</HBox>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" percentWidth="90.0" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Separator prefWidth="200.0" styleClass="strangeSeparator" GridPane.columnIndex="1" />
</children>
</GridPane>
</children>
</VBox>
<VBox fillWidth="false" spacing="5.0">
<children>
<RadioButton fx:id="splitRad" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_RadioBtn_Split">
@ -29,6 +51,9 @@
</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>
@ -40,6 +65,9 @@
</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>
@ -51,18 +79,28 @@
</HBox>
<Button fx:id="changeSaveToBtn" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_Btn_ChangeSaveToLocation" />
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</VBox>
<HBox alignment="CENTER">
<children>
<Label fx:id="statusLbl" />
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</HBox>
<Pane VBox.vgrow="ALWAYS" />
<VBox>
<children>
<HBox alignment="CENTER">
<children>
<Button fx:id="convertBtn" contentDisplay="TOP" mnemonicParsing="false" text="%tabSplMrg_Btn_Convert" />
<Button fx:id="convertBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabSplMrg_Btn_Convert" />
</children>
</HBox>
</children>
</VBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>

View file

@ -60,3 +60,5 @@ windowTitleError=Error
windowBodyPleaseFinishTransfersFirst=Unable to split/merge files when application USB/Network process active. Please interrupt active transfers first.
done_txt=Done!
failure_txt=Failed
btn_Select=Select
btn_InjectPayloader=Inject payload

View file

@ -60,4 +60,6 @@ windowTitleError=\u041E\u0448\u0438\u0431\u043A\u0430
windowBodyPleaseFinishTransfersFirst=\u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u044C \u0440\u0430\u0437\u0431\u0438\u0432\u043A\u0443 \u0438\u043B\u0438 \u0441\u043B\u0438\u044F\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u0430 \u0432 \u0442\u043E\u0442 \u043C\u043E\u043C\u0435\u043D\u0442, \u043A\u043E\u0433\u0434\u0430 \u0430\u043A\u0442\u0438\u0432\u0435\u043D \u043F\u0440\u043E\u0446\u0435\u0441\u0441 USB \u0438\u043B\u0438 \u0421\u0435\u0442\u0435\u0432\u043E\u0439 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438. \u0421\u043F\u0435\u0440\u0432\u0430 \u043F\u0440\u0435\u0440\u0432\u0438\u0442\u0435 \u0435\u0433\u043E.
done_txt=\u0413\u043E\u0442\u043E\u0432\u043E!
failure_txt=\u041D\u0435\u0443\u0434\u0430\u0447\u0430
btn_Select=\u0412\u044B\u0431\u0440\u0430\u0442\u044C
btn_InjectPayloader=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C payload

View file

@ -60,3 +60,5 @@ windowTitleError=\u041F\u043E\u043C\u0438\u043B\u043A\u0430
windowBodyPleaseFinishTransfersFirst=\u041D\u0435\u043C\u043E\u0436\u043B\u0438\u0432\u043E \u0437\u0434\u0456\u0439\u0441\u043D\u044E\u0432\u0430\u0442\u0438 \u0440\u043E\u0437\u0431\u0438\u0432\u043A\u0443 \u0430\u0431\u043E \u0437'\u0454\u0434\u043D\u0430\u043D\u043D\u044F \u0444\u0430\u0439\u043B\u0443 \u0443 \u0442\u043E\u0439 \u043C\u043E\u043C\u0435\u043D\u0442, \u044F\u043A \u043F\u0440\u043E\u0446\u0435\u0441 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0456 \u0447\u0435\u0440\u0435\u0437 USB \u0447\u0438 \u0442\u043E \u0447\u0435\u0440\u0435\u0437 \u043C\u0435\u0440\u0435\u0436\u0443 \u0449\u0435 \u0430\u043A\u0442\u0438\u0432\u043D\u0438\u0439. \u0421\u043F\u043E\u0447\u0430\u0442\u043A\u0443 \u043F\u0440\u0438\u043F\u0438\u043D\u0456\u0442\u044C \u0439\u043E\u0433\u043E.
done_txt=\u0413\u043E\u0442\u043E\u0432\u043E!
failure_txt=\u041D\u0435\u0432\u0434\u0430\u0447\u0430
btn_Select=\u0412\u0438\u0431\u0440\u0430\u0442\u0438
btn_InjectPayloader=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 payload

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -92,11 +92,6 @@
.tool-bar{
-fx-background-color: transparent;
}
.special-pane-as-border{
-fx-background-color: #f7fafa;
-fx-min-height: 1;
}
// -======================== Choice box =========================-
.choice-box {
-fx-background-color: #4f4f4f;
@ -144,16 +139,16 @@
-fx-fill: #7effff;
}
.tab-pane .tab{
-fx-background-color: #424242;
-fx-background-color: transparent;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-border-radius: 0 0 0 0;
-fx-border-width: 3 0 0 0;
-fx-border-color: #424242;
-fx-border-color: transparent;
}
.tab-pane .tab:selected{
-fx-background-color: #2d2d2d;
-fx-background-color: transparent;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-border-radius: 0 0 0 0;
@ -168,8 +163,7 @@
.tab-pane > .tab-header-area > .tab-header-background
{
-fx-background-color: #424242;
-fx-background-color: linear-gradient(to right, #2d2d2d 0%, #343434 7.5%, #343434 100%); //#424242; //
}
.tab-pane > .tab-header-area > .headers-region > .tab {
-fx-padding: 10;
@ -255,8 +249,18 @@
-fx-background-radius : 0.0em;
-fx-border-radius :2.0em;
}
// -========================== Scroll =====================-
/* -========================= Separator ===================- */
.separator *.line {
-fx-border-style: solid;
-fx-border-width: 0 0 1 0;
-fx-border-color: #3a3738;
}
.strangeSeparator *.line {
-fx-border-style: solid;
-fx-border-width: 0 0 1 0;
-fx-border-color: #f7fafa;
}
/* -========================== Scroll =====================- */
.scroll-bar .increment-arrow,
.scroll-bar .decrement-arrow {
-fx-background-color: #71e016;

View file

@ -109,12 +109,7 @@
.tool-bar{
-fx-background-color: transparent;
}
.special-pane-as-border{
-fx-background-color: #2c2c2c;
-fx-min-height: 1;
}
// -======================== Choice box =========================-
/* -======================== Choice box =========================- */
.choice-box {
-fx-background-color: #fefefe;
-fx-border-color: #fefefe;
@ -150,7 +145,7 @@
-fx-text-fill: #2c2c2c;
}
// -======================== TAB PANE =========================-
/* -======================== TAB PANE =========================- */
.tab-pane .tab SVGPath{
-fx-fill: #2c2c2c;
}
@ -191,7 +186,7 @@
.tab-pane > .tab-header-area > .headers-region > .tab {
-fx-padding: 10;
}
// -=========================== TABLE ======================-
/* -=========================== TABLE ======================- */
.table-view {
-fx-background-color: #fefefe;
-fx-background-image: url(app_logo.png);
@ -240,7 +235,18 @@
-fx-padding: 0.0em; /* 0 */
-fx-table-cell-border-color: #b0b0b0;
}
// -========================== Context menu =====================-
/* -========================= Separator ===================- */
.separator *.line {
-fx-border-style: solid;
-fx-border-width: 0 0 1 0;
-fx-border-color: #a7a7a7;
}
.strangeSeparator *.line {
-fx-border-style: solid;
-fx-border-width: 0 0 1 0;
-fx-border-color: #2c2c2c;
}
/* -========================== Context menu =====================- */
.context-menu {
-fx-background-color: #fefefe;
-fx-cursor: hand;
@ -251,7 +257,7 @@
.context-menu .menu-item:focused .label {
-fx-text-fill: white;
}
// -========================== Text Field =====================-
/* -========================== Text Field =====================- */
.text-field {
-fx-border-color: #289de8;
-fx-border-width: 0 0 1 0;