v0.6 GoldLeaf v0.6.1 support

This commit is contained in:
Dmitry Isaenko 2019-08-14 05:37:58 +03:00
parent d34d522f46
commit cd73968306
20 changed files with 1076 additions and 597 deletions

View file

@ -25,7 +25,8 @@ public class AppPreferences {
String HostPort,
String HostExtra,
boolean autoCheck4Updates,
boolean tinfoilXciSupport
boolean tinfoilXciSupport,
boolean nspFileFilterForGl
){
setProtocol(Protocol);
setRecent(PreviouslyOpened);
@ -41,6 +42,7 @@ public class AppPreferences {
setHostExtra(HostExtra);
setAutoCheckUpdates(autoCheck4Updates);
setTfXCI(tinfoilXciSupport);
setNspFileFilterGL(nspFileFilterForGl);
}
public String getTheme(){
String theme = preferences.get("THEME", "/res/app_dark.css"); // Don't let user to change settings manually
@ -109,4 +111,7 @@ public class AppPreferences {
public String getLanguage(){return preferences.get("USR_LANG", Locale.getDefault().getISO3Language());}
public void setLanguage(String langStr){preferences.put("USR_LANG", langStr);}
public boolean getNspFileFilterGL(){return preferences.getBoolean("GL_NSP_FILTER", false); }
public void setNspFileFilterGL(boolean prop){preferences.putBoolean("GL_NSP_FILTER", prop);}
}

View file

@ -8,6 +8,7 @@ import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import nsusbloader.AppPreferences;
import nsusbloader.MediatorControl;
import java.net.URL;
import java.util.ResourceBundle;
@ -49,6 +50,11 @@ public class FrontController implements Initializable {
nsIpTextField.setVisible(true);
}
}
// Really bad disable-enable upload button function
if (tableFilesListController.isFilesForUploadListEmpty())
MediatorControl.getInstance().getContoller().disableUploadStopBtn(true);
else
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
}); // Add listener to notify tableView controller
tableFilesListController.setNewProtocol(choiceProtocol.getSelectionModel().getSelectedItem()); // Notify tableView controller

View file

