RomFs support: Frontend implementation for decrypted blobs (no export functionality); backend structures corrected, updated and ready for usage.
Bug fix for NSP table implementation: checkbox is visible now. Fix compilation time warnings regarding JavaFX unsafe stuff.
This commit is contained in:
parent
5c0b037fa8
commit
bad2924c02
22 changed files with 1300 additions and 195 deletions
2
pom.xml
2
pom.xml
|
@ -8,7 +8,7 @@
|
||||||
<name>konogonka</name>
|
<name>konogonka</name>
|
||||||
|
|
||||||
<artifactId>konogonka</artifactId>
|
<artifactId>konogonka</artifactId>
|
||||||
<version>0.0.2-SNAPSHOT</version>
|
<version>0.0.3-SNAPSHOT</version>
|
||||||
|
|
||||||
<url>https://github.com/developersu/${project.name}}/</url>
|
<url>https://github.com/developersu/${project.name}}/</url>
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -21,6 +21,8 @@ package konogonka.Controllers;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.input.DragEvent;
|
||||||
|
import javafx.scene.input.TransferMode;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import konogonka.AppPreferences;
|
import konogonka.AppPreferences;
|
||||||
|
@ -35,10 +37,10 @@ import konogonka.Controllers.XML.XMLController;
|
||||||
import konogonka.MediatorControl;
|
import konogonka.MediatorControl;
|
||||||
import konogonka.Settings.SettingsWindow;
|
import konogonka.Settings.SettingsWindow;
|
||||||
import konogonka.Tools.ISuperProvider;
|
import konogonka.Tools.ISuperProvider;
|
||||||
import konogonka.Tools.TIK.TIKProvider;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class MainController implements Initializable {
|
public class MainController implements Initializable {
|
||||||
|
@ -187,6 +189,21 @@ public class MainController implements Initializable {
|
||||||
RFSTabController.analyze(selectedFile);
|
RFSTabController.analyze(selectedFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private boolean isNotSupportedFileFormat(String fileExtension){
|
||||||
|
switch (fileExtension){
|
||||||
|
case "nsp":
|
||||||
|
case "nsz":
|
||||||
|
case "xci":
|
||||||
|
case "nca":
|
||||||
|
case "tic":
|
||||||
|
case "xml":
|
||||||
|
case "npdm":
|
||||||
|
case "romfs":
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@FXML
|
@FXML
|
||||||
private void showHideLogs(){
|
private void showHideLogs(){
|
||||||
if (splitPane.getItems().size() == 2)
|
if (splitPane.getItems().size() == 2)
|
||||||
|
@ -194,6 +211,50 @@ public class MainController implements Initializable {
|
||||||
else
|
else
|
||||||
splitPane.getItems().add(logPane);
|
splitPane.getItems().add(logPane);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Drag-n-drop support (dragOver consumer)
|
||||||
|
* */
|
||||||
|
@FXML
|
||||||
|
private void handleDragOver(DragEvent event){
|
||||||
|
event.acceptTransferModes(TransferMode.ANY);
|
||||||
|
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Drag-n-drop support (drop consumer)
|
||||||
|
* */
|
||||||
|
@FXML
|
||||||
|
private void handleDrop(DragEvent event){
|
||||||
|
List<File> filesDropped = event.getDragboard().getFiles();
|
||||||
|
|
||||||
|
if ( filesDropped.isEmpty() ) {
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
event.consume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File droppedFile = filesDropped.get(0);
|
||||||
|
|
||||||
|
String fileExtension = droppedFile.getName().toLowerCase().replaceAll("^.*\\.", "");
|
||||||
|
|
||||||
|
if (isNotSupportedFileFormat(fileExtension)) {
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
event.consume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedFile = droppedFile;
|
||||||
|
|
||||||
|
resetAllTabsContent();
|
||||||
|
filenameSelected.setText(selectedFile.getAbsolutePath());
|
||||||
|
previouslyOpenedPath = selectedFile.getParent();
|
||||||
|
analyzeBtn.setDisable(false);
|
||||||
|
setFocusOnPane(fileExtension);
|
||||||
|
|
||||||
|
event.setDropCompleted(true);
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
|
||||||
public void showContentWindow(ISuperProvider provider, IRowModel model){
|
public void showContentWindow(ISuperProvider provider, IRowModel model){
|
||||||
try{
|
try{
|
||||||
new ChildWindow(provider, model);
|
new ChildWindow(provider, model);
|
||||||
|
|
|
@ -18,11 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package konogonka.Controllers.NSP;
|
package konogonka.Controllers.NSP;
|
||||||
|
|
||||||
import javafx.beans.Observable;
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
|
@ -35,8 +32,6 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.input.MouseButton;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.util.Callback;
|
|
||||||
import konogonka.Controllers.IRowModel;
|
import konogonka.Controllers.IRowModel;
|
||||||
import konogonka.MediatorControl;
|
import konogonka.MediatorControl;
|
||||||
import konogonka.Tools.ISuperProvider;
|
import konogonka.Tools.ISuperProvider;
|
||||||
|
@ -44,7 +39,6 @@ import konogonka.Tools.PFS0.IPFS0Provider;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
@ -82,13 +76,13 @@ public class Pfs0TableViewController implements Initializable {
|
||||||
TableColumn<Pfs0RowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
TableColumn<Pfs0RowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||||
TableColumn<Pfs0RowModel, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
TableColumn<Pfs0RowModel, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
||||||
TableColumn<Pfs0RowModel, Long> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
TableColumn<Pfs0RowModel, Long> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||||
TableColumn<Pfs0RowModel, Boolean> uploadColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
TableColumn<Pfs0RowModel, Boolean> checkBoxColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||||
|
|
||||||
numberColumn.setEditable(false);
|
numberColumn.setEditable(false);
|
||||||
fileNameColumn.setEditable(false);
|
fileNameColumn.setEditable(false);
|
||||||
fileOffsetColumn.setEditable(false);
|
fileOffsetColumn.setEditable(false);
|
||||||
fileSizeColumn.setEditable(false);
|
fileSizeColumn.setEditable(false);
|
||||||
uploadColumn.setEditable(true);
|
checkBoxColumn.setEditable(true);
|
||||||
|
|
||||||
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||||
numberColumn.setMinWidth(30.0);
|
numberColumn.setMinWidth(30.0);
|
||||||
|
@ -108,17 +102,17 @@ public class Pfs0TableViewController implements Initializable {
|
||||||
fileSizeColumn.setMaxWidth(120.0);
|
fileSizeColumn.setMaxWidth(120.0);
|
||||||
fileSizeColumn.setResizable(false);
|
fileSizeColumn.setResizable(false);
|
||||||
|
|
||||||
uploadColumn.setMinWidth(120.0);
|
checkBoxColumn.setMinWidth(120.0);
|
||||||
uploadColumn.setPrefWidth(120.0);
|
checkBoxColumn.setPrefWidth(120.0);
|
||||||
uploadColumn.setMaxWidth(120.0);
|
checkBoxColumn.setMaxWidth(120.0);
|
||||||
uploadColumn.setResizable(false);
|
checkBoxColumn.setResizable(false);
|
||||||
|
|
||||||
numberColumn.setCellValueFactory(new PropertyValueFactory<>("number"));
|
numberColumn.setCellValueFactory(new PropertyValueFactory<>("number"));
|
||||||
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
|
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
|
||||||
fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
|
fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
|
||||||
fileOffsetColumn.setCellValueFactory(new PropertyValueFactory<>("fileOffset"));
|
fileOffsetColumn.setCellValueFactory(new PropertyValueFactory<>("fileOffset"));
|
||||||
// ><
|
// ><
|
||||||
uploadColumn.setCellValueFactory(paramFeatures -> {
|
checkBoxColumn.setCellValueFactory(paramFeatures -> {
|
||||||
Pfs0RowModel model = paramFeatures.getValue();
|
Pfs0RowModel model = paramFeatures.getValue();
|
||||||
|
|
||||||
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
||||||
|
@ -130,7 +124,7 @@ public class Pfs0TableViewController implements Initializable {
|
||||||
return booleanProperty;
|
return booleanProperty;
|
||||||
});
|
});
|
||||||
|
|
||||||
uploadColumn.setCellFactory(paramFeatures -> new CheckBoxTableCell<>());
|
checkBoxColumn.setCellFactory(paramFeatures -> new CheckBoxTableCell<>());
|
||||||
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
||||||
Pfs0RowModelTableView -> {
|
Pfs0RowModelTableView -> {
|
||||||
final TableRow<Pfs0RowModel> row = new TableRow<>();
|
final TableRow<Pfs0RowModel> row = new TableRow<>();
|
||||||
|
@ -167,6 +161,7 @@ public class Pfs0TableViewController implements Initializable {
|
||||||
table.getColumns().add(fileNameColumn);
|
table.getColumns().add(fileNameColumn);
|
||||||
table.getColumns().add(fileOffsetColumn);
|
table.getColumns().add(fileOffsetColumn);
|
||||||
table.getColumns().add(fileSizeColumn);
|
table.getColumns().add(fileSizeColumn);
|
||||||
|
table.getColumns().add(checkBoxColumn);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add files when user selected them
|
* Add files when user selected them
|
||||||
|
|
59
src/main/java/konogonka/Controllers/RFS/RFSEntry.java
Normal file
59
src/main/java/konogonka/Controllers/RFS/RFSEntry.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package konogonka.Controllers.RFS;
|
||||||
|
|
||||||
|
import konogonka.Controllers.IRowModel;
|
||||||
|
import konogonka.Tools.RomFs.FileSystemEntry;
|
||||||
|
|
||||||
|
public class RFSEntry implements IRowModel {
|
||||||
|
private FileSystemEntry fileSystemEntry;
|
||||||
|
private boolean check;
|
||||||
|
|
||||||
|
public RFSEntry(FileSystemEntry fileSystemEntry){
|
||||||
|
this.fileSystemEntry = fileSystemEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDirectory(){
|
||||||
|
return fileSystemEntry.isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return fileSystemEntry.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumber() { return 0; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFileName() { return fileSystemEntry.getName(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getFileSize() { return fileSystemEntry.getFileSize(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getFileOffset() { return fileSystemEntry.getFileOffset(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMarkSelected() { return check; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMarkSelected(boolean value) { check = value; }
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package konogonka.Controllers.RFS;
|
||||||
|
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.Initializable;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.MouseButton;
|
||||||
|
import konogonka.Controllers.IRowModel;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
public class RFSFolderTableViewController implements Initializable {
|
||||||
|
@FXML
|
||||||
|
private TableView<RFSEntry> table;
|
||||||
|
private ObservableList<RFSEntry> rowsObsLst;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
|
rowsObsLst = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
table.setPlaceholder(new Label());
|
||||||
|
table.setEditable(false); // At least with hacks it works as expected. Otherwise - null pointer exception
|
||||||
|
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
|
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||||
|
table.setOnKeyPressed(keyEvent -> {
|
||||||
|
if (!rowsObsLst.isEmpty()) {
|
||||||
|
if (keyEvent.getCode() == KeyCode.SPACE) {
|
||||||
|
for (RFSEntry item : table.getSelectionModel().getSelectedItems()) {
|
||||||
|
item.setMarkSelected( ! item.isMarkSelected());
|
||||||
|
}
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyEvent.consume();
|
||||||
|
});
|
||||||
|
|
||||||
|
TableColumn<RFSEntry, Integer> numberColumn = new TableColumn<>(resourceBundle.getString("tableNumberLbl"));
|
||||||
|
TableColumn<RFSEntry, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||||
|
TableColumn<RFSEntry, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
||||||
|
TableColumn<RFSEntry, Long> fileSizeColumn = new TableColumn<>(resourceBundle.getString("tableSizeLbl"));
|
||||||
|
TableColumn<RFSEntry, Boolean> checkBoxColumn = new TableColumn<>(resourceBundle.getString("tableUploadLbl"));
|
||||||
|
|
||||||
|
numberColumn.setEditable(false);
|
||||||
|
fileNameColumn.setEditable(false);
|
||||||
|
fileOffsetColumn.setEditable(false);
|
||||||
|
fileSizeColumn.setEditable(false);
|
||||||
|
checkBoxColumn.setEditable(true);
|
||||||
|
|
||||||
|
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||||
|
numberColumn.setMinWidth(30.0);
|
||||||
|
numberColumn.setPrefWidth(30.0);
|
||||||
|
numberColumn.setMaxWidth(30.0);
|
||||||
|
numberColumn.setResizable(false);
|
||||||
|
|
||||||
|
fileNameColumn.setMinWidth(25.0);
|
||||||
|
|
||||||
|
fileOffsetColumn.setMinWidth(130.0);
|
||||||
|
fileOffsetColumn.setPrefWidth(130.0);
|
||||||
|
fileOffsetColumn.setMaxWidth(130.0);
|
||||||
|
fileOffsetColumn.setResizable(false);
|
||||||
|
|
||||||
|
fileSizeColumn.setMinWidth(120.0);
|
||||||
|
fileSizeColumn.setPrefWidth(120.0);
|
||||||
|
fileSizeColumn.setMaxWidth(120.0);
|
||||||
|
fileSizeColumn.setResizable(false);
|
||||||
|
|
||||||
|
checkBoxColumn.setMinWidth(120.0);
|
||||||
|
checkBoxColumn.setPrefWidth(120.0);
|
||||||
|
checkBoxColumn.setMaxWidth(120.0);
|
||||||
|
checkBoxColumn.setResizable(false);
|
||||||
|
|
||||||
|
numberColumn.setCellValueFactory(new PropertyValueFactory<>("number"));
|
||||||
|
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
|
||||||
|
fileSizeColumn.setCellValueFactory(new PropertyValueFactory<>("fileSize"));
|
||||||
|
fileOffsetColumn.setCellValueFactory(new PropertyValueFactory<>("fileOffset"));
|
||||||
|
|
||||||
|
// ><
|
||||||
|
checkBoxColumn.setCellValueFactory(paramFeatures -> {
|
||||||
|
RFSEntry model = paramFeatures.getValue();
|
||||||
|
|
||||||
|
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
||||||
|
|
||||||
|
booleanProperty.addListener((observableValue, oldValue, newValue) -> {
|
||||||
|
model.setMarkSelected(newValue);
|
||||||
|
table.refresh();
|
||||||
|
});
|
||||||
|
return booleanProperty;
|
||||||
|
});
|
||||||
|
|
||||||
|
checkBoxColumn.setCellFactory(paramFeatures -> new CheckBoxTableCell<>());
|
||||||
|
table.setRowFactory( // this shit is made to implement context menu. It's such a pain..
|
||||||
|
RFSEntryTableView -> {
|
||||||
|
final TableRow<RFSEntry> row = new TableRow<>();
|
||||||
|
ContextMenu contextMenu = new ContextMenu();
|
||||||
|
/* // TODO: CHANGE TO 'Export' or something
|
||||||
|
MenuItem openMenuItem = new MenuItem("Open");
|
||||||
|
openMenuItem.setOnAction(new EventHandler<ActionEvent>() {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
MediatorControl.getInstance().getContoller().showContentWindow(provider, row.getItem());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
contextMenu.getItems().addAll(openMenuItem);
|
||||||
|
*/
|
||||||
|
row.setContextMenu(contextMenu);
|
||||||
|
row.contextMenuProperty().bind(
|
||||||
|
Bindings.when(Bindings.isNotNull(row.itemProperty())).then(contextMenu).otherwise((ContextMenu)null)
|
||||||
|
);
|
||||||
|
// Just.. don't ask..
|
||||||
|
row.setOnMouseClicked(mouseEvent -> {
|
||||||
|
if (!row.isEmpty() && mouseEvent.getButton() == MouseButton.PRIMARY){
|
||||||
|
RFSEntry thisItem = row.getItem();
|
||||||
|
thisItem.setMarkSelected(!thisItem.isMarkSelected());
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
mouseEvent.consume();
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
table.setItems(rowsObsLst);
|
||||||
|
table.getColumns().add(numberColumn);
|
||||||
|
table.getColumns().add(fileNameColumn);
|
||||||
|
table.getColumns().add(fileOffsetColumn);
|
||||||
|
table.getColumns().add(fileSizeColumn);
|
||||||
|
table.getColumns().add(checkBoxColumn);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Add files when user selected them on left-hand tree
|
||||||
|
* */
|
||||||
|
public void setContent(TreeItem<RFSEntry> containerTreeItem){
|
||||||
|
rowsObsLst.clear();
|
||||||
|
|
||||||
|
if (containerTreeItem == null) {
|
||||||
|
table.refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TreeItem<RFSEntry> childTreeItem : containerTreeItem.getChildren())
|
||||||
|
rowsObsLst.add(childTreeItem.getValue());
|
||||||
|
|
||||||
|
table.refresh();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,12 +19,14 @@
|
||||||
package konogonka.Controllers.RFS;
|
package konogonka.Controllers.RFS;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.TreeItem;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.control.TreeView;
|
import javafx.scene.input.MouseButton;
|
||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.util.Callback;
|
||||||
import konogonka.Controllers.ITabController;
|
import konogonka.Controllers.ITabController;
|
||||||
import konogonka.Tools.ISuperProvider;
|
import konogonka.Tools.ISuperProvider;
|
||||||
|
import konogonka.Tools.RomFs.FileSystemEntry;
|
||||||
|
import konogonka.Tools.RomFs.Level6Header;
|
||||||
import konogonka.Tools.RomFs.RomFsDecryptedProvider;
|
import konogonka.Tools.RomFs.RomFsDecryptedProvider;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -34,20 +36,48 @@ import java.util.ResourceBundle;
|
||||||
public class RomFsController implements ITabController {
|
public class RomFsController implements ITabController {
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private TreeView<RFSFolderEntry> filesTreeView;
|
private Label headerHeaderLengthLbl,
|
||||||
|
headerDirectoryHashTableOffsetLbl,
|
||||||
|
headerDirectoryHashTableLengthLbl,
|
||||||
|
headerDirectoryMetadataTableOffsetLbl,
|
||||||
|
headerDirectoryMetadataTableLengthLbl,
|
||||||
|
headerFileHashTableOffsetLbl,
|
||||||
|
headerFileHashTableLengthLbl,
|
||||||
|
headerFileMetadataTableOffsetLbl,
|
||||||
|
headerFileMetadataTableLengthLbl,
|
||||||
|
headerFileDataOffsetLbl;
|
||||||
@FXML
|
@FXML
|
||||||
private VBox folderContentVBox;
|
private Label headerHeaderLengthHexLbl,
|
||||||
|
headerDirectoryHashTableOffsetHexLbl,
|
||||||
|
headerDirectoryHashTableLengthHexLbl,
|
||||||
|
headerDirectoryMetadataTableOffsetHexLbl,
|
||||||
|
headerDirectoryMetadataTableLengthHexLbl,
|
||||||
|
headerFileHashTableOffsetHexLbl,
|
||||||
|
headerFileHashTableLengthHexLbl,
|
||||||
|
headerFileMetadataTableOffsetHexLbl,
|
||||||
|
headerFileMetadataTableLengthHexLbl,
|
||||||
|
headerFileDataOffsetHexLbl;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TreeView<RFSEntry> filesTreeView;
|
||||||
|
|
||||||
private RomFsDecryptedProvider RomFsProvider;
|
private RomFsDecryptedProvider RomFsProvider;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private RFSFolderTableViewController RFSTableViewController;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
TreeItem<RFSFolderEntry> rootTest = getEmptyRoot();
|
filesTreeView.setOnMouseClicked(mouseEvent -> {
|
||||||
TreeItem<RFSFolderEntry> test = new TreeItem<>(new RFSFolderEntry("WIP"), getFolderImage());
|
TreeItem<RFSEntry> item = filesTreeView.getSelectionModel().getSelectedItem();
|
||||||
|
if (item != null && item.getValue().isDirectory())
|
||||||
|
RFSTableViewController.setContent(item);
|
||||||
|
mouseEvent.consume();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
rootTest.getChildren().add(test);
|
private final class RFSTreeCell extends TreeCell<RFSEntry>{
|
||||||
|
|
||||||
filesTreeView.setRoot(rootTest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,22 +89,96 @@ public class RomFsController implements ITabController {
|
||||||
public void analyze(File file, long offset) {
|
public void analyze(File file, long offset) {
|
||||||
try {
|
try {
|
||||||
this.RomFsProvider = new RomFsDecryptedProvider(file);
|
this.RomFsProvider = new RomFsDecryptedProvider(file);
|
||||||
|
Level6Header header = RomFsProvider.getHeader();
|
||||||
|
long tempValue;
|
||||||
|
tempValue = header.getHeaderLength();
|
||||||
|
headerHeaderLengthLbl.setText(Long.toString(tempValue));
|
||||||
|
headerHeaderLengthHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getDirectoryHashTableOffset();
|
||||||
|
headerDirectoryHashTableOffsetLbl.setText(Long.toString(tempValue));
|
||||||
|
headerDirectoryHashTableOffsetHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getDirectoryHashTableLength();
|
||||||
|
headerDirectoryHashTableLengthLbl.setText(Long.toString(tempValue));
|
||||||
|
headerDirectoryHashTableLengthHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getDirectoryMetadataTableOffset();
|
||||||
|
headerDirectoryMetadataTableOffsetLbl.setText(Long.toString(tempValue));
|
||||||
|
headerDirectoryMetadataTableOffsetHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getDirectoryMetadataTableLength();
|
||||||
|
headerDirectoryMetadataTableLengthLbl.setText(Long.toString(tempValue));
|
||||||
|
headerDirectoryMetadataTableLengthHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getFileHashTableOffset();
|
||||||
|
headerFileHashTableOffsetLbl.setText(Long.toString(tempValue));
|
||||||
|
headerFileHashTableOffsetHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getFileHashTableLength();
|
||||||
|
headerFileHashTableLengthLbl.setText(Long.toString(tempValue));
|
||||||
|
headerFileHashTableLengthHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getFileMetadataTableOffset();
|
||||||
|
headerFileMetadataTableOffsetLbl.setText(Long.toString(tempValue));
|
||||||
|
headerFileMetadataTableOffsetHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getFileMetadataTableLength();
|
||||||
|
headerFileMetadataTableLengthLbl.setText(Long.toString(tempValue));
|
||||||
|
headerFileMetadataTableLengthHexLbl.setText(getHexString(tempValue));
|
||||||
|
tempValue = header.getFileDataOffset();
|
||||||
|
headerFileDataOffsetLbl.setText(Long.toString(tempValue));
|
||||||
|
headerFileDataOffsetHexLbl.setText(getHexString(tempValue));
|
||||||
|
|
||||||
|
TreeItem<RFSEntry> rootItem = getTreeFolderItem(RomFsProvider.getRootEntry());
|
||||||
|
|
||||||
|
filesTreeView.setRoot(rootItem);
|
||||||
|
|
||||||
|
RFSTableViewController.setContent(rootItem);
|
||||||
}
|
}
|
||||||
catch (Exception e){ // TODO: FIX
|
catch (Exception e){ // TODO: FIX
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
TreeItem<RFSFolderEntry> rootItem = getEmptyRoot();
|
}
|
||||||
|
|
||||||
filesTreeView.setRoot(rootItem);
|
private TreeItem<RFSEntry> getTreeFolderItem(FileSystemEntry childEntry){
|
||||||
|
TreeItem<RFSEntry> entryTreeItem = new TreeItem<>(new RFSEntry(childEntry), getFolderImage());
|
||||||
|
for (FileSystemEntry entry : childEntry.getContent()){
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
entryTreeItem.getChildren().add(getTreeFolderItem(entry));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
entryTreeItem.getChildren().add( getTreeFileItem(entry) );;
|
||||||
|
}
|
||||||
|
entryTreeItem.setExpanded(true);
|
||||||
|
|
||||||
|
return entryTreeItem;
|
||||||
|
}
|
||||||
|
private TreeItem<RFSEntry> getTreeFileItem(FileSystemEntry childEntry) {
|
||||||
|
return new TreeItem<>(new RFSEntry(childEntry), getFileImage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||||
|
throw new Exception("NOT IMPLEMENTED: analyze(ISuperProvider parentProvider, int fileNo)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetTab() {
|
public void resetTab() {
|
||||||
|
headerHeaderLengthLbl.setText("");
|
||||||
|
headerDirectoryHashTableOffsetLbl.setText("");
|
||||||
|
headerDirectoryHashTableLengthLbl.setText("");
|
||||||
|
headerDirectoryMetadataTableOffsetLbl.setText("");
|
||||||
|
headerDirectoryMetadataTableLengthLbl.setText("");
|
||||||
|
headerFileHashTableOffsetLbl.setText("");
|
||||||
|
headerFileHashTableLengthLbl.setText("");
|
||||||
|
headerFileMetadataTableOffsetLbl.setText("");
|
||||||
|
headerFileMetadataTableLengthLbl.setText("");
|
||||||
|
headerFileDataOffsetLbl.setText("");
|
||||||
|
|
||||||
|
headerHeaderLengthHexLbl.setText("");
|
||||||
|
headerDirectoryHashTableOffsetHexLbl.setText("");
|
||||||
|
headerDirectoryHashTableLengthHexLbl.setText("");
|
||||||
|
headerDirectoryMetadataTableOffsetHexLbl.setText("");
|
||||||
|
headerDirectoryMetadataTableLengthHexLbl.setText("");
|
||||||
|
headerFileHashTableOffsetHexLbl.setText("");
|
||||||
|
headerFileHashTableLengthHexLbl.setText("");
|
||||||
|
headerFileMetadataTableOffsetHexLbl.setText("");
|
||||||
|
headerFileMetadataTableLengthHexLbl.setText("");
|
||||||
|
headerFileDataOffsetHexLbl.setText("");
|
||||||
|
|
||||||
filesTreeView.setRoot(null);
|
filesTreeView.setRoot(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +187,13 @@ public class RomFsController implements ITabController {
|
||||||
folderImage.getStyleClass().add("regionFolder");
|
folderImage.getStyleClass().add("regionFolder");
|
||||||
return folderImage;
|
return folderImage;
|
||||||
}
|
}
|
||||||
|
private Region getFileImage(){
|
||||||
|
final Region folderImage = new Region();
|
||||||
|
folderImage.getStyleClass().add("regionFile");
|
||||||
|
return folderImage;
|
||||||
|
}
|
||||||
|
|
||||||
private TreeItem<RFSFolderEntry> getEmptyRoot(){
|
private String getHexString(long value){
|
||||||
return new TreeItem<>(new RFSFolderEntry("/"));
|
return String.format("0x%x", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,9 +87,9 @@ public class TIKController implements ITabController {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void analyze(File file, long offset) {
|
public void analyze(File file, long offset) {
|
||||||
Task analyzer = Analyzer.analyzeTIK(file, offset);
|
Task<TIKProvider> analyzer = Analyzer.analyzeTIK(file, offset);
|
||||||
analyzer.setOnSucceeded(e->{
|
analyzer.setOnSucceeded(e->{
|
||||||
TIKProvider tik = (TIKProvider) analyzer.getValue();
|
TIKProvider tik = analyzer.getValue();
|
||||||
if (offset == 0)
|
if (offset == 0)
|
||||||
setData(tik, file);
|
setData(tik, file);
|
||||||
else
|
else
|
||||||
|
|
|
@ -42,12 +42,8 @@ import konogonka.Tools.ISuperProvider;
|
||||||
import konogonka.Tools.XCI.HFS0Provider;
|
import konogonka.Tools.XCI.HFS0Provider;
|
||||||
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class MainFx extends Application {
|
public class MainFx extends Application {
|
||||||
public static final String appVersion = "v0.0.2";
|
public static final String appVersion = "v0.0.3";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception{
|
public void start(Stage primaryStage) throws Exception{
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
/*
|
|
||||||
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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
88
src/main/java/konogonka/Tools/RomFs/FileMeta4Debug.java
Normal file
88
src/main/java/konogonka/Tools/RomFs/FileMeta4Debug.java
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package konogonka.Tools.RomFs;
|
||||||
|
|
||||||
|
import konogonka.LoperConverter;
|
||||||
|
import konogonka.ModelControllers.LogPrinter;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static konogonka.RainbowDump.formatDecHexString;
|
||||||
|
|
||||||
|
public class FileMeta4Debug {
|
||||||
|
|
||||||
|
List<FileMeta> allFiles;
|
||||||
|
|
||||||
|
FileMeta4Debug(long fileMetadataTableLength, byte[] fileMetadataTable) {
|
||||||
|
allFiles = new ArrayList<>();
|
||||||
|
int i = 0;
|
||||||
|
while (i < fileMetadataTableLength) {
|
||||||
|
FileMeta fileMeta = new FileMeta();
|
||||||
|
fileMeta.containingDirectoryOffset = LoperConverter.getLEint(fileMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileMeta.nextSiblingFileOffset = LoperConverter.getLEint(fileMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileMeta.fileDataOffset = LoperConverter.getLElong(fileMetadataTable, i);
|
||||||
|
i += 8;
|
||||||
|
fileMeta.fileDataLength = LoperConverter.getLElong(fileMetadataTable, i);
|
||||||
|
i += 8;
|
||||||
|
fileMeta.nextFileOffset = LoperConverter.getLEint(fileMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileMeta.fileNameLength = LoperConverter.getLEint(fileMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileMeta.fileName = new String(Arrays.copyOfRange(fileMetadataTable, i, i + fileMeta.fileNameLength), StandardCharsets.UTF_8);
|
||||||
|
;
|
||||||
|
i += getRealNameSize(fileMeta.fileNameLength);
|
||||||
|
|
||||||
|
allFiles.add(fileMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FileMeta fileMeta : allFiles){
|
||||||
|
System.out.println(
|
||||||
|
"-------------------------FILE--------------------------------\n" +
|
||||||
|
"Offset of Containing Directory " + formatDecHexString(fileMeta.containingDirectoryOffset) + "\n" +
|
||||||
|
"Offset of next Sibling File " + formatDecHexString(fileMeta.nextSiblingFileOffset) + "\n" +
|
||||||
|
"Offset of File's Data " + formatDecHexString(fileMeta.fileDataOffset) + "\n" +
|
||||||
|
"Length of File's Data " + formatDecHexString(fileMeta.fileDataLength) + "\n" +
|
||||||
|
"Offset of next File in the same Hash Table bucket " + formatDecHexString(fileMeta.nextFileOffset) + "\n" +
|
||||||
|
"Name Length " + formatDecHexString(fileMeta.fileNameLength) + "\n" +
|
||||||
|
"Name Length (rounded up to multiple of 4) " + fileMeta.fileName + "\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRealNameSize(int value){
|
||||||
|
if (value % 4 == 0)
|
||||||
|
return value;
|
||||||
|
return value + 4 - value % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FileMeta{
|
||||||
|
int containingDirectoryOffset;
|
||||||
|
int nextSiblingFileOffset;
|
||||||
|
long fileDataOffset;
|
||||||
|
long fileDataLength;
|
||||||
|
int nextFileOffset;
|
||||||
|
int fileNameLength;
|
||||||
|
String fileName;
|
||||||
|
}
|
||||||
|
}
|
192
src/main/java/konogonka/Tools/RomFs/FileSystemEntry.java
Normal file
192
src/main/java/konogonka/Tools/RomFs/FileSystemEntry.java
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package konogonka.Tools.RomFs;
|
||||||
|
|
||||||
|
import konogonka.LoperConverter;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FileSystemEntry {
|
||||||
|
private boolean directoryFlag;
|
||||||
|
private String name;
|
||||||
|
private List<FileSystemEntry> content;
|
||||||
|
|
||||||
|
private static byte[] dirsMetadataTable;
|
||||||
|
private static byte[] filesMetadataTable;
|
||||||
|
|
||||||
|
private long fileOffset;
|
||||||
|
private long fileSize;
|
||||||
|
|
||||||
|
public FileSystemEntry(byte[] dirsMetadataTable, byte[] filesMetadataTable) throws Exception{
|
||||||
|
FileSystemEntry.dirsMetadataTable = dirsMetadataTable;
|
||||||
|
FileSystemEntry.filesMetadataTable = filesMetadataTable;
|
||||||
|
this.content = new ArrayList<>();
|
||||||
|
this.directoryFlag = true;
|
||||||
|
DirectoryMetaData rootDirectoryMetaData = new DirectoryMetaData();
|
||||||
|
if (rootDirectoryMetaData.dirName.isEmpty())
|
||||||
|
this.name = "/";
|
||||||
|
else
|
||||||
|
this.name = rootDirectoryMetaData.dirName;
|
||||||
|
if (rootDirectoryMetaData.parentDirectoryOffset != 0)
|
||||||
|
throw new Exception("Offset of Parent Directory is incorrect. Expected 0 for root, received value is "+ rootDirectoryMetaData.parentDirectoryOffset);
|
||||||
|
if (rootDirectoryMetaData.nextSiblingDirectoryOffset != -1)
|
||||||
|
throw new Exception("Offset of next Sibling Directory is incorrect. Expected -1 for root, received value is "+ rootDirectoryMetaData.nextSiblingDirectoryOffset);
|
||||||
|
if (rootDirectoryMetaData.firstSubdirectoryOffset != -1)
|
||||||
|
content.add(getDirectory(rootDirectoryMetaData.firstSubdirectoryOffset));
|
||||||
|
if (rootDirectoryMetaData.firstFileOffset != -1)
|
||||||
|
content.add(getFile(this, rootDirectoryMetaData.firstFileOffset));
|
||||||
|
content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileSystemEntry(){
|
||||||
|
this.content = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileSystemEntry getDirectory(int childDirMetaPosition){
|
||||||
|
FileSystemEntry fileSystemEntry = new FileSystemEntry();
|
||||||
|
fileSystemEntry.directoryFlag = true;
|
||||||
|
|
||||||
|
DirectoryMetaData directoryMetaData = new DirectoryMetaData(childDirMetaPosition);
|
||||||
|
fileSystemEntry.name = directoryMetaData.dirName;
|
||||||
|
|
||||||
|
if (directoryMetaData.nextSiblingDirectoryOffset != -1)
|
||||||
|
this.content.add(getDirectory(directoryMetaData.nextSiblingDirectoryOffset));
|
||||||
|
|
||||||
|
if (directoryMetaData.firstSubdirectoryOffset != -1)
|
||||||
|
fileSystemEntry.content.add(getDirectory(directoryMetaData.firstSubdirectoryOffset));
|
||||||
|
|
||||||
|
if (directoryMetaData.firstFileOffset != -1)
|
||||||
|
fileSystemEntry.content.add(getFile(fileSystemEntry, directoryMetaData.firstFileOffset));
|
||||||
|
|
||||||
|
fileSystemEntry.content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
||||||
|
|
||||||
|
return fileSystemEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileSystemEntry getFile(FileSystemEntry directoryContainer, int childFileMetaPosition){
|
||||||
|
FileSystemEntry fileSystemEntry = new FileSystemEntry();
|
||||||
|
fileSystemEntry.directoryFlag = false;
|
||||||
|
|
||||||
|
FileMetaData fileMetaData = new FileMetaData(childFileMetaPosition);
|
||||||
|
fileSystemEntry.name = fileMetaData.fileName;
|
||||||
|
fileSystemEntry.fileOffset = fileMetaData.fileDataRealOffset;
|
||||||
|
fileSystemEntry.fileSize = fileMetaData.fileDataRealLength;
|
||||||
|
if (fileMetaData.nextSiblingFileOffset != -1)
|
||||||
|
directoryContainer.content.add( getFile(directoryContainer, fileMetaData.nextSiblingFileOffset) );
|
||||||
|
|
||||||
|
return fileSystemEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDirectory() { return directoryFlag; }
|
||||||
|
public boolean isFile() { return ! directoryFlag; }
|
||||||
|
public long getFileOffset() { return fileOffset; }
|
||||||
|
public long getFileSize() { return fileSize; }
|
||||||
|
public List<FileSystemEntry> getContent() { return content; }
|
||||||
|
public String getName(){ return name; }
|
||||||
|
|
||||||
|
|
||||||
|
private static class DirectoryMetaData {
|
||||||
|
private int parentDirectoryOffset;
|
||||||
|
private int nextSiblingDirectoryOffset;
|
||||||
|
private int firstSubdirectoryOffset;
|
||||||
|
private int firstFileOffset;
|
||||||
|
|
||||||
|
private String dirName;
|
||||||
|
|
||||||
|
private DirectoryMetaData(){
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
private DirectoryMetaData(int childDirMetaPosition){
|
||||||
|
int i = childDirMetaPosition;
|
||||||
|
parentDirectoryOffset = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
nextSiblingDirectoryOffset = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
firstSubdirectoryOffset = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
firstFileOffset = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
// int nextHashTableBucketDirectoryOffset = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
int dirNameLength = LoperConverter.getLEint(dirsMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
dirName = new String(Arrays.copyOfRange(dirsMetadataTable, i, i + dirNameLength), StandardCharsets.UTF_8);
|
||||||
|
//i += getRealNameSize(dirNameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRealNameSize(int value){
|
||||||
|
if (value % 4 == 0)
|
||||||
|
return value;
|
||||||
|
return value + 4 - value % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class FileMetaData {
|
||||||
|
|
||||||
|
private int nextSiblingFileOffset;
|
||||||
|
private long fileDataRealOffset;
|
||||||
|
private long fileDataRealLength;
|
||||||
|
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
private FileMetaData(){
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileMetaData(int childFileMetaPosition){
|
||||||
|
int i = childFileMetaPosition;
|
||||||
|
// int containingDirectoryOffset = LoperConverter.getLEint(filesMetadataTable, i); // never used
|
||||||
|
i += 4;
|
||||||
|
nextSiblingFileOffset = LoperConverter.getLEint(filesMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileDataRealOffset = LoperConverter.getLElong(filesMetadataTable, i);
|
||||||
|
i += 8;
|
||||||
|
fileDataRealLength = LoperConverter.getLElong(filesMetadataTable, i);
|
||||||
|
i += 8;
|
||||||
|
//int nextHashTableBucketFileOffset = LoperConverter.getLEint(filesMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
int fileNameLength = LoperConverter.getLEint(filesMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
fileName = new String(Arrays.copyOfRange(filesMetadataTable, i, i + fileNameLength), StandardCharsets.UTF_8);;
|
||||||
|
//i += getRealNameSize(fileNameLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printTreeForDebug(){
|
||||||
|
System.out.println("/");
|
||||||
|
for (FileSystemEntry entry: content)
|
||||||
|
printEntry(2, entry);
|
||||||
|
}
|
||||||
|
private void printEntry(int cnt, FileSystemEntry entry) {
|
||||||
|
for (int i = 0; i < cnt; i++)
|
||||||
|
System.out.print(" ");
|
||||||
|
|
||||||
|
if (entry.isDirectory()){
|
||||||
|
System.out.println("|-" + entry.getName());
|
||||||
|
for (FileSystemEntry e : entry.content)
|
||||||
|
printEntry(cnt+2, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
System.out.println("|-" + entry.getName() + String.format(" 0x%-10x 0x%-10x", entry.fileOffset, entry.fileSize));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
/*
|
|
||||||
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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
85
src/main/java/konogonka/Tools/RomFs/FolderMeta4Debug.java
Normal file
85
src/main/java/konogonka/Tools/RomFs/FolderMeta4Debug.java
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package konogonka.Tools.RomFs;
|
||||||
|
|
||||||
|
import konogonka.LoperConverter;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static konogonka.RainbowDump.formatDecHexString;
|
||||||
|
|
||||||
|
public class FolderMeta4Debug {
|
||||||
|
|
||||||
|
List<FolderMeta> allFolders;
|
||||||
|
|
||||||
|
FolderMeta4Debug(long directoryMetadataTableLength, byte[] directoryMetadataTable){
|
||||||
|
allFolders = new ArrayList<>();
|
||||||
|
int i = 0;
|
||||||
|
while (i < directoryMetadataTableLength){
|
||||||
|
FolderMeta folderMeta = new FolderMeta();
|
||||||
|
folderMeta.parentDirectoryOffset = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.nextSiblingDirectoryOffset = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.firstSubdirectoryOffset = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.firstFileOffset = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.nextDirectoryOffset = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.dirNameLength = LoperConverter.getLEint(directoryMetadataTable, i);
|
||||||
|
i += 4;
|
||||||
|
folderMeta.dirName = new String(Arrays.copyOfRange(directoryMetadataTable, i, i + folderMeta.dirNameLength), StandardCharsets.UTF_8);
|
||||||
|
i += getRealNameSize(folderMeta.dirNameLength);
|
||||||
|
|
||||||
|
allFolders.add(folderMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FolderMeta headersDirectory : allFolders)
|
||||||
|
System.out.println(
|
||||||
|
"---------------------------DIRECTORY------------------------\n" +
|
||||||
|
"Offset of Parent Directory (self if Root) " + formatDecHexString(headersDirectory.parentDirectoryOffset ) +"\n" +
|
||||||
|
"Offset of next Sibling Directory " + formatDecHexString(headersDirectory.nextSiblingDirectoryOffset) +"\n" +
|
||||||
|
"Offset of first Child Directory (Subdirectory) " + formatDecHexString(headersDirectory.firstSubdirectoryOffset ) +"\n" +
|
||||||
|
"Offset of first File (in File Metadata Table) " + formatDecHexString(headersDirectory.firstFileOffset ) +"\n" +
|
||||||
|
"Offset of next Directory in the same Hash Table bucket " + formatDecHexString(headersDirectory.nextDirectoryOffset ) +"\n" +
|
||||||
|
"Name Length " + formatDecHexString(headersDirectory.dirNameLength ) +"\n" +
|
||||||
|
"Name Length (rounded up to multiple of 4) " + headersDirectory.dirName + "\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getRealNameSize(int value){
|
||||||
|
if (value % 4 == 0)
|
||||||
|
return value;
|
||||||
|
return value + 4 - value % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FolderMeta {
|
||||||
|
int parentDirectoryOffset;
|
||||||
|
int nextSiblingDirectoryOffset;
|
||||||
|
int firstSubdirectoryOffset;
|
||||||
|
int firstFileOffset;
|
||||||
|
int nextDirectoryOffset;
|
||||||
|
int dirNameLength;
|
||||||
|
String dirName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,49 +20,34 @@
|
||||||
package konogonka.Tools.RomFs;
|
package konogonka.Tools.RomFs;
|
||||||
|
|
||||||
import konogonka.LoperConverter;
|
import konogonka.LoperConverter;
|
||||||
import konogonka.RainbowDump;
|
|
||||||
|
|
||||||
public class Level6Header {
|
public class Level6Header {
|
||||||
private long headerHeaderLength;
|
private long headerLength;
|
||||||
private long headerDirectoryHashTableOffset;
|
private long directoryHashTableOffset;
|
||||||
private long headerDirectoryHashTableLength;
|
private long directoryHashTableLength;
|
||||||
private long headerDirectoryMetadataTableOffset;
|
private long directoryMetadataTableOffset;
|
||||||
private long headerDirectoryMetadataTableLength;
|
private long directoryMetadataTableLength;
|
||||||
private long headerFileHashTableOffset;
|
private long fileHashTableOffset;
|
||||||
private long headerFileHashTableLength;
|
private long fileHashTableLength;
|
||||||
private long headerFileMetadataTableOffset;
|
private long fileMetadataTableOffset;
|
||||||
private long headerFileMetadataTableLength;
|
private long fileMetadataTableLength;
|
||||||
private long headerFileDataOffset;
|
private long fileDataOffset;
|
||||||
|
|
||||||
private byte[] headerBytes;
|
private byte[] headerBytes;
|
||||||
private int i;
|
private int i;
|
||||||
|
|
||||||
Level6Header(byte[] headerBytes){
|
Level6Header(byte[] headerBytes){
|
||||||
this.headerBytes = headerBytes;
|
this.headerBytes = headerBytes;
|
||||||
headerHeaderLength = getNext();
|
headerLength = getNext();
|
||||||
headerDirectoryHashTableOffset = getNext();
|
directoryHashTableOffset = getNext();
|
||||||
headerDirectoryHashTableLength = getNext();
|
directoryHashTableLength = getNext();
|
||||||
headerDirectoryMetadataTableOffset = getNext();
|
directoryMetadataTableOffset = getNext();
|
||||||
headerDirectoryMetadataTableLength = getNext();
|
directoryMetadataTableLength = getNext();
|
||||||
headerFileHashTableOffset = getNext();
|
fileHashTableOffset = getNext();
|
||||||
headerFileHashTableLength = getNext();
|
fileHashTableLength = getNext();
|
||||||
headerFileMetadataTableOffset = getNext();
|
fileMetadataTableOffset = getNext();
|
||||||
headerFileMetadataTableLength = getNext();
|
fileMetadataTableLength = getNext();
|
||||||
headerFileDataOffset = getNext();
|
fileDataOffset = getNext();
|
||||||
|
|
||||||
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" +
|
|
||||||
"-------------------------------------------------------------"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getNext(){
|
private long getNext(){
|
||||||
|
@ -71,14 +56,14 @@ public class Level6Header {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getHeaderHeaderLength() { return headerHeaderLength; }
|
public long getHeaderLength() { return headerLength; }
|
||||||
public long getHeaderDirectoryHashTableOffset() { return headerDirectoryHashTableOffset; }
|
public long getDirectoryHashTableOffset() { return directoryHashTableOffset; }
|
||||||
public long getHeaderDirectoryHashTableLength() { return headerDirectoryHashTableLength; }
|
public long getDirectoryHashTableLength() { return directoryHashTableLength; }
|
||||||
public long getHeaderDirectoryMetadataTableOffset() { return headerDirectoryMetadataTableOffset; }
|
public long getDirectoryMetadataTableOffset() { return directoryMetadataTableOffset; }
|
||||||
public long getHeaderDirectoryMetadataTableLength() { return headerDirectoryMetadataTableLength; }
|
public long getDirectoryMetadataTableLength() { return directoryMetadataTableLength; }
|
||||||
public long getHeaderFileHashTableOffset() { return headerFileHashTableOffset; }
|
public long getFileHashTableOffset() { return fileHashTableOffset; }
|
||||||
public long getHeaderFileHashTableLength() { return headerFileHashTableLength; }
|
public long getFileHashTableLength() { return fileHashTableLength; }
|
||||||
public long getHeaderFileMetadataTableOffset() { return headerFileMetadataTableOffset; }
|
public long getFileMetadataTableOffset() { return fileMetadataTableOffset; }
|
||||||
public long getHeaderFileMetadataTableLength() { return headerFileMetadataTableLength; }
|
public long getFileMetadataTableLength() { return fileMetadataTableLength; }
|
||||||
public long getHeaderFileDataOffset() { return headerFileDataOffset; }
|
public long getFileDataOffset() { return fileDataOffset; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,19 @@
|
||||||
|
|
||||||
package konogonka.Tools.RomFs;
|
package konogonka.Tools.RomFs;
|
||||||
|
|
||||||
|
import konogonka.LoperConverter;
|
||||||
import konogonka.Tools.ISuperProvider;
|
import konogonka.Tools.ISuperProvider;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.PipedInputStream;
|
import java.io.PipedInputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static konogonka.RainbowDump.formatDecHexString;
|
||||||
|
|
||||||
public class RomFsDecryptedProvider implements ISuperProvider {
|
public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
|
|
||||||
|
@ -33,12 +40,14 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
private File decryptedFSImage;
|
private File decryptedFSImage;
|
||||||
private Level6Header header;
|
private Level6Header header;
|
||||||
|
|
||||||
|
private FileSystemEntry rootEntry;
|
||||||
|
|
||||||
public RomFsDecryptedProvider(File decryptedFSImage) throws Exception{ // TODO: add default setup AND using meta-data headers from NCA RomFs section (?)
|
public RomFsDecryptedProvider(File decryptedFSImage) throws Exception{ // TODO: add default setup AND using meta-data headers from NCA RomFs section (?)
|
||||||
this.decryptedFSImage = decryptedFSImage;
|
this.decryptedFSImage = decryptedFSImage;
|
||||||
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(decryptedFSImage));
|
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(decryptedFSImage));
|
||||||
|
|
||||||
skipTo(bis, LEVEL_6_DEFAULT_OFFSET);
|
skipBytes(bis, LEVEL_6_DEFAULT_OFFSET);
|
||||||
|
|
||||||
byte[] rawDataChunk = new byte[0x50];
|
byte[] rawDataChunk = new byte[0x50];
|
||||||
|
|
||||||
|
@ -46,10 +55,52 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
throw new Exception("Failed to read header (0x50)");
|
throw new Exception("Failed to read header (0x50)");
|
||||||
|
|
||||||
this.header = new Level6Header(rawDataChunk);
|
this.header = new Level6Header(rawDataChunk);
|
||||||
|
/*
|
||||||
|
// Print Dir Hash table as is:
|
||||||
|
long seekTo = header.getDirectoryHashTableOffset() - 0x50;
|
||||||
|
rawDataChunk = new byte[(int) header.getDirectoryHashTableLength()];
|
||||||
|
skipTo(bis, seekTo);
|
||||||
|
if (bis.read(rawDataChunk) != (int) header.getDirectoryHashTableLength())
|
||||||
|
throw new Exception("Failed to read Dir hash table");
|
||||||
|
RainbowDump.hexDumpUTF8(rawDataChunk);
|
||||||
|
// Print Files Hash table as is:
|
||||||
|
seekTo = header.getFileHashTableOffset() - header.getDirectoryMetadataTableOffset();
|
||||||
|
rawDataChunk = new byte[(int) header.getFileHashTableLength()];
|
||||||
|
skipTo(bis, seekTo);
|
||||||
|
if (bis.read(rawDataChunk) != (int) header.getFileHashTableLength())
|
||||||
|
throw new Exception("Failed to read Files hash table");
|
||||||
|
RainbowDump.hexDumpUTF8(rawDataChunk);
|
||||||
|
*/
|
||||||
|
// Read directories metadata
|
||||||
|
long locationInFile = header.getDirectoryMetadataTableOffset() - 0x50;
|
||||||
|
|
||||||
|
skipBytes(bis, locationInFile);
|
||||||
|
|
||||||
|
if (header.getDirectoryMetadataTableLength() < 0)
|
||||||
|
throw new Exception("Not supported operation.");
|
||||||
|
|
||||||
|
byte[] directoryMetadataTable = new byte[(int) header.getDirectoryMetadataTableLength()];
|
||||||
|
|
||||||
|
if (bis.read(directoryMetadataTable) != (int) header.getDirectoryMetadataTableLength())
|
||||||
|
throw new Exception("Failed to read "+header.getDirectoryMetadataTableLength());
|
||||||
|
// Read files metadata
|
||||||
|
locationInFile = header.getFileMetadataTableOffset() - header.getFileHashTableOffset(); // TODO: replace to 'CurrentPosition'?
|
||||||
|
|
||||||
|
skipBytes(bis, locationInFile);
|
||||||
|
|
||||||
|
if (header.getFileMetadataTableLength() < 0)
|
||||||
|
throw new Exception("Not supported operation.");
|
||||||
|
|
||||||
|
byte[] fileMetadataTable = new byte[(int) header.getFileMetadataTableLength()];
|
||||||
|
|
||||||
|
if (bis.read(fileMetadataTable) != (int) header.getFileMetadataTableLength())
|
||||||
|
throw new Exception("Failed to read "+header.getFileMetadataTableLength());
|
||||||
|
|
||||||
|
rootEntry = new FileSystemEntry(directoryMetadataTable, fileMetadataTable);
|
||||||
|
//printDebug(directoryMetadataTable, fileMetadataTable);
|
||||||
bis.close();
|
bis.close();
|
||||||
}
|
}
|
||||||
private void skipTo(BufferedInputStream bis, long size) throws Exception{
|
private void skipBytes(BufferedInputStream bis, long size) throws Exception{
|
||||||
long mustSkip = size;
|
long mustSkip = size;
|
||||||
long skipped = 0;
|
long skipped = 0;
|
||||||
while (mustSkip > 0){
|
while (mustSkip > 0){
|
||||||
|
@ -57,13 +108,9 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
mustSkip = size - skipped;
|
mustSkip = size - skipped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private int getRealNameSize(int value){
|
|
||||||
if (value % 4 == 0)
|
|
||||||
return value;
|
|
||||||
return value + 4 - value % 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Level6Header getHeader() { return header; }
|
public Level6Header getHeader() { return header; }
|
||||||
|
public FileSystemEntry getRootEntry() { return rootEntry; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception {
|
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception {
|
||||||
|
@ -72,7 +119,7 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception {
|
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception {
|
||||||
return null;
|
throw new Exception("RomFsDecryptedProvider -> getProviderSubFilePipedInpStream(): Get files by number is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,4 +131,10 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
||||||
public long getRawFileDataStart() {
|
public long getRawFileDataStart() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void printDebug(byte[] directoryMetadataTable, byte[] fileMetadataTable){
|
||||||
|
new FolderMeta4Debug(header.getDirectoryMetadataTableLength(), directoryMetadataTable);
|
||||||
|
new FileMeta4Debug(header.getFileMetadataTableLength(), fileMetadataTable);
|
||||||
|
rootEntry.printTreeForDebug();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,25 @@
|
||||||
<?import javafx.scene.control.TableView?>
|
<?import javafx.scene.control.TableView?>
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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 <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NSP.Pfs0TableViewController">
|
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NSP.Pfs0TableViewController">
|
||||||
<children>
|
<children>
|
||||||
<TableView fx:id="table" editable="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
<TableView fx:id="table" editable="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||||
|
|
|
@ -1,15 +1,366 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.SplitPane?>
|
<?import javafx.scene.control.SplitPane?>
|
||||||
|
<?import javafx.scene.control.TitledPane?>
|
||||||
<?import javafx.scene.control.TreeView?>
|
<?import javafx.scene.control.TreeView?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.scene.text.Font?>
|
||||||
|
|
||||||
<SplitPane dividerPositions="0.2" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.RFS.RomFsController">
|
<VBox spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.RFS.RomFsController">
|
||||||
<items>
|
<children>
|
||||||
<TreeView fx:id="filesTreeView" />
|
<TitledPane animated="false" expanded="false" text="Header (Level 6)">
|
||||||
<VBox fx:id="folderContentVBox">
|
<content>
|
||||||
|
<GridPane gridLinesVisible="true">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="60.0" minWidth="55.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="250.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
<RowConstraints maxHeight="30.0" minHeight="30.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||||
|
</rowConstraints>
|
||||||
|
<children>
|
||||||
|
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="1">
|
||||||
|
<children>
|
||||||
|
<Label layoutX="38.0" layoutY="6.0" text="Size" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="2">
|
||||||
|
<children>
|
||||||
|
<Label layoutX="14.0" layoutY="7.0" text="Description" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="3">
|
||||||
|
<children>
|
||||||
|
<Label layoutY="6.0" text="Value Dec" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<AnchorPane styleClass="customTitleGrid">
|
||||||
|
<children>
|
||||||
|
<Label layoutX="2.0" layoutY="7.0" text="Offset" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<Label text="Directory Metadata Table Length" GridPane.columnIndex="2" GridPane.rowIndex="5">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="Directory Metadata Table Offset" GridPane.columnIndex="2" GridPane.rowIndex="4">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="File Hash Table Offset" GridPane.columnIndex="2" GridPane.rowIndex="6">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="File Hash Table Length" GridPane.columnIndex="2" GridPane.rowIndex="7">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="File Metadata Table Offset" GridPane.columnIndex="2" GridPane.rowIndex="8">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="File Metadata Table Length" GridPane.columnIndex="2" GridPane.rowIndex="9">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="File Data Offset" GridPane.columnIndex="2" GridPane.rowIndex="10">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.rowIndex="2">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x0" GridPane.rowIndex="1">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerHeaderLengthLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="1">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="Header Length (always 0x50 ?)" GridPane.columnIndex="2" GridPane.rowIndex="1">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="Directory Hash Table Offset" GridPane.columnIndex="2" GridPane.rowIndex="2">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="Directory Hash Table Length" GridPane.columnIndex="2" GridPane.rowIndex="3">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="2">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x10" GridPane.rowIndex="3">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="3">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x18" GridPane.rowIndex="4">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="4">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x20" GridPane.rowIndex="5">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="5">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x28" GridPane.rowIndex="6">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="6">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x30" GridPane.rowIndex="7">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="7">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x38" GridPane.rowIndex="8">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="8">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x40" GridPane.rowIndex="9">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="9">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x48" GridPane.rowIndex="10">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label text="0x8" GridPane.columnIndex="1" GridPane.rowIndex="10">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryHashTableOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="2">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryHashTableLengthLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="3">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryMetadataTableOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="4">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileHashTableOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="6">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryMetadataTableLengthLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="5">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileHashTableLengthLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="7">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileMetadataTableOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="8">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileMetadataTableLengthLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="9">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileDataOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="10">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<AnchorPane styleClass="customTitleGrid" GridPane.columnIndex="4">
|
||||||
|
<children>
|
||||||
|
<Label layoutY="6.0" text="Value Hex" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
|
<font>
|
||||||
|
<Font name="System Bold" size="13.0" />
|
||||||
|
</font>
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
||||||
|
<Label fx:id="headerHeaderLengthHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="1">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryHashTableOffsetHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="2">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryHashTableLengthHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="3">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryMetadataTableOffsetHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="4">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerDirectoryMetadataTableLengthHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="5">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileHashTableOffsetHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="6">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileHashTableLengthHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="7">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileMetadataTableOffsetHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="8">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileMetadataTableLengthHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="9">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
<Label fx:id="headerFileDataOffsetHexLbl" text="-" GridPane.columnIndex="4" GridPane.rowIndex="10">
|
||||||
|
<padding>
|
||||||
|
<Insets left="5.0" right="5.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</GridPane>
|
||||||
|
</content>
|
||||||
|
</TitledPane>
|
||||||
|
<SplitPane dividerPositions="0.2" VBox.vgrow="ALWAYS">
|
||||||
|
<items>
|
||||||
|
<TreeView fx:id="filesTreeView" />
|
||||||
|
<fx:include fx:id="RFSTableView" source="RFSTableView.fxml" />
|
||||||
|
</items>
|
||||||
|
|
||||||
</VBox>
|
</SplitPane>
|
||||||
</items>
|
</children>
|
||||||
|
<padding>
|
||||||
</SplitPane>
|
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
|
||||||
|
</padding>
|
||||||
|
</VBox>
|
||||||
|
|
29
src/main/resources/FXML/RomFS/RFSTableView.fxml
Normal file
29
src/main/resources/FXML/RomFS/RFSTableView.fxml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.TableView?>
|
||||||
|
<?import javafx.scene.layout.AnchorPane?>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
~ 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 <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<AnchorPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.RFS.RFSFolderTableViewController">
|
||||||
|
<children>
|
||||||
|
<TableView fx:id="table" editable="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||||
|
</children>
|
||||||
|
</AnchorPane>
|
|
@ -43,7 +43,7 @@
|
||||||
</Button>
|
</Button>
|
||||||
</items>
|
</items>
|
||||||
</ToolBar>
|
</ToolBar>
|
||||||
<SplitPane fx:id="splitPane" dividerPositions="0.5" VBox.vgrow="ALWAYS">
|
<SplitPane fx:id="splitPane" onDragDropped="#handleDrop" onDragOver="#handleDragOver" dividerPositions="0.5" VBox.vgrow="ALWAYS">
|
||||||
<items>
|
<items>
|
||||||
<TabPane fx:id="tabPane" side="LEFT" tabClosingPolicy="UNAVAILABLE" tabMinHeight="35.0" tabMinWidth="25.0">
|
<TabPane fx:id="tabPane" side="LEFT" tabClosingPolicy="UNAVAILABLE" tabMinHeight="35.0" tabMinWidth="25.0">
|
||||||
<tabs>
|
<tabs>
|
||||||
|
|
|
@ -434,3 +434,9 @@
|
||||||
-fx-min-height: 17.0;
|
-fx-min-height: 17.0;
|
||||||
-fx-min-width: 17.5;
|
-fx-min-width: 17.5;
|
||||||
}
|
}
|
||||||
|
.regionFile {
|
||||||
|
-fx-shape: "M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z";
|
||||||
|
-fx-background-color: #e54d1e;
|
||||||
|
-fx-min-height: 17.0;
|
||||||
|
-fx-min-width: 13;
|
||||||
|
}
|
Loading…
Reference in a new issue