diff --git a/src/main/java/konogonka/Controllers/MainController.java b/src/main/java/konogonka/Controllers/MainController.java
index 0450770..bd112c4 100644
--- a/src/main/java/konogonka/Controllers/MainController.java
+++ b/src/main/java/konogonka/Controllers/MainController.java
@@ -28,6 +28,7 @@ import konogonka.Child.ChildWindow;
import konogonka.Controllers.NCA.NCAController;
import konogonka.Controllers.NPDM.NPDMController;
import konogonka.Controllers.NSP.NSPController;
+import konogonka.Controllers.RFS.RomFsController;
import konogonka.Controllers.TIK.TIKController;
import konogonka.Controllers.XCI.XCIController;
import konogonka.Controllers.XML.XMLController;
@@ -71,6 +72,8 @@ public class MainController implements Initializable {
private XMLController XMLTabController;
@FXML
private NPDMController NPDMTabController;
+ @FXML
+ private RomFsController RFSTabController;
private File selectedFile;
@@ -104,10 +107,23 @@ public class MainController implements Initializable {
else
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
- fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files", "*.nsp", "*.nsz", "*.xci", "*.nca", "*.tik", "*.xml", "*.npdm"));
+ fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files",
+ "*.nsp", "*.nsz", "*.xci", "*.nca", "*.tik", "*.xml", "*.npdm", "*.romfs"));
this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow());
- // todo: fix
+
+ if (this.selectedFile != null && this.selectedFile.exists()) {
+ resetAllTabsContent();
+ filenameSelected.setText(this.selectedFile.getAbsolutePath());
+ previouslyOpenedPath = this.selectedFile.getParent();
+ analyzeBtn.setDisable(false);
+ String fileExtension = this.selectedFile.getName().toLowerCase().replaceAll("^.*\\.", "");
+ setFocusOnPane(fileExtension);
+ }
+
+ logArea.clear();
+ }
+ private void resetAllTabsContent(){
analyzeBtn.setDisable(true);
NSPTabController.resetTab();
XCITabController.resetTab();
@@ -115,36 +131,32 @@ public class MainController implements Initializable {
TIKTabController.resetTab();
XMLTabController.resetTab();
NPDMTabController.resetTab();
-
- if (this.selectedFile != null && this.selectedFile.exists()) {
- filenameSelected.setText(this.selectedFile.getAbsolutePath());
- previouslyOpenedPath = this.selectedFile.getParent();
- analyzeBtn.setDisable(false);
- String fileExtension = this.selectedFile.getName().toLowerCase().replaceAll("^.*\\.", "");
- switch (fileExtension){
- case "nsp":
- case "nsz":
- tabPane.getSelectionModel().select(0);
- break;
- case "xci":
- tabPane.getSelectionModel().select(1);
- break;
- case "nca":
- tabPane.getSelectionModel().select(2);
- break;
- case "tic":
- tabPane.getSelectionModel().select(3);
- break;
- case "xml":
- tabPane.getSelectionModel().select(4);
- break;
- case "npdm":
- tabPane.getSelectionModel().select(5);
- break;
- }
+ RFSTabController.resetTab();
+ }
+ private void setFocusOnPane(String fileExtension){
+ switch (fileExtension){
+ case "nsp":
+ case "nsz":
+ tabPane.getSelectionModel().select(0);
+ break;
+ case "xci":
+ tabPane.getSelectionModel().select(1);
+ break;
+ case "nca":
+ tabPane.getSelectionModel().select(2);
+ break;
+ case "tic":
+ tabPane.getSelectionModel().select(3);
+ break;
+ case "xml":
+ tabPane.getSelectionModel().select(4);
+ break;
+ case "npdm":
+ tabPane.getSelectionModel().select(5);
+ break;
+ case "romfs":
+ tabPane.getSelectionModel().select(6);
}
-
- logArea.clear();
}
/**
* Start analyze
@@ -154,7 +166,7 @@ public class MainController implements Initializable {
switch (fileExtension){
case "nsp":
case "nsz":
- NSPTabController.analyze(selectedFile); // TODO: NSP OR XCI
+ NSPTabController.analyze(selectedFile); // TODO: NSP OR NSZ ?
break;
case "xci":
XCITabController.analyze(selectedFile);
@@ -171,6 +183,8 @@ public class MainController implements Initializable {
case "npdm":
NPDMTabController.analyze(selectedFile);
break;
+ case "romfs":
+ RFSTabController.analyze(selectedFile);
}
}
@FXML
diff --git a/src/main/java/konogonka/Controllers/RFS/RFSFolderEntry.java b/src/main/java/konogonka/Controllers/RFS/RFSFolderEntry.java
new file mode 100644
index 0000000..f4bf4b6
--- /dev/null
+++ b/src/main/java/konogonka/Controllers/RFS/RFSFolderEntry.java
@@ -0,0 +1,36 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of Konogonka.
+
+ Konogonka 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.
+
+ Konogonka 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 Konogonka. If not, see .
+*/
+package konogonka.Controllers.RFS;
+
+public class RFSFolderEntry {
+ private String name;
+
+ public RFSFolderEntry(String name){
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString(){
+ return name;
+ }
+}
diff --git a/src/main/java/konogonka/Controllers/RFS/RomFsController.java b/src/main/java/konogonka/Controllers/RFS/RomFsController.java
new file mode 100644
index 0000000..46f662f
--- /dev/null
+++ b/src/main/java/konogonka/Controllers/RFS/RomFsController.java
@@ -0,0 +1,81 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of Konogonka.
+
+ Konogonka 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.
+
+ Konogonka 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 Konogonka. If not, see .
+*/
+package konogonka.Controllers.RFS;
+
+import javafx.fxml.FXML;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeView;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.VBox;
+import konogonka.Controllers.ITabController;
+import konogonka.Tools.ISuperProvider;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class RomFsController implements ITabController {
+
+ @FXML
+ private TreeView filesTreeView;
+ @FXML
+ private VBox folderContentVBox;
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ TreeItem rootTest = getEmptyRoot();
+ TreeItem test = new TreeItem<>(new RFSFolderEntry("WIP"), getFolderImage());
+
+ rootTest.getChildren().add(test);
+
+ filesTreeView.setRoot(rootTest);
+ }
+
+ @Override
+ public void analyze(File file) {
+ this.analyze(file, 0);
+ }
+
+ @Override
+ public void analyze(File file, long offset) {
+ TreeItem rootItem = getEmptyRoot();
+
+ filesTreeView.setRoot(rootItem);
+ }
+
+ @Override
+ public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
+
+ }
+
+ @Override
+ public void resetTab() {
+ filesTreeView.setRoot(null);
+ }
+
+ private Region getFolderImage(){
+ final Region folderImage = new Region();
+ folderImage.getStyleClass().add("regionFolder");
+ return folderImage;
+ }
+
+ private TreeItem getEmptyRoot(){
+ return new TreeItem<>(new RFSFolderEntry("/"));
+ }
+}
diff --git a/src/main/java/konogonka/RainbowHexDump.java b/src/main/java/konogonka/RainbowDump.java
similarity index 93%
rename from src/main/java/konogonka/RainbowHexDump.java
rename to src/main/java/konogonka/RainbowDump.java
index 21593ed..97d6e6f 100644
--- a/src/main/java/konogonka/RainbowHexDump.java
+++ b/src/main/java/konogonka/RainbowDump.java
@@ -23,7 +23,7 @@ import java.nio.charset.StandardCharsets;
/**
* Debug tool like hexdump <3
*/
-public class RainbowHexDump {
+public class RainbowDump {
private static final String ANSI_RESET = "\u001B[0m";
private static final String ANSI_BLACK = "\u001B[30m";
private static final String ANSI_RED = "\u001B[31m";
@@ -55,4 +55,8 @@ public class RainbowHexDump {
public static void octDumpLong(long value){
System.out.println(String.format("%64s", Long.toBinaryString( value )).replace(' ', '0')+" | "+value);
}
+
+ public static String formatDecHexString(long value){
+ return String.format("%-20d 0x%x", value, value);
+ }
}
diff --git a/src/main/java/konogonka/Tools/NCA/NCAContent.java b/src/main/java/konogonka/Tools/NCA/NCAContent.java
index 5b8aec8..4577908 100644
--- a/src/main/java/konogonka/Tools/NCA/NCAContent.java
+++ b/src/main/java/konogonka/Tools/NCA/NCAContent.java
@@ -313,7 +313,6 @@ public class NCAContent {
}
}
private class CryptoSection03RomFS{
-
CryptoSection03RomFS(File file,
long offsetPosition,
byte[] decryptedKey,
diff --git a/src/main/java/konogonka/Tools/NPDM/KernelAccessControlProvider.java b/src/main/java/konogonka/Tools/NPDM/KernelAccessControlProvider.java
index ddc8625..75d6d66 100644
--- a/src/main/java/konogonka/Tools/NPDM/KernelAccessControlProvider.java
+++ b/src/main/java/konogonka/Tools/NPDM/KernelAccessControlProvider.java
@@ -19,12 +19,9 @@
package konogonka.Tools.NPDM;
import konogonka.LoperConverter;
-import konogonka.RainbowHexDump;
-import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
-import java.util.Map;
/*
NOTE: This implementation is extremely bad for using application as library. Use raw for own purposes.
diff --git a/src/main/java/konogonka/Tools/RomFs/FileMeta.java b/src/main/java/konogonka/Tools/RomFs/FileMeta.java
new file mode 100644
index 0000000..e4f4d0d
--- /dev/null
+++ b/src/main/java/konogonka/Tools/RomFs/FileMeta.java
@@ -0,0 +1,29 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of Konogonka.
+
+ Konogonka 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.
+
+ Konogonka 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 Konogonka. If not, see .
+*/
+package konogonka.Tools.RomFs;
+
+public class FileMeta {
+ private int containingDirectoryOffset;
+ private int nextSiblingFileOffset;
+ private long fileDataOffset;
+ private long fileDataLength;
+ private int nextFileOffset;
+ private int fileNameLength;
+ private String fileName;
+}
diff --git a/src/main/java/konogonka/Tools/RomFs/FolderMeta.java b/src/main/java/konogonka/Tools/RomFs/FolderMeta.java
new file mode 100644
index 0000000..0c6cd7e
--- /dev/null
+++ b/src/main/java/konogonka/Tools/RomFs/FolderMeta.java
@@ -0,0 +1,29 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of Konogonka.
+
+ Konogonka 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.
+
+ Konogonka 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 Konogonka. If not, see .
+*/
+package konogonka.Tools.RomFs;
+
+public class FolderMeta {
+ private int parentDirectoryOffset;
+ private int nextSiblingDirectoryOffset;
+ private int firstSubdirectoryOffset;
+ private int firstFileOffset;
+ private int nextDirectoryOffset;
+ private int dirNameLength;
+ private String dirName;
+}
diff --git a/src/main/java/konogonka/Tools/RomFs/Level6Header.java b/src/main/java/konogonka/Tools/RomFs/Level6Header.java
new file mode 100644
index 0000000..d11c334
--- /dev/null
+++ b/src/main/java/konogonka/Tools/RomFs/Level6Header.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019-2020 Dmitry Isaenko
+ *
+ * This file is part of Konogonka.
+ *
+ * Konogonka 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.
+ *
+ * Konogonka 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 Konogonka. If not, see .
+ */
+
+package konogonka.Tools.RomFs;
+
+import konogonka.LoperConverter;
+import konogonka.RainbowDump;
+
+public class Level6Header {
+ private long headerHeaderLength;
+ private long headerDirectoryHashTableOffset;
+ private long headerDirectoryHashTableLength;
+ private long headerDirectoryMetadataTableOffset;
+ private long headerDirectoryMetadataTableLength;
+ private long headerFileHashTableOffset;
+ private long headerFileHashTableLength;
+ private long headerFileMetadataTableOffset;
+ private long headerFileMetadataTableLength;
+ private long headerFileDataOffset;
+
+ Level6Header(byte[] headerBytes){
+ int i = 0;
+ headerHeaderLength = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerDirectoryHashTableOffset = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerDirectoryHashTableLength = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerDirectoryMetadataTableOffset = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerDirectoryMetadataTableLength = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerFileHashTableOffset = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerFileHashTableLength = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerFileMetadataTableOffset = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerFileMetadataTableLength = LoperConverter.getLEint(headerBytes, i);
+ i += 0x8;
+ headerFileDataOffset = LoperConverter.getLEint(headerBytes, i);
+
+ System.out.println("== Level 6 Header ==\n" +
+ "Header Length (always 0x50 ?) "+ RainbowDump.formatDecHexString(headerHeaderLength)+" (size of this structure within first 0x200 block of LEVEL 6 part)\n" +
+ "Directory Hash Table Offset "+ RainbowDump.formatDecHexString(headerDirectoryHashTableOffset)+" (against THIS block where HEADER contains)\n" +
+ "Directory Hash Table Length "+ RainbowDump.formatDecHexString(headerDirectoryHashTableLength) + "\n" +
+ "Directory Metadata Table Offset "+ RainbowDump.formatDecHexString(headerDirectoryMetadataTableOffset) + "\n" +
+ "Directory Metadata Table Length "+ RainbowDump.formatDecHexString(headerDirectoryMetadataTableLength) + "\n" +
+ "File Hash Table Offset "+ RainbowDump.formatDecHexString(headerFileHashTableOffset) + "\n" +
+ "File Hash Table Length "+ RainbowDump.formatDecHexString(headerFileHashTableLength) + "\n" +
+ "File Metadata Table Offset "+ RainbowDump.formatDecHexString(headerFileMetadataTableOffset) + "\n" +
+ "File Metadata Table Length "+ RainbowDump.formatDecHexString(headerFileMetadataTableLength) + "\n" +
+ "File Data Offset "+ RainbowDump.formatDecHexString(headerFileDataOffset) + "\n" +
+ "-------------------------------------------------------------"
+ );
+ }
+
+ public long getHeaderHeaderLength() { return headerHeaderLength; }
+ public long getHeaderDirectoryHashTableOffset() { return headerDirectoryHashTableOffset; }
+ public long getHeaderDirectoryHashTableLength() { return headerDirectoryHashTableLength; }
+ public long getHeaderDirectoryMetadataTableOffset() { return headerDirectoryMetadataTableOffset; }
+ public long getHeaderDirectoryMetadataTableLength() { return headerDirectoryMetadataTableLength; }
+ public long getHeaderFileHashTableOffset() { return headerFileHashTableOffset; }
+ public long getHeaderFileHashTableLength() { return headerFileHashTableLength; }
+ public long getHeaderFileMetadataTableOffset() { return headerFileMetadataTableOffset; }
+ public long getHeaderFileMetadataTableLength() { return headerFileMetadataTableLength; }
+ public long getHeaderFileDataOffset() { return headerFileDataOffset; }
+}
diff --git a/src/main/java/konogonka/Tools/RomFs/RomFsDecryptedProvider.java b/src/main/java/konogonka/Tools/RomFs/RomFsDecryptedProvider.java
new file mode 100644
index 0000000..ff57205
--- /dev/null
+++ b/src/main/java/konogonka/Tools/RomFs/RomFsDecryptedProvider.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2019-2020 Dmitry Isaenko
+ *
+ * This file is part of Konogonka.
+ *
+ * Konogonka 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.
+ *
+ * Konogonka 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 Konogonka. If not, see .
+ */
+
+package konogonka.Tools.RomFs;
+
+import konogonka.Tools.ISuperProvider;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.PipedInputStream;
+
+public class RomFsDecryptedProvider implements ISuperProvider {
+
+ private static final long LEVEL_6_DEFAULT_OFFSET = 0x14000;
+
+ private File decryptedFSImage;
+ private Level6Header header;
+
+ public RomFsDecryptedProvider(File decryptedFSImage) throws Exception{ // TODO: add default setup AND using meta-data headers from NCA RomFs section (?)
+ this.decryptedFSImage = decryptedFSImage;
+
+ BufferedInputStream bis = new BufferedInputStream(new FileInputStream(decryptedFSImage));
+
+ skipTo(bis, LEVEL_6_DEFAULT_OFFSET);
+
+ byte[] rawDataChunk = new byte[0x50];
+
+ if (bis.read(rawDataChunk) != 0x50)
+ throw new Exception("Failed to read header (0x50)");
+
+ this.header = new Level6Header(rawDataChunk);
+
+ bis.close();
+ }
+ private void skipTo(BufferedInputStream bis, long size) throws Exception{
+ long mustSkip = size;
+ long skipped = 0;
+ while (mustSkip > 0){
+ skipped += bis.skip(mustSkip);
+ mustSkip = size - skipped;
+ }
+ }
+ private int getRealNameSize(int value){
+ if (value % 4 == 0)
+ return value;
+ return value + 4 - value % 4;
+ }
+
+ public Level6Header getHeader() { return header; }
+
+ @Override
+ public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception {
+ return null;
+ }
+
+ @Override
+ public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception {
+ return null;
+ }
+
+ @Override
+ public File getFile() {
+ return decryptedFSImage;
+ }
+
+ @Override
+ public long getRawFileDataStart() {
+ return 0;
+ }
+}
diff --git a/src/main/java/konogonka/Tools/XCI/HFS0Provider.java b/src/main/java/konogonka/Tools/XCI/HFS0Provider.java
index 4bdc1eb..df4ff9b 100644
--- a/src/main/java/konogonka/Tools/XCI/HFS0Provider.java
+++ b/src/main/java/konogonka/Tools/XCI/HFS0Provider.java
@@ -18,7 +18,6 @@
*/
package konogonka.Tools.XCI;
-import konogonka.RainbowHexDump;
import konogonka.Tools.ISuperProvider;
import java.io.*;
diff --git a/src/main/resources/FXML/NCA/NCASectionContent.fxml b/src/main/resources/FXML/NCA/NCASectionContent.fxml
index bedecd3..037ccb7 100644
--- a/src/main/resources/FXML/NCA/NCASectionContent.fxml
+++ b/src/main/resources/FXML/NCA/NCASectionContent.fxml
@@ -4,7 +4,10 @@
+
+
+
@@ -61,5 +64,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/FXML/RomFS/RFSTab.fxml b/src/main/resources/FXML/RomFS/RFSTab.fxml
new file mode 100644
index 0000000..bd209f1
--- /dev/null
+++ b/src/main/resources/FXML/RomFS/RFSTab.fxml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/FXML/landingPage.fxml b/src/main/resources/FXML/landingPage.fxml
index 525a213..3e2f2a0 100644
--- a/src/main/resources/FXML/landingPage.fxml
+++ b/src/main/resources/FXML/landingPage.fxml
@@ -95,6 +95,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/res/app_light.css b/src/main/resources/res/app_light.css
index 46f4afa..7375d8c 100644
--- a/src/main/resources/res/app_light.css
+++ b/src/main/resources/res/app_light.css
@@ -426,4 +426,11 @@
.titled-pane:focused > .title > .arrow-button .arrow
{
-fx-background-color: white, white;
+}
+
+.regionFolder {
+ -fx-shape: "M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z";
+ -fx-background-color: #ffbf00;
+ -fx-min-height: 17.0;
+ -fx-min-width: 17.5;
}
\ No newline at end of file