@ -17,6 +17,7 @@ import nsusbloader.USB.UsbCommunications;
import java.io.File;
import java.net.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
@ -56,7 +57,10 @@ public class NSLMainController implements Initializable {
MediatorControl.getInstance().setController(this);
uploadStopBtn.setDisable(true);
if (FrontTabController.getSelectedProtocol().equals("TinFoil"))
uploadStopBtn.setDisable(true);
else
uploadStopBtn.setDisable(false);
selectNspBtn.setOnAction(e->{ selectFilesBtnAction(); });
uploadStopBtn.setOnAction(e->{ uploadBtnAction(); });
@ -128,23 +132,26 @@ public class NSLMainController implements Initializable {
if ((workThread == null || !workThread.isAlive())){
// Collect files
List<File> nspToUpload;
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) == null) {
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) == null && FrontTabController.getSelectedProtocol().equals("TinFoil")) {
logArea.setText(resourceBundle.getString("logsNoFolderFileSelected"));
return;
}
else {
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
for (File item: nspToUpload)
logArea.appendText(" "+item.getAbsolutePath()+"\n");
if ((nspToUpload = FrontTabController.tableFilesListController.getFilesForUpload()) != null){
logArea.setText(resourceBundle.getString("logsFilesToUploadTitle")+"\n");
for (File item: nspToUpload)
logArea.appendText(" "+item.getAbsolutePath()+"\n");
}
else {
logArea.clear();
nspToUpload = new LinkedList<>();
}
}
// If USB selected
if (FrontTabController.getSelectedProtocol().equals("GoldLeaf") ||
(
FrontTabController.getSelectedProtocol().equals("TinFoil")
&& FrontTabController.getSelectedNetUsb().equals("USB")
)
( FrontTabController.getSelectedProtocol().equals("TinFoil") && FrontTabController.getSelectedNetUsb().equals("USB") )
){
usbNetCommunications = new UsbCommunications(nspToUpload, FrontTabController.getSelectedProtocol());
usbNetCommunications = new UsbCommunications(nspToUpload, FrontTabController.getSelectedProtocol(), SettingsTabController.getNSPFileFilterForGL());
workThread = new Thread(usbNetCommunications);
workThread.setDaemon(true);
workThread.start();
@ -217,7 +224,10 @@ public class NSLMainController implements Initializable {
* Crunch. Now you see that I'm not a programmer.. This function called from NSTableViewController
* */
public void disableUploadStopBtn(boolean disable){
uploadStopBtn.setDisable(disable);
if (FrontTabController.getSelectedProtocol().equals("TinFoil"))
uploadStopBtn.setDisable(disable);
else
uploadStopBtn.setDisable(false);
}
/**
* Drag-n-drop support (dragOver consumer)
@ -285,7 +295,8 @@ public class NSLMainController implements Initializable {
SettingsTabController.getHostPort(),
SettingsTabController.getHostExtra(),
SettingsTabController.getAutoCheckForUpdates(),
SettingsTabController.getTfXCISupport()
SettingsTabController.getTfXCISupport(),
SettingsTabController.getNSPFileFilterForGL()
);
}
}

View file

@ -25,7 +25,6 @@ import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.ResourceBundle;
public class NSTableViewController implements Initializable {
@ -33,8 +32,6 @@ public class NSTableViewController implements Initializable {
private TableView<NSLRowModel> table;
private ObservableList<NSLRowModel> rowsObsLst;
private String protocol;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
rowsObsLst = FXCollections.observableArrayList();
@ -55,7 +52,6 @@ public class NSTableViewController implements Initializable {
} else if (keyEvent.getCode() == KeyCode.SPACE) {
for (NSLRowModel item : table.getSelectionModel().getSelectedItems()) {
item.setMarkForUpload(!item.isMarkForUpload());
restrictSelection(item);
}
table.refresh();
}
@ -107,7 +103,6 @@ public class NSTableViewController implements Initializable {
@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean oldValue, Boolean newValue) {
model.setMarkForUpload(newValue);
restrictSelection(model);
}
});
return booleanProperty;
@ -162,7 +157,7 @@ public class NSTableViewController implements Initializable {
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
NSLRowModel thisItem = row.getItem();
thisItem.setMarkForUpload(!thisItem.isMarkForUpload());
restrictSelection(thisItem);
table.refresh();
}
mouseEvent.consume();
}
@ -174,18 +169,6 @@ public class NSTableViewController implements Initializable {
table.setItems(rowsObsLst);
table.getColumns().addAll(statusColumn, fileNameColumn, fileSizeColumn, uploadColumn);
}
/**
* See uploadColumn callback. In case of GoldLeaf we have to restrict selection
* */
private void restrictSelection(NSLRowModel modelChecked){
if (!protocol.equals("TinFoil") && rowsObsLst.size() > 1) { // Tinfoil doesn't need any restrictions. If only one file in list, also useless
for (NSLRowModel model: rowsObsLst){
if (model != modelChecked)
model.setMarkForUpload(false);
}
}
table.refresh();
}
/**
* Add files when user selected them
* */
@ -196,21 +179,15 @@ public class NSTableViewController implements Initializable {
filesAlreayInList.add(model.getNspFileName());
for (File file: newFiles)
if (!filesAlreayInList.contains(file.getName())) {
if (protocol.equals("TinFoil"))
rowsObsLst.add(new NSLRowModel(file, true));
else
rowsObsLst.add(new NSLRowModel(file, false));
rowsObsLst.add(new NSLRowModel(file, true));
}
}
else {
for (File file: newFiles)
if (protocol.equals("TinFoil"))
rowsObsLst.add(new NSLRowModel(file, true));
else
rowsObsLst.add(new NSLRowModel(file, false));
rowsObsLst.add(new NSLRowModel(file, true));
MediatorControl.getInstance().getContoller().disableUploadStopBtn(false);
}
rowsObsLst.get(0).setMarkForUpload(true);
//rowsObsLst.get(0).setMarkForUpload(true);
table.refresh();
}
/**
@ -237,14 +214,16 @@ public class NSTableViewController implements Initializable {
return null;
}
}
public boolean isFilesForUploadListEmpty(){
return rowsObsLst.isEmpty();
}
/**
* Update files in case something is wrong. Requested from UsbCommunications
* */
public void setFileStatus(String fileName, EFileStatus status){
for (NSLRowModel model: rowsObsLst){
if (model.getNspFileName().equals(fileName)){
if (model.getNspFileName().equals(fileName))
model.setStatus(status);
}
}
table.refresh();
}
@ -252,25 +231,10 @@ public class NSTableViewController implements Initializable {
* Called if selected different USB protocol
* */
public void setNewProtocol(String newProtocol){
protocol = newProtocol;
if (rowsObsLst.isEmpty())
return;
if (newProtocol.equals("TinFoil")){
for (NSLRowModel model: rowsObsLst)
model.setMarkForUpload(true);
}
else {
ListIterator<NSLRowModel> iterator = rowsObsLst.listIterator();
while (iterator.hasNext()){
NSLRowModel current = iterator.next();
if (current.getNspFileName().toLowerCase().endsWith("xci"))
iterator.remove();
else
current.setMarkForUpload(false);
}
if (!rowsObsLst.isEmpty())
rowsObsLst.get(0).setMarkForUpload(true);
}
if (! newProtocol.equals("TinFoil"))
rowsObsLst.removeIf(current -> current.getNspFileName().toLowerCase().endsWith("xci"));
table.refresh();
}

View file

@ -23,7 +23,8 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class SettingsController implements Initializable {
@FXML
private CheckBox nspFilesFilterForGLCB;
@FXML
private CheckBox validateNSHostNameCb;
@FXML
@ -64,6 +65,8 @@ public class SettingsController implements Initializable {
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
nspFilesFilterForGLCB.setSelected(AppPreferences.getInstance().getNspFileFilterGL());
validateNSHostNameCb.setSelected(AppPreferences.getInstance().getNsIpValidationNeeded());
expertSettingsVBox.setDisable(!AppPreferences.getInstance().getExpertMode());
@ -243,7 +246,7 @@ public class SettingsController implements Initializable {
});
}
public boolean getNSPFileFilterForGL(){return nspFilesFilterForGLCB.isSelected(); }
public boolean getExpertModeSelected(){ return expertModeCb.isSelected(); }
public boolean getAutoIpSelected(){ return autoDetectIpCb.isSelected(); }
public boolean getRandPortSelected(){ return randPortCb.isSelected(); }

View file

@ -49,7 +49,7 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
}
catch (UnsupportedEncodingException uee){
isValid = false;
logPrinter.print("NET: Unsupported encoding for 'URLEncoder'. Internal issue you can't fix. Please report. . Returned:\n\t"+uee.getMessage(), EMsgType.FAIL);
logPrinter.print("NET: Unsupported encoding for 'URLEncoder'. Internal issue you can't fix. Please report. Returned:\n\t"+uee.getMessage(), EMsgType.FAIL);
for (File nspFile : filesList)
nspMap.put(nspFile.getName(), nspFile);
close(EFileStatus.FAILED);

View file

@ -24,7 +24,7 @@ public class NETPacket {
"Accept-Ranges: bytes\r\n"+
"Content-Range: bytes %d-%d/%d\r\n"+
"Content-Length: %d\r\n"+
"Last-Modified: Mon, 18 Mar 2019 12:57:33 GMT\r\n\r\n";
"Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT\r\n\r\n";
private static final String CODE_400 =
"HTTP/1.0 400 invalid range\r\n"+
"Server: NS-USBloader-"+NSLMain.appVersion+"\r\n" +

View file

@ -12,10 +12,9 @@ import java.util.Locale;
import java.util.ResourceBundle;
public class NSLMain extends Application {
public static final String appVersion = "v0.5.3";
public static final String appVersion = "v0.6";
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
Locale userLocale = new Locale(AppPreferences.getInstance().getLanguage()); // NOTE: user locale based on ISO3 Language codes

View file

@ -1,25 +0,0 @@
package nsusbloader.USB.PFS;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Data class to hold NCA, tik, xml etc. meta-information
* */
public class NCAFile {
//private int ncaNumber;
private byte[] ncaFileName;
private long ncaOffset;
private long ncaSize;
//public void setNcaNumber(int ncaNumber){ this.ncaNumber = ncaNumber; }
public void setNcaFileName(byte[] ncaFileName) { this.ncaFileName = ncaFileName; }
public void setNcaOffset(long ncaOffset) { this.ncaOffset = ncaOffset; }
public void setNcaSize(long ncaSize) { this.ncaSize = ncaSize; }
//public int getNcaNumber() {return this.ncaNumber; }
public byte[] getNcaFileName() { return ncaFileName; }
public byte[] getNcaFileNameLength() { return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ncaFileName.length).array(); }
public long getNcaOffset() { return ncaOffset; }
public long getNcaSize() { return ncaSize; }
}

View file

@ -1,218 +0,0 @@
package nsusbloader.USB.PFS;
import nsusbloader.ModelControllers.LogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.ServiceWindow;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* Used in GoldLeaf USB protocol
* */
public class PFSProvider {
private static final byte[] PFS0 = new byte[]{(byte)0x50, (byte)0x46, (byte)0x53, (byte)0x30}; // PFS0, and what did you think?
private LogPrinter logPrinter;
private ResourceBundle rb;
private RandomAccessFile randAccessFile;
private String nspFileName;
private NCAFile[] ncaFiles;
private long bodySize;
private int ticketID = -1;
public PFSProvider(File nspFile, LogPrinter logPrinter){
this.logPrinter = logPrinter;
try {
this.randAccessFile = new RandomAccessFile(nspFile, "r");
nspFileName = nspFile.getName();
}
catch (FileNotFoundException fnfe){
logPrinter.print("PFS File not founnd: \n "+fnfe.getMessage(), EMsgType.FAIL);
nspFileName = null;
}
Locale userLocale = new Locale(Locale.getDefault().getISO3Language());
rb = ResourceBundle.getBundle("locale", userLocale);
}
public boolean init() {
if (nspFileName == null)
return false;
int filesCount;
int header;
logPrinter.print("PFS Start NSP file analyze for ["+nspFileName+"]", EMsgType.INFO);
try {
byte[] fileStartingBytes = new byte[12];
// Read PFS0, files count, header, padding (4 zero bytes)
if (randAccessFile.read(fileStartingBytes) == 12)
logPrinter.print("PFS Read file starting bytes.", EMsgType.PASS);
else {
logPrinter.print("PFS Read file starting bytes.", EMsgType.FAIL);
randAccessFile.close();
return false;
}
// Check PFS0
if (Arrays.equals(PFS0, Arrays.copyOfRange(fileStartingBytes, 0, 4)))
logPrinter.print("PFS Read 'PFS0'.", EMsgType.PASS);
else {
logPrinter.print("PFS Read 'PFS0'.", EMsgType.WARNING);
if (!ServiceWindow.getConfirmationWindow(nspFileName+"\n"+rb.getString("windowTitleConfirmWrongPFS0"), rb.getString("windowBodyConfirmWrongPFS0"))) {
randAccessFile.close();
return false;
}
}
// Get files count
filesCount = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 4, 8)).order(ByteOrder.LITTLE_ENDIAN).getInt();
if (filesCount > 0 ) {
logPrinter.print("PFS Read files count [" + filesCount + "]", EMsgType.PASS);
}
else {
logPrinter.print("PFS Read files count", EMsgType.FAIL);
randAccessFile.close();
return false;
}
// Get header
header = ByteBuffer.wrap(Arrays.copyOfRange(fileStartingBytes, 8, 12)).order(ByteOrder.LITTLE_ENDIAN).getInt();
if (header > 0 )
logPrinter.print("PFS Read header ["+header+"]", EMsgType.PASS);
else {
logPrinter.print("PFS Read header ", EMsgType.FAIL);
randAccessFile.close();
return false;
}
//*********************************************************************************************
// Create NCA set
this.ncaFiles = new NCAFile[filesCount];
// Collect files from NSP
byte[] ncaInfoArr = new byte[24]; // should be unsigned long, but.. java.. u know my pain man
HashMap<Integer, Long> ncaNameOffsets = new LinkedHashMap<>();
int offset;
long nca_offset;
long nca_size;
long nca_name_offset;
for (int i=0; i<filesCount; i++){
if (randAccessFile.read(ncaInfoArr) == 24) {
logPrinter.print("PFS Read NCA inside NSP: " + i, EMsgType.PASS);
}
else {
logPrinter.print("PFS Read NCA inside NSP: "+i, EMsgType.FAIL);
randAccessFile.close();
return false;
}
offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();
nca_offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 4, 12)).order(ByteOrder.LITTLE_ENDIAN).getLong();
nca_size = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 12, 20)).order(ByteOrder.LITTLE_ENDIAN).getLong();
nca_name_offset = ByteBuffer.wrap(Arrays.copyOfRange(ncaInfoArr, 20, 24)).order(ByteOrder.LITTLE_ENDIAN).getInt(); // yes, cast from int to long.
logPrinter.print(" Padding check", offset == 0?EMsgType.PASS:EMsgType.WARNING);
logPrinter.print(" NCA offset check: "+nca_offset, nca_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
logPrinter.print(" NCA size check: "+nca_size, nca_size >= 0?EMsgType.PASS: EMsgType.WARNING);
logPrinter.print(" NCA name offset check: "+nca_name_offset, nca_name_offset >= 0?EMsgType.PASS:EMsgType.WARNING);
NCAFile ncaFile = new NCAFile();
ncaFile.setNcaOffset(nca_offset);
ncaFile.setNcaSize(nca_size);
this.ncaFiles[i] = ncaFile;
ncaNameOffsets.put(i, nca_name_offset);
}
// Final offset
byte[] bufForInt = new byte[4];
if ((randAccessFile.read(bufForInt) == 4) && (Arrays.equals(bufForInt, new byte[4])))
logPrinter.print("PFS Final padding check", EMsgType.PASS);
else
logPrinter.print("PFS Final padding check", EMsgType.WARNING);
// Calculate position including header for body size offset
bodySize = randAccessFile.getFilePointer()+header;
//*********************************************************************************************
// Collect file names from NCAs
logPrinter.print("PFS Collecting file names", EMsgType.INFO);
List<Byte> ncaFN; // Temporary
byte[] b = new byte[1]; // Temporary
for (int i=0; i<filesCount; i++){
ncaFN = new ArrayList<>();
randAccessFile.seek(filesCount*24+16+ncaNameOffsets.get(i)); // Files cont * 24(bit for each meta-data) + 4 bytes goes after all of them + 12 bit what were in the beginning
while ((randAccessFile.read(b)) != -1){
if (b[0] == 0x00)
break;
else
ncaFN.add(b[0]);
}
byte[] exchangeTempArray = new byte[ncaFN.size()];
for (int j=0; j < ncaFN.size(); j++)
exchangeTempArray[j] = ncaFN.get(j);
// Find and store ticket (.tik)
if (new String(exchangeTempArray, StandardCharsets.UTF_8).toLowerCase().endsWith(".tik"))
this.ticketID = i;
this.ncaFiles[i].setNcaFileName(Arrays.copyOf(exchangeTempArray, exchangeTempArray.length));
}
randAccessFile.close();
}
catch (IOException ioe){
logPrinter.print("PFS Failed NSP file analyze for ["+nspFileName+"]\n "+ioe.getMessage(), EMsgType.FAIL);
ioe.printStackTrace();
}
logPrinter.print("PFS Finish NSP file analyze for ["+nspFileName+"]", EMsgType.PASS);
return true;
}
/**
* Return file name as byte array
* */
public byte[] getBytesNspFileName(){
return nspFileName.getBytes(StandardCharsets.UTF_8);
}
/**
* Return file name as String
* */
public String getStringNspFileName(){
return nspFileName;
}
/**
* Return file name length as byte array
* */
public byte[] getBytesNspFileNameLength(){
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(getBytesNspFileName().length).array();
}
/**
* Return NCA count inside of file as byte array
* */
public byte[] getBytesCountOfNca(){
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ncaFiles.length).array();
}
/**
* Return NCA count inside of file as int
* */
public int getIntCountOfNca(){
return ncaFiles.length;
}
/**
* Return requested-by-number NCA file inside of file
* */
public NCAFile getNca(int ncaNumber){
return ncaFiles[ncaNumber];
}
/**
* Return bodySize
* */
public long getBodySize(){
return bodySize;
}
/**
* Return special NCA file: ticket
* (sugar)
* */
public int getNcaTicketID(){
return ticketID;
}
}

File diff suppressed because it is too large Load diff