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>
|
||||
|
||||
<artifactId>konogonka</artifactId>
|
||||
<version>0.0.2-SNAPSHOT</version>
|
||||
<version>0.0.3-SNAPSHOT</version>
|
||||
|
||||
<url>https://github.com/developersu/${project.name}}/</url>
|
||||
<description>
|
||||
|
|
|
@ -21,6 +21,8 @@ package konogonka.Controllers;
|
|||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import konogonka.AppPreferences;
|
||||
|
@ -35,10 +37,10 @@ import konogonka.Controllers.XML.XMLController;
|
|||
import konogonka.MediatorControl;
|
||||
import konogonka.Settings.SettingsWindow;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.TIK.TIKProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class MainController implements Initializable {
|
||||
|
@ -187,6 +189,21 @@ public class MainController implements Initializable {
|
|||
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
|
||||
private void showHideLogs(){
|
||||
if (splitPane.getItems().size() == 2)
|
||||
|
@ -194,6 +211,50 @@ public class MainController implements Initializable {
|
|||
else
|
||||
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){
|
||||
try{
|
||||
new ChildWindow(provider, model);
|
||||
|
|
|
@ -18,11 +18,8 @@
|
|||
*/
|
||||
package konogonka.Controllers.NSP;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
|
@ -35,8 +32,6 @@ import javafx.scene.control.cell.PropertyValueFactory;
|
|||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
@ -44,7 +39,6 @@ import konogonka.Tools.PFS0.IPFS0Provider;
|
|||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
@ -82,13 +76,13 @@ public class Pfs0TableViewController implements Initializable {
|
|||
TableColumn<Pfs0RowModel, String> fileNameColumn = new TableColumn<>(resourceBundle.getString("tableFileNameLbl"));
|
||||
TableColumn<Pfs0RowModel, Long> fileOffsetColumn = new TableColumn<>(resourceBundle.getString("tableOffsetLbl"));
|
||||
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);
|
||||
fileNameColumn.setEditable(false);
|
||||
fileOffsetColumn.setEditable(false);
|
||||
fileSizeColumn.setEditable(false);
|
||||
uploadColumn.setEditable(true);
|
||||
checkBoxColumn.setEditable(true);
|
||||
|
||||
// See https://bugs.openjdk.java.net/browse/JDK-8157687
|
||||
numberColumn.setMinWidth(30.0);
|
||||
|
@ -108,17 +102,17 @@ public class Pfs0TableViewController implements Initializable {
|
|||
fileSizeColumn.setMaxWidth(120.0);
|
||||
fileSizeColumn.setResizable(false);
|
||||
|
||||
uploadColumn.setMinWidth(120.0);
|
||||
uploadColumn.setPrefWidth(120.0);
|
||||
uploadColumn.setMaxWidth(120.0);
|
||||
uploadColumn.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"));
|
||||
// ><
|
||||
uploadColumn.setCellValueFactory(paramFeatures -> {
|
||||
checkBoxColumn.setCellValueFactory(paramFeatures -> {
|
||||
Pfs0RowModel model = paramFeatures.getValue();
|
||||
|
||||
SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(model.isMarkSelected());
|
||||
|
@ -130,7 +124,7 @@ public class Pfs0TableViewController implements Initializable {
|
|||
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..
|
||||
Pfs0RowModelTableView -> {
|
||||
final TableRow<Pfs0RowModel> row = new TableRow<>();
|
||||
|
@ -167,6 +161,7 @@ public class Pfs0TableViewController implements Initializable {
|
|||
table.getColumns().add(fileNameColumn);
|
||||
table.getColumns().add(fileOffsetColumn);
|
||||
table.getColumns().add(fileSizeColumn);
|
||||
table.getColumns().add(checkBoxColumn);
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TreeItem;
|
||||
import javafx.scene.control.TreeView;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.ITabController;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.RomFs.FileSystemEntry;
|
||||
import konogonka.Tools.RomFs.Level6Header;
|
||||
import konogonka.Tools.RomFs.RomFsDecryptedProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -34,20 +36,48 @@ import java.util.ResourceBundle;
|
|||
public class RomFsController implements ITabController {
|
||||
|
||||
@FXML
|
||||
private TreeView<RFSFolderEntry> filesTreeView;
|
||||
private Label headerHeaderLengthLbl,
|
||||
headerDirectoryHashTableOffsetLbl,
|
||||
headerDirectoryHashTableLengthLbl,
|
||||
headerDirectoryMetadataTableOffsetLbl,
|
||||
headerDirectoryMetadataTableLengthLbl,
|
||||
headerFileHashTableOffsetLbl,
|
||||
headerFileHashTableLengthLbl,
|
||||
headerFileMetadataTableOffsetLbl,
|
||||
headerFileMetadataTableLengthLbl,
|
||||
headerFileDataOffsetLbl;
|
||||
@FXML
|
||||
private VBox folderContentVBox;
|
||||
private Label headerHeaderLengthHexLbl,
|
||||
headerDirectoryHashTableOffsetHexLbl,
|
||||
headerDirectoryHashTableLengthHexLbl,
|
||||
headerDirectoryMetadataTableOffsetHexLbl,
|
||||
headerDirectoryMetadataTableLengthHexLbl,
|
||||
headerFileHashTableOffsetHexLbl,
|
||||
headerFileHashTableLengthHexLbl,
|
||||
headerFileMetadataTableOffsetHexLbl,
|
||||
headerFileMetadataTableLengthHexLbl,
|
||||
headerFileDataOffsetHexLbl;
|
||||
|
||||
@FXML
|
||||
private TreeView<RFSEntry> filesTreeView;
|
||||
|
||||
private RomFsDecryptedProvider RomFsProvider;
|
||||
|
||||
@FXML
|
||||
private RFSFolderTableViewController RFSTableViewController;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
TreeItem<RFSFolderEntry> rootTest = getEmptyRoot();
|
||||
TreeItem<RFSFolderEntry> test = new TreeItem<>(new RFSFolderEntry("WIP"), getFolderImage());
|
||||
filesTreeView.setOnMouseClicked(mouseEvent -> {
|
||||
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
|
||||
|
@ -59,22 +89,96 @@ public class RomFsController implements ITabController {
|
|||
public void analyze(File file, long offset) {
|
||||
try {
|
||||
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
|
||||
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
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
|
||||
throw new Exception("NOT IMPLEMENTED: analyze(ISuperProvider parentProvider, int fileNo)");
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -83,8 +187,13 @@ public class RomFsController implements ITabController {
|
|||
folderImage.getStyleClass().add("regionFolder");
|
||||
return folderImage;
|
||||
}
|
||||
private Region getFileImage(){
|
||||
final Region folderImage = new Region();
|
||||
folderImage.getStyleClass().add("regionFile");
|
||||
return folderImage;
|
||||
}
|
||||
|
||||
private TreeItem<RFSFolderEntry> getEmptyRoot(){
|
||||
return new TreeItem<>(new RFSFolderEntry("/"));
|
||||
private String getHexString(long value){
|
||||
return String.format("0x%x", value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,9 +87,9 @@ public class TIKController implements ITabController {
|
|||
}
|
||||
@Override
|
||||
public void analyze(File file, long offset) {
|
||||
Task analyzer = Analyzer.analyzeTIK(file, offset);
|
||||
Task<TIKProvider> analyzer = Analyzer.analyzeTIK(file, offset);
|
||||
analyzer.setOnSucceeded(e->{
|
||||
TIKProvider tik = (TIKProvider) analyzer.getValue();
|
||||
TIKProvider tik = analyzer.getValue();
|
||||
if (offset == 0)
|
||||
setData(tik, file);
|
||||
else
|
||||
|
|
|
@ -42,12 +42,8 @@ import konogonka.Tools.ISuperProvider;
|
|||
import konogonka.Tools.XCI.HFS0Provider;
|
||||
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.net.URL;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.util.Locale;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
public class MainFx extends Application {
|
||||
public static final String appVersion = "v0.0.2";
|
||||
public static final String appVersion = "v0.0.3";
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
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;
|
||||
private long headerLength;
|
||||
private long directoryHashTableOffset;
|
||||
private long directoryHashTableLength;
|
||||
private long directoryMetadataTableOffset;
|
||||
private long directoryMetadataTableLength;
|
||||
private long fileHashTableOffset;
|
||||
private long fileHashTableLength;
|
||||
private long fileMetadataTableOffset;
|
||||
private long fileMetadataTableLength;
|
||||
private long fileDataOffset;
|
||||
|
||||
private byte[] headerBytes;
|
||||
private int i;
|
||||
|
||||
Level6Header(byte[] headerBytes){
|
||||
this.headerBytes = headerBytes;
|
||||
headerHeaderLength = getNext();
|
||||
headerDirectoryHashTableOffset = getNext();
|
||||
headerDirectoryHashTableLength = getNext();
|
||||
headerDirectoryMetadataTableOffset = getNext();
|
||||
headerDirectoryMetadataTableLength = getNext();
|
||||
headerFileHashTableOffset = getNext();
|
||||
headerFileHashTableLength = getNext();
|
||||
headerFileMetadataTableOffset = getNext();
|
||||
headerFileMetadataTableLength = getNext();
|
||||
headerFileDataOffset = 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" +
|
||||
"-------------------------------------------------------------"
|
||||
);
|
||||
headerLength = getNext();
|
||||
directoryHashTableOffset = getNext();
|
||||
directoryHashTableLength = getNext();
|
||||
directoryMetadataTableOffset = getNext();
|
||||
directoryMetadataTableLength = getNext();
|
||||
fileHashTableOffset = getNext();
|
||||
fileHashTableLength = getNext();
|
||||
fileMetadataTableOffset = getNext();
|
||||
fileMetadataTableLength = getNext();
|
||||
fileDataOffset = getNext();
|
||||
}
|
||||
|
||||
private long getNext(){
|
||||
|
@ -71,14 +56,14 @@ public class Level6Header {
|
|||
return result;
|
||||
}
|
||||
|
||||
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; }
|
||||
public long getHeaderLength() { return headerLength; }
|
||||
public long getDirectoryHashTableOffset() { return directoryHashTableOffset; }
|
||||
public long getDirectoryHashTableLength() { return directoryHashTableLength; }
|
||||
public long getDirectoryMetadataTableOffset() { return directoryMetadataTableOffset; }
|
||||
public long getDirectoryMetadataTableLength() { return directoryMetadataTableLength; }
|
||||
public long getFileHashTableOffset() { return fileHashTableOffset; }
|
||||
public long getFileHashTableLength() { return fileHashTableLength; }
|
||||
public long getFileMetadataTableOffset() { return fileMetadataTableOffset; }
|
||||
public long getFileMetadataTableLength() { return fileMetadataTableLength; }
|
||||
public long getFileDataOffset() { return fileDataOffset; }
|
||||
}
|
||||
|
|
|
@ -19,12 +19,19 @@
|
|||
|
||||
package konogonka.Tools.RomFs;
|
||||
|
||||
import konogonka.LoperConverter;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
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 {
|
||||
|
||||
|
@ -33,12 +40,14 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
|||
private File decryptedFSImage;
|
||||
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 (?)
|
||||
this.decryptedFSImage = 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];
|
||||
|
||||
|
@ -46,10 +55,52 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
|||
throw new Exception("Failed to read header (0x50)");
|
||||
|
||||
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();
|
||||
}
|
||||
private void skipTo(BufferedInputStream bis, long size) throws Exception{
|
||||
private void skipBytes(BufferedInputStream bis, long size) throws Exception{
|
||||
long mustSkip = size;
|
||||
long skipped = 0;
|
||||
while (mustSkip > 0){
|
||||
|
@ -57,13 +108,9 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
|||
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 FileSystemEntry getRootEntry() { return rootEntry; }
|
||||
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception {
|
||||
|
@ -72,7 +119,7 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
|||
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception {
|
||||
return null;
|
||||
throw new Exception("RomFsDecryptedProvider -> getProviderSubFilePipedInpStream(): Get files by number is not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -84,4 +131,10 @@ public class RomFsDecryptedProvider implements ISuperProvider {
|
|||
public long getRawFileDataStart() {
|
||||
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.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">
|
||||
<children>
|
||||
<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"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.SplitPane?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?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.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">
|
||||
<children>
|
||||
<TitledPane animated="false" expanded="false" text="Header (Level 6)">
|
||||
<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" />
|
||||
<VBox fx:id="folderContentVBox">
|
||||
|
||||
</VBox>
|
||||
<fx:include fx:id="RFSTableView" source="RFSTableView.fxml" />
|
||||
</items>
|
||||
|
||||
</SplitPane>
|
||||
</SplitPane>
|
||||
</children>
|
||||
<padding>
|
||||
<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>
|
||||
</items>
|
||||
</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>
|
||||
<TabPane fx:id="tabPane" side="LEFT" tabClosingPolicy="UNAVAILABLE" tabMinHeight="35.0" tabMinWidth="25.0">
|
||||
<tabs>
|
||||
|
|
|
@ -434,3 +434,9 @@
|
|||
-fx-min-height: 17.0;
|
||||
-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