Some notes for NPDM implementation

This commit is contained in:
Dmitry Isaenko 2019-08-22 05:57:52 +03:00
parent 02b49d9cb2
commit bd70a7db78
17 changed files with 719 additions and 15 deletions

View file

@ -1,6 +1,6 @@
# konogonka
Deep WIP multi-tool to work with XCI/NSP/NCA/NRO(?) files
Deep WIP multi-tool to work with NS-specific files / filesystem images.
### License
@ -24,5 +24,6 @@ JRE/JDK 8u60 or higher.
### Checklist
* [ ] LogPrinter to singleton implementation
* [ ] NPDM support
* [ ] CNMT support
* [ ] support
* [ ] NSO support

View file

@ -8,11 +8,11 @@
<name>konogonka</name>
<artifactId>konogonka</artifactId>
<version>0.1-SNAPSHOT</version>
<version>0.0-SNAPSHOT</version>
<url>https://github.com/developersu/${project.name}}/</url>
<description>
NSP and XCI multitool
NS filesystem multitool
</description>
<inceptionYear>2019</inceptionYear>
<organization>

View file

@ -8,6 +8,7 @@ import javafx.stage.FileChooser;
import konogonka.AppPreferences;
import konogonka.Child.ChildWindow;
import konogonka.Controllers.NCA.NCAController;
import konogonka.Controllers.NPDM.NPDMController;
import konogonka.Controllers.NSP.NSPController;
import konogonka.Controllers.TIK.TIKController;
import konogonka.Controllers.XCI.XCIController;
@ -50,6 +51,8 @@ public class MainController implements Initializable {
private TIKController TIKTabController;
@FXML
private XMLController XMLTabController;
@FXML
private NPDMController NPDMTabController;
private File selectedFile;
@ -83,7 +86,7 @@ public class MainController implements Initializable {
else
fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files", "*.nsp", "*.xci", "*.nca", "*.tik", "*.xml"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files", "*.nsp", "*.xci", "*.nca", "*.tik", "*.xml", "*.npdm"));
this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow());
@ -93,6 +96,7 @@ public class MainController implements Initializable {
NCATabController.resetTab();
TIKTabController.resetTab();
XMLTabController.resetTab();
NPDMTabController.resetTab();
if (this.selectedFile != null && this.selectedFile.exists()) {
filenameSelected.setText(this.selectedFile.getAbsolutePath());
@ -108,6 +112,8 @@ public class MainController implements Initializable {
tabPane.getSelectionModel().select(3);
else if (this.selectedFile.getName().toLowerCase().endsWith(".xml"))
tabPane.getSelectionModel().select(4);
else if (this.selectedFile.getName().toLowerCase().endsWith(".npdm"))
tabPane.getSelectionModel().select(5);
}
logArea.clear();
@ -126,6 +132,8 @@ public class MainController implements Initializable {
TIKTabController.analyze(selectedFile);
else if (selectedFile.getName().toLowerCase().endsWith("xml"))
XMLTabController.analyze(selectedFile);
else if (selectedFile.getName().toLowerCase().endsWith("npdm"))
NPDMTabController.analyze(selectedFile);
}
@FXML
private void showHideLogs(){

View file

@ -0,0 +1,4 @@
package konogonka.Controllers.NPDM;
public class ACI0Provider {
}

View file

@ -0,0 +1,4 @@
package konogonka.Controllers.NPDM;
public class ACIDProvider {
}

View file

@ -0,0 +1,110 @@
package konogonka.Controllers.NPDM;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import konogonka.Controllers.ITabController;
import konogonka.Tools.NPDM.NPDMProvider;
import konogonka.Workers.AnalyzerNPDM;
import java.io.File;
import java.net.URL;
import java.util.Locale;
import java.util.ResourceBundle;
import static konogonka.LoperConverter.byteArrToHexString;
public class NPDMController implements ITabController {
@FXML
private Label magicNumLbl,
reserved1Lbl,
MMUFlagsLbl,
reserved2Lbl,
mainThreadPrioLbl,
mainThreadCoreNumLbl,
reserved3Lbl,
personalMmHeapSizeLbl,
versionLbl,
mainThreadStackSizeLbl,
aci0offsetLbl,
aci0sizeLbl,
acidOffsetLbl,
acidSizeLbl,
npdmFileSize;
@FXML
private TextField titleNameTf,
productCodeTf,
reserved4Tf;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) { }
@Override
public void analyze(File file) { analyze(file, 0); }
@Override
public void analyze(File file, long offset) {
AnalyzerNPDM analyzerNPDM = new AnalyzerNPDM(file, offset);
analyzerNPDM.setOnSucceeded(e->{
NPDMProvider tik = analyzerNPDM.getValue();
if (offset == 0)
setData(tik, file);
else
setData(tik, null);
});
Thread workThread = new Thread(analyzerNPDM);
workThread.setDaemon(true);
workThread.start();
}
@Override
public void resetTab() {
magicNumLbl.setText("-");
reserved1Lbl.setText("-");
MMUFlagsLbl.setText("-");
reserved2Lbl.setText("-");
mainThreadPrioLbl.setText("-");
mainThreadCoreNumLbl.setText("-");
reserved3Lbl.setText("-");
personalMmHeapSizeLbl.setText("-");
versionLbl.setText("-");
mainThreadStackSizeLbl.setText("-");
aci0offsetLbl.setText("-");
aci0sizeLbl.setText("-");
acidOffsetLbl.setText("-");
acidSizeLbl.setText("-");
titleNameTf.setText("-");
productCodeTf.setText("-");
reserved4Tf.setText("-");
npdmFileSize.setText("-");
}
private void setData(NPDMProvider npdmProvider, File file) {
if (npdmProvider == null)
return;
if (file != null)
npdmFileSize.setText(Long.toString(file.length()));
else
npdmFileSize.setText("skipping calculation for in-file ticket");
magicNumLbl.setText(npdmProvider.getMagicNum());
reserved1Lbl.setText(byteArrToHexString(npdmProvider.getReserved1()));
MMUFlagsLbl.setText(npdmProvider.getMMUFlags()+" (0b"+String.format("%8s", Integer.toBinaryString(npdmProvider.getMMUFlags() & 0xFF)).replace(' ', '0')+")");
reserved2Lbl.setText(String.format("0x%02x", npdmProvider.getReserved2()));
mainThreadPrioLbl.setText(Byte.toString(npdmProvider.getMainThreadPrio()));
mainThreadCoreNumLbl.setText(Byte.toString(npdmProvider.getMainThreadCoreNum()));
reserved3Lbl.setText(byteArrToHexString(npdmProvider.getReserved3()));
personalMmHeapSizeLbl.setText(Integer.toString(npdmProvider.getPersonalMmHeapSize()));
versionLbl.setText(Integer.toString(npdmProvider.getVersion()));
mainThreadStackSizeLbl.setText(Long.toString(npdmProvider.getMainThreadStackSize()));
titleNameTf.setText(npdmProvider.getTitleName());
productCodeTf.setText(byteArrToHexString(npdmProvider.getProductCode()));
reserved4Tf.setText(byteArrToHexString(npdmProvider.getReserved4()));
aci0offsetLbl.setText(Long.toString(npdmProvider.getAci0offset()));
aci0sizeLbl.setText(Long.toString(npdmProvider.getAci0size()));
acidOffsetLbl.setText(Long.toString(npdmProvider.getAcidOffset()));
acidSizeLbl.setText(Long.toString(npdmProvider.getAcidSize()));
}
}

View file

@ -48,9 +48,7 @@ public class TIKController implements ITabController {
String key = rightsIdTf.getText();
String value = titleKeyBlockStartTf.getText();
int titleKeysCnt = AppPreferences.getInstance().getTitleKeysCount();
System.out.println(key+" "+value+" "+titleKeysCnt);
if (key.length() > 16 && ! (key.length() > 32) && value.length() == 32){
System.out.println("OK");
for (int i = 0; i < titleKeysCnt; i++){
if (AppPreferences.getInstance().getTitleKeyPair(i)[0].equals(key))
return;

View file

@ -51,7 +51,6 @@ public class XMLController implements ITabController {
* Read from offset to length
* */
public void analyze(File file, long offset, long fileSize) {
System.out.println(file.length()+" "+offset+" "+fileSize);
try {
if (fileSize > 10485760) // 10mB
throw new Exception("XMLController -> analyze(): File is too big. It must be something wrong with it. Usually they're smaller");

View file

@ -11,6 +11,17 @@ public class LoperConverter {
public static long getLElong(byte[] bytes, int fromOffset){
return ByteBuffer.wrap(bytes, fromOffset, 0x8).order(ByteOrder.LITTLE_ENDIAN).getLong();
}
/**
* Convert int to long. Workaround to store unsigned int
* @param bytes original array
* @param fromOffset start position of the 4-bytes value
* */
public static long getLElongOfInt(byte[] bytes, int fromOffset){
final byte[] holder = new byte[8];
System.arraycopy(bytes, fromOffset, holder, 0, 4);
return ByteBuffer.wrap(holder).order(ByteOrder.LITTLE_ENDIAN).getLong();
}
public static String byteArrToHexString(byte[] bArr){
if (bArr == null)
return "";

View file

@ -12,7 +12,7 @@ import java.util.Locale;
import java.util.ResourceBundle;
public class MainFx extends Application {
public static final String appVersion = "v0.1-DEV";
public static final String appVersion = "v0.0-SNAPSHOT";
@Override
public void start(Stage primaryStage) throws Exception{

View file

@ -0,0 +1,77 @@
package konogonka.Tools.NPDM;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import static konogonka.LoperConverter.*;
public class NPDMProvider {
private String magicNum;
private byte[] reserved1;
private byte MMUFlags;
private byte reserved2;
private byte mainThreadPrio;
private byte mainThreadCoreNum;
private byte[] reserved3;
private int personalMmHeapSize; // safe-to-store
private int version; // safe?
private long mainThreadStackSize; // TODO: check if safe
private String titleName;
private byte[] productCode;
private byte[] reserved4;
private long aci0offset; // originally 4-bytes (u-int)
private long aci0size; // originally 4-bytes (u-int)
private long acidOffset; // originally 4-bytes (u-int)
private long acidSize; // originally 4-bytes (u-int)
public NPDMProvider(File file) throws Exception { this(file, 0); }
public NPDMProvider(File file, long offset) throws Exception {
if (file.length() - offset < 0x80) // Header's size
throw new Exception("NPDMProvider: File is too small.");
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(offset);
// Get META
byte[] metaBuf = new byte[0x80];
if (raf.read(metaBuf) != 0x80)
throw new Exception("NPDMProvider: Failed to read 'META'");
magicNum = new String(metaBuf, 0, 4, StandardCharsets.UTF_8);
reserved1 = Arrays.copyOfRange(metaBuf, 0x4, 0xC);
MMUFlags = metaBuf[0xC];
reserved2 = metaBuf[0xD];
mainThreadPrio = metaBuf[0xE];
mainThreadCoreNum = metaBuf[0xF];
reserved3 = Arrays.copyOfRange(metaBuf, 0x10, 0x14);
personalMmHeapSize = getLEint(metaBuf, 0x14);
version = getLEint(metaBuf, 0x18);
mainThreadStackSize = getLElongOfInt(metaBuf, 0x1C);
titleName = new String(metaBuf, 0x20, 0x10, StandardCharsets.UTF_8);
productCode = Arrays.copyOfRange(metaBuf, 0x30, 0x40);
reserved4 = Arrays.copyOfRange(metaBuf, 0x40, 0x70);
aci0offset = getLElongOfInt(metaBuf, 0x70);
aci0size = getLElongOfInt(metaBuf, 0x74);
acidOffset = getLElongOfInt(metaBuf, 0x78);
acidSize = getLElongOfInt(metaBuf, 0x7C);
}
public String getMagicNum() { return magicNum; }
public byte[] getReserved1() { return reserved1; }
public byte getMMUFlags() { return MMUFlags; }
public byte getReserved2() { return reserved2; }
public byte getMainThreadPrio() { return mainThreadPrio; }
public byte getMainThreadCoreNum() { return mainThreadCoreNum; }
public byte[] getReserved3() { return reserved3; }
public int getPersonalMmHeapSize() { return personalMmHeapSize; }
public int getVersion() { return version; }
public long getMainThreadStackSize() { return mainThreadStackSize; }
public String getTitleName() { return titleName; }
public byte[] getProductCode() { return productCode; }
public byte[] getReserved4() { return reserved4; }
public long getAci0offset() { return aci0offset; }
public long getAci0size() { return aci0size; }
public long getAcidOffset() { return acidOffset; }
public long getAcidSize() { return acidSize; }
}

View file

@ -1,8 +1,5 @@
package konogonka.Tools.PFS0;
import konogonka.ModelControllers.EMsgType;
import konogonka.RainbowHexDump;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

View file

@ -3,7 +3,6 @@ package konogonka.Workers;
import javafx.concurrent.Task;
import konogonka.ModelControllers.EMsgType;
import konogonka.ModelControllers.LogPrinter;
import konogonka.Tools.ISuperProvider;
import konogonka.Tools.NCA.NCAProvider;
import java.io.File;

View file

@ -0,0 +1,46 @@
package konogonka.Workers;
import javafx.concurrent.Task;
import konogonka.ModelControllers.EMsgType;
import konogonka.ModelControllers.LogPrinter;
import konogonka.Tools.NPDM.NPDMProvider;
import java.io.File;
public class AnalyzerNPDM extends Task<NPDMProvider> {
private File file;
private long offset;
private LogPrinter logPrinter;
public AnalyzerNPDM(File file){
this(file, 0);
}
public AnalyzerNPDM(File file, long offset){
this.file = file;
this.offset = offset;
this.logPrinter = new LogPrinter();
}
@Override
protected NPDMProvider call() {
logPrinter.print("\tStart chain: NPDM", EMsgType.INFO);
try{
return new NPDMProvider(file, offset);
}
catch (Exception e){
logPrinter.print("\tException: "+e.getMessage(), EMsgType.FAIL);
return null;
}
finally {
close();
}
}
private void close(){
logPrinter.print("\tEnd chain: NPDM", EMsgType.INFO);
logPrinter.close();
}
}

View file

@ -0,0 +1,442 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<ScrollPane fitToWidth="true" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.NPDM.NPDMController">
<VBox spacing="5.0">
<Label text="META">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<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="430.0" minWidth="300.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 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" 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="0x0" GridPane.rowIndex="1">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="1">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x1" GridPane.columnIndex="1" GridPane.rowIndex="5">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0xE" GridPane.rowIndex="5">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x1" GridPane.columnIndex="1" GridPane.rowIndex="4">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0xD" GridPane.rowIndex="4">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x1" GridPane.columnIndex="1" GridPane.rowIndex="3">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0xC" 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="0x4" GridPane.rowIndex="2">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0xF" GridPane.rowIndex="6">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x1" GridPane.columnIndex="1" GridPane.rowIndex="6">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x10" GridPane.rowIndex="7">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="7">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x14" GridPane.rowIndex="8">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="8">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x18" GridPane.rowIndex="9">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="9">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x1C" GridPane.rowIndex="10">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="10">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x20" GridPane.rowIndex="11">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x10" GridPane.columnIndex="1" GridPane.rowIndex="11">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Magicnum &quot;META&quot;" GridPane.columnIndex="2" GridPane.rowIndex="1">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Reserved (1)" GridPane.columnIndex="2" GridPane.rowIndex="2">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="MMU flags*" GridPane.columnIndex="2" GridPane.rowIndex="3">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x30" GridPane.rowIndex="12">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x10" GridPane.columnIndex="1" GridPane.rowIndex="12">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x40" GridPane.rowIndex="13">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x30" GridPane.columnIndex="1" GridPane.rowIndex="13">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x70" GridPane.rowIndex="14">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="16">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="15">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x74" GridPane.rowIndex="15">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x78" GridPane.rowIndex="16">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Reserved (3)" GridPane.columnIndex="2" GridPane.rowIndex="7">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="14">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Reserved (2)" GridPane.columnIndex="2" GridPane.rowIndex="4">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x7C" GridPane.rowIndex="17">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="0x4" GridPane.columnIndex="1" GridPane.rowIndex="17">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Main thread priority (0-63)" GridPane.columnIndex="2" GridPane.rowIndex="5">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Main thread core number" GridPane.columnIndex="2" GridPane.rowIndex="6">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="magicNumLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="1">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="reserved1Lbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="2">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="[3.0.0+] System resource (PersonalMmHeap) size" GridPane.columnIndex="2" GridPane.rowIndex="8">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Version (0 for all titles prior to 8.1.0, 1 for certain titles since)." GridPane.columnIndex="2" GridPane.rowIndex="9">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Main thread stack size***" GridPane.columnIndex="2" GridPane.rowIndex="10">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Title name (usually/always &quot;Application&quot;)" GridPane.columnIndex="2" GridPane.rowIndex="11">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Product code (usually/always all zeroes)" GridPane.columnIndex="2" GridPane.rowIndex="12">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="ACI0 size" GridPane.columnIndex="2" GridPane.rowIndex="15">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="Reserved (4)" GridPane.columnIndex="2" GridPane.rowIndex="13">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="ACI0 offset" GridPane.columnIndex="2" GridPane.rowIndex="14">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="ACID offset" GridPane.columnIndex="2" GridPane.rowIndex="16">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="MMUFlagsLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="3">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label text="ACID size" GridPane.columnIndex="2" GridPane.rowIndex="17">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="reserved2Lbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="4">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="mainThreadPrioLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="5">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="mainThreadCoreNumLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="6">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="reserved3Lbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="7">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="personalMmHeapSizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="8">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="versionLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="9">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="mainThreadStackSizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="10">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="aci0offsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="14">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="aci0sizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="15">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="acidOffsetLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="16">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<Label fx:id="acidSizeLbl" text="-" GridPane.columnIndex="3" GridPane.rowIndex="17">
<padding>
<Insets left="5.0" right="5.0" />
</padding>
</Label>
<TextField fx:id="titleNameTf" GridPane.columnIndex="3" GridPane.rowIndex="11" />
<TextField fx:id="productCodeTf" GridPane.columnIndex="3" GridPane.rowIndex="12" />
<TextField fx:id="reserved4Tf" GridPane.columnIndex="3" GridPane.rowIndex="13" />
</children>
</GridPane>
<Label text="* bit0 = use 64-bit instructions, bit1 = use 64-bit address space, bit2 = use 32-bit address space, bit3 = use 32-bit address space without reserved region, bit4 = optimize memory allocation?" />
<Label text="** max size as of 5.x: 534773760" />
<Label text="*** Should(?) be page-aligned. In non-nspwn scenarios, values of 0 can also rarely break in Horizon. This might be something auto-adapting or a security feature of some sort?" />
<HBox spacing="5.0">
<children>
<Label text="File size" />
<Label text=":" />
<Label fx:id="npdmFileSize" text="-" />
</children>
</HBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</VBox>
</ScrollPane>

View file

@ -14,7 +14,7 @@
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.SVGPath?>
<VBox xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Settings.SettingsController">
<VBox xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Settings.SettingsController">
<children>
<TabPane side="LEFT" tabClosingPolicy="UNAVAILABLE" tabMaxHeight="100.0" tabMaxWidth="80.0" tabMinHeight="80.0" tabMinWidth="50.0" VBox.vgrow="ALWAYS">
<tabs>
@ -101,7 +101,7 @@
<graphic>
<VBox alignment="TOP_CENTER" spacing="5.0">
<children>
<SVGPath content="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" />
<SVGPath content="M7,6H17A6,6 0 0,1 23,12A6,6 0 0,1 17,18C15.22,18 13.63,17.23 12.53,16H11.47C10.37,17.23 8.78,18 7,18A6,6 0 0,1 1,12A6,6 0 0,1 7,6M6,9V11H4V13H6V15H8V13H10V11H8V9H6M15.5,12A1.5,1.5 0 0,0 14,13.5A1.5,1.5 0 0,0 15.5,15A1.5,1.5 0 0,0 17,13.5A1.5,1.5 0 0,0 15.5,12M18.5,9A1.5,1.5 0 0,0 17,10.5A1.5,1.5 0 0,0 18.5,12A1.5,1.5 0 0,0 20,10.5A1.5,1.5 0 0,0 18.5,9Z" />
<Label text="title.keys" />
</children>
</VBox>

View file

@ -87,6 +87,14 @@
<Label text="XML" />
</graphic>
</Tab>
<Tab closable="false">
<content>
<fx:include fx:id="NPDMTab" source="NPDM/NPDMTab.fxml" />
</content>
<graphic>
<Label text="NPDM" />
</graphic>
</Tab>
</tabs>
</TabPane>
<AnchorPane fx:id="logPane" prefHeight="200.0" prefWidth="200.0">