++ NPDM implementation, UI updates
This commit is contained in:
parent
bd70a7db78
commit
5dcbaff8ac
20 changed files with 2630 additions and 1459 deletions
|
@ -15,7 +15,7 @@ import java.util.Locale;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
public class ChildWindow {
|
||||
public ChildWindow(ISuperProvider provider, IRowModel model) throws IOException{
|
||||
public ChildWindow(ISuperProvider provider, IRowModel model) throws IOException {
|
||||
Stage stageSettings = new Stage();
|
||||
|
||||
stageSettings.setMinWidth(570);
|
||||
|
@ -23,21 +23,22 @@ public class ChildWindow {
|
|||
|
||||
FXMLLoader loaderSettings;
|
||||
|
||||
if (model.getFileName().endsWith(".nca")){
|
||||
if (model.getFileName().endsWith(".nca")) {
|
||||
loaderSettings = new FXMLLoader(getClass().getResource("/FXML/NCA/NCATab.fxml"));
|
||||
}
|
||||
else if(model.getFileName().endsWith(".tik")){
|
||||
} else if (model.getFileName().endsWith(".tik")) {
|
||||
loaderSettings = new FXMLLoader(getClass().getResource("/FXML/TIK/TIKTab.fxml"));
|
||||
}
|
||||
else if(model.getFileName().endsWith(".xml")){
|
||||
} else if (model.getFileName().endsWith(".xml")) {
|
||||
loaderSettings = new FXMLLoader(getClass().getResource("/FXML/XML/XMLTab.fxml"));
|
||||
}
|
||||
else if(model.getFileName().endsWith(".npdm")){
|
||||
loaderSettings = new FXMLLoader(getClass().getResource("/FXML/NPDM/NPDMTab.fxml"));
|
||||
}
|
||||
else if(model.getFileName().endsWith(".cert")){
|
||||
// TODO: IMPLEMENT
|
||||
return;
|
||||
}
|
||||
else if(model.getFileName().endsWith(".cnmt")){
|
||||
// TODO: IMPLEMENT
|
||||
// todo: implement
|
||||
return;
|
||||
}
|
||||
else // TODO: Dynamic detection function
|
||||
|
@ -53,6 +54,15 @@ public class ChildWindow {
|
|||
XMLController myController = loaderSettings.<XMLController>getController();
|
||||
myController.analyze(provider.getFile(), provider.getRawFileDataStart()+model.getFileOffset(), model.getFileSize());
|
||||
}
|
||||
else if (model.getFileName().endsWith(".npdm")){
|
||||
ITabController myController = loaderSettings.<ITabController>getController();
|
||||
try {
|
||||
myController.analyze(provider, model.getNumber());
|
||||
}
|
||||
catch (Exception e){
|
||||
System.out.println("ERR"+e.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
ITabController myController = loaderSettings.<ITabController>getController();
|
||||
myController.analyze(provider.getFile(), provider.getRawFileDataStart()+model.getFileOffset());
|
||||
|
|
|
@ -8,5 +8,6 @@ import java.io.File;
|
|||
public interface ITabController extends Initializable {
|
||||
void analyze(File file);
|
||||
void analyze(File file, long offset);
|
||||
void analyze(ISuperProvider parentProvider, int fileNo) throws Exception;
|
||||
void resetTab();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import javafx.scene.control.Label;
|
|||
import javafx.scene.control.TextField;
|
||||
import konogonka.AppPreferences;
|
||||
import konogonka.Controllers.ITabController;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.NCA.NCAContentPFS0;
|
||||
import konogonka.Tools.NCA.NCAProvider;
|
||||
import konogonka.Workers.AnalyzerNCA;
|
||||
|
@ -105,7 +106,10 @@ public class NCAController implements ITabController {
|
|||
public void analyze(File file) {
|
||||
analyze(file, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
throw new Exception("Not supported for NCA");
|
||||
}
|
||||
@Override
|
||||
public void resetTab() {
|
||||
// Header
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
package konogonka.Controllers.NPDM;
|
||||
|
||||
public class ACI0Provider {
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package konogonka.Controllers.NPDM;
|
||||
|
||||
public class ACIDProvider {
|
||||
}
|
|
@ -4,12 +4,14 @@ import javafx.fxml.FXML;
|
|||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import konogonka.Controllers.ITabController;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.NPDM.ACI0Provider;
|
||||
import konogonka.Tools.NPDM.ACIDProvider;
|
||||
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;
|
||||
|
@ -38,21 +40,65 @@ public class NPDMController implements ITabController {
|
|||
productCodeTf,
|
||||
reserved4Tf;
|
||||
|
||||
// ACI0
|
||||
@FXML
|
||||
private Label aci0MagicNumLbl,
|
||||
aci0Reserved1Lbl,
|
||||
aci0TitleIDLbl,
|
||||
aci0Reserved2Lbl,
|
||||
aci0FsAccessHeaderOffsetLbl,
|
||||
aci0FsAccessHeaderSizeLbl,
|
||||
aci0ServiceAccessControlOffsetLbl,
|
||||
aci0ServiceAccessControlSizeLbl,
|
||||
aci0KernelAccessControlOffsetLbl,
|
||||
aci0KernelAccessControlSizeLbl,
|
||||
aci0Reserved3Lbl;
|
||||
// ACID
|
||||
@FXML TextField acidRsa2048signatureTf,
|
||||
acidRsa2048publicKeyTf;
|
||||
@FXML
|
||||
private Label acidMagicNumLbl,
|
||||
acidDataSizeLbl,
|
||||
acidReserved1Lbl,
|
||||
acidFlag1Lbl,
|
||||
acidFlag2Lbl,
|
||||
acidFlag3Lbl,
|
||||
acidFlag4Lbl,
|
||||
acidTitleRangeMinLbl,
|
||||
acidTitleRangeMaxLbl,
|
||||
acidFsAccessControlOffsetLbl,
|
||||
acidFsAccessControlSizeLbl,
|
||||
acidServiceAccessControlOffsetLbl,
|
||||
acidServiceAccessControlSizeLbl,
|
||||
acidKernelAccessControlOffsetLbl,
|
||||
acidKernelAccessControlSizeLbl,
|
||||
acidReserved2Lbl;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) { }
|
||||
|
||||
@Override
|
||||
public void analyze(File file) { analyze(file, 0); }
|
||||
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
AnalyzerNPDM analyzerNPDM = new AnalyzerNPDM(parentProvider, fileNo);
|
||||
analyzerNPDM.setOnSucceeded(e->{
|
||||
NPDMProvider npdm = analyzerNPDM.getValue();
|
||||
setData(npdm, null);
|
||||
});
|
||||
Thread workThread = new Thread(analyzerNPDM);
|
||||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
@Override
|
||||
public void analyze(File file, long offset) {
|
||||
AnalyzerNPDM analyzerNPDM = new AnalyzerNPDM(file, offset);
|
||||
analyzerNPDM.setOnSucceeded(e->{
|
||||
NPDMProvider tik = analyzerNPDM.getValue();
|
||||
NPDMProvider npdm = analyzerNPDM.getValue();
|
||||
if (offset == 0)
|
||||
setData(tik, file);
|
||||
setData(npdm, file);
|
||||
else
|
||||
setData(tik, null);
|
||||
setData(npdm, null);
|
||||
});
|
||||
Thread workThread = new Thread(analyzerNPDM);
|
||||
workThread.setDaemon(true);
|
||||
|
@ -79,6 +125,38 @@ public class NPDMController implements ITabController {
|
|||
productCodeTf.setText("-");
|
||||
reserved4Tf.setText("-");
|
||||
npdmFileSize.setText("-");
|
||||
|
||||
// ACI0
|
||||
aci0MagicNumLbl.setText("-");
|
||||
aci0Reserved1Lbl.setText("-");
|
||||
aci0TitleIDLbl.setText("-");
|
||||
aci0Reserved2Lbl.setText("-");
|
||||
aci0FsAccessHeaderOffsetLbl.setText("-");
|
||||
aci0FsAccessHeaderSizeLbl.setText("-");
|
||||
aci0ServiceAccessControlOffsetLbl.setText("-");
|
||||
aci0ServiceAccessControlSizeLbl.setText("-");
|
||||
aci0KernelAccessControlOffsetLbl.setText("-");
|
||||
aci0KernelAccessControlSizeLbl.setText("-");
|
||||
aci0Reserved3Lbl.setText("-");
|
||||
// ACID
|
||||
acidRsa2048signatureTf.setText("-");
|
||||
acidRsa2048publicKeyTf.setText("-");
|
||||
acidMagicNumLbl.setText("-");
|
||||
acidDataSizeLbl.setText("-");
|
||||
acidReserved1Lbl.setText("-");
|
||||
acidFlag1Lbl.setText("-");
|
||||
acidFlag2Lbl.setText("-");
|
||||
acidFlag3Lbl.setText("-");
|
||||
acidFlag4Lbl.setText("-");
|
||||
acidTitleRangeMinLbl.setText("-");
|
||||
acidTitleRangeMaxLbl.setText("-");
|
||||
acidFsAccessControlOffsetLbl.setText("-");
|
||||
acidFsAccessControlSizeLbl.setText("-");
|
||||
acidServiceAccessControlOffsetLbl.setText("-");
|
||||
acidServiceAccessControlSizeLbl.setText("-");
|
||||
acidKernelAccessControlOffsetLbl.setText("-");
|
||||
acidKernelAccessControlSizeLbl.setText("-");
|
||||
acidReserved2Lbl.setText("-");
|
||||
}
|
||||
private void setData(NPDMProvider npdmProvider, File file) {
|
||||
if (npdmProvider == null)
|
||||
|
@ -101,10 +179,42 @@ public class NPDMController implements ITabController {
|
|||
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()));
|
||||
aci0offsetLbl.setText(Integer.toString(npdmProvider.getAci0offset()));
|
||||
aci0sizeLbl.setText(Integer.toString(npdmProvider.getAci0size()));
|
||||
acidOffsetLbl.setText(Integer.toString(npdmProvider.getAcidOffset()));
|
||||
acidSizeLbl.setText(Integer.toString(npdmProvider.getAcidSize()));
|
||||
// ACI0
|
||||
ACI0Provider aci0 = npdmProvider.getAci0();
|
||||
aci0MagicNumLbl.setText(aci0.getMagicNum());
|
||||
aci0Reserved1Lbl.setText(byteArrToHexString(aci0.getReserved1()));
|
||||
aci0TitleIDLbl.setText(byteArrToHexString(aci0.getTitleID()));
|
||||
aci0Reserved2Lbl.setText(byteArrToHexString(aci0.getReserved2()));
|
||||
aci0FsAccessHeaderOffsetLbl.setText(Integer.toString(aci0.getFsAccessHeaderOffset()));
|
||||
aci0FsAccessHeaderSizeLbl.setText(Integer.toString(aci0.getFsAccessHeaderSize()));
|
||||
aci0ServiceAccessControlOffsetLbl.setText(Integer.toString(aci0.getServiceAccessControlOffset()));
|
||||
aci0ServiceAccessControlSizeLbl.setText(Integer.toString(aci0.getServiceAccessControlSize()));
|
||||
aci0KernelAccessControlOffsetLbl.setText(Integer.toString(aci0.getKernelAccessControlOffset()));
|
||||
aci0KernelAccessControlSizeLbl.setText(Integer.toString(aci0.getKernelAccessControlSize()));
|
||||
aci0Reserved3Lbl.setText(byteArrToHexString(aci0.getReserved3()));
|
||||
// ACID
|
||||
ACIDProvider acid = npdmProvider.getAcid();
|
||||
acidRsa2048signatureTf.setText(byteArrToHexString(acid.getRsa2048signature()));
|
||||
acidRsa2048publicKeyTf.setText(byteArrToHexString(acid.getRsa2048publicKey()));
|
||||
acidMagicNumLbl.setText(acid.getMagicNum());
|
||||
acidDataSizeLbl.setText(Integer.toString(acid.getDataSize()));
|
||||
acidReserved1Lbl.setText(byteArrToHexString(acid.getReserved1()));
|
||||
acidFlag1Lbl.setText(String.format("0x%02x", acid.getFlag1()));
|
||||
acidFlag2Lbl.setText(String.format("0x%02x", acid.getFlag2()));
|
||||
acidFlag3Lbl.setText(String.format("0x%02x", acid.getFlag3()));
|
||||
acidFlag4Lbl.setText(String.format("0x%02x", acid.getFlag4()));
|
||||
acidTitleRangeMinLbl.setText(Long.toString(acid.getTitleRangeMin()));
|
||||
acidTitleRangeMaxLbl.setText(Long.toString(acid.getTitleRangeMax()));
|
||||
acidFsAccessControlOffsetLbl.setText(Integer.toString(acid.getFsAccessControlOffset()));
|
||||
acidFsAccessControlSizeLbl.setText(Integer.toString(acid.getFsAccessControlSize()));
|
||||
acidServiceAccessControlOffsetLbl.setText(Integer.toString(acid.getServiceAccessControlOffset()));
|
||||
acidServiceAccessControlSizeLbl.setText(Integer.toString(acid.getServiceAccessControlSize()));
|
||||
acidKernelAccessControlOffsetLbl.setText(Integer.toString(acid.getKernelAccessControlOffset()));
|
||||
acidKernelAccessControlSizeLbl.setText(Integer.toString(acid.getKernelAccessControlSize()));
|
||||
acidReserved2Lbl.setText(byteArrToHexString(acid.getReserved2()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -108,6 +108,10 @@ public class NSPController implements ITabController {
|
|||
workThread.setDaemon(true);
|
||||
workThread.start();
|
||||
}
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
throw new Exception("Not supported for NSP");
|
||||
}
|
||||
/**
|
||||
* Just populate fields by already analyzed PFS0
|
||||
* */
|
||||
|
|
|
@ -6,6 +6,7 @@ import javafx.scene.control.Label;
|
|||
import javafx.scene.control.TextField;
|
||||
import konogonka.AppPreferences;
|
||||
import konogonka.Controllers.ITabController;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.TIK.TIKProvider;
|
||||
import konogonka.Workers.AnalyzerTIK;
|
||||
|
||||
|
@ -61,7 +62,10 @@ public class TIKController implements ITabController {
|
|||
|
||||
@Override
|
||||
public void analyze(File file) { analyze(file, 0); }
|
||||
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
throw new Exception("Not supported for TIK");
|
||||
}
|
||||
@Override
|
||||
public void analyze(File file, long offset) {
|
||||
AnalyzerTIK analyzerTIK = new AnalyzerTIK(file, offset);
|
||||
|
|
|
@ -107,6 +107,10 @@ public class XCIController implements ITabController {
|
|||
workThread.start();
|
||||
}
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
throw new Exception("Not supported for XCI");
|
||||
}
|
||||
@Override
|
||||
public void resetTab(){
|
||||
HFSBlockController.setSelectedFile(null);
|
||||
/* Header */
|
||||
|
|
|
@ -4,6 +4,7 @@ import javafx.fxml.FXML;
|
|||
import javafx.scene.control.TextArea;
|
||||
import konogonka.Controllers.ITabController;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
|
@ -14,7 +15,6 @@ import java.util.ResourceBundle;
|
|||
|
||||
public class XMLController implements ITabController {
|
||||
@FXML
|
||||
|
||||
private TextArea mainTa;
|
||||
|
||||
@Override
|
||||
|
@ -47,6 +47,7 @@ public class XMLController implements ITabController {
|
|||
MediatorControl.getInstance().getContoller().logArea.appendText("XMLController -> analyze(): \n"+e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from offset to length
|
||||
* */
|
||||
|
@ -68,6 +69,10 @@ public class XMLController implements ITabController {
|
|||
}
|
||||
}
|
||||
@Override
|
||||
public void analyze(ISuperProvider parentProvider, int fileNo) throws Exception {
|
||||
throw new Exception("Not supported for XML");
|
||||
}
|
||||
@Override
|
||||
public void resetTab() {
|
||||
mainTa.setText(null);
|
||||
}
|
||||
|
|
23
src/main/java/konogonka/Tools/ASuperInFileProvider.java
Normal file
23
src/main/java/konogonka/Tools/ASuperInFileProvider.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package konogonka.Tools;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PipedInputStream;
|
||||
|
||||
/**
|
||||
* Create prototype of the provider that created and works with pipes only
|
||||
* */
|
||||
public abstract class ASuperInFileProvider {
|
||||
protected byte[] readFromStream(PipedInputStream pis, int size) throws IOException {
|
||||
byte[] buffer = new byte[size];
|
||||
int startingPos = 0;
|
||||
int readCnt;
|
||||
while (size > 0){
|
||||
readCnt = pis.read(buffer, startingPos, size);
|
||||
if (readCnt == -1)
|
||||
return null;
|
||||
startingPos += readCnt;
|
||||
size -= readCnt;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
|
@ -163,7 +163,7 @@ public class NCAProvider {
|
|||
else
|
||||
cryptoTypeReal = cryptoType1;
|
||||
|
||||
if (cryptoTypeReal > 0) // TODO: CLARIFY WHY THEH FUCK IS IT FAIR????
|
||||
if (cryptoTypeReal > 0) // TODO: CLARIFY WHY THE FUCK IS IT FAIR????
|
||||
cryptoTypeReal -= 1;
|
||||
|
||||
//todo: if nca3 proceed
|
||||
|
@ -193,6 +193,8 @@ public class NCAProvider {
|
|||
decryptedKey2 = cipher.doFinal(encryptedKey2);
|
||||
decryptedKey3 = cipher.doFinal(encryptedKey3);
|
||||
}
|
||||
else
|
||||
throw new Exception("key_are_key_[UNKNOWN] requested ("+keyIndex+"). Not supported.");
|
||||
}
|
||||
|
||||
tableEntry0 = new NCAHeaderTableEntry(tableBytes);
|
||||
|
@ -244,6 +246,7 @@ public class NCAProvider {
|
|||
public NCASectionBlock getSectionBlock1() { return sectionBlock1; }
|
||||
public NCASectionBlock getSectionBlock2() { return sectionBlock2; }
|
||||
public NCASectionBlock getSectionBlock3() { return sectionBlock3; }
|
||||
|
||||
public boolean isKeyAvailable(){ // TODO: USE
|
||||
if (Arrays.equals(rightsId, new byte[0x10]))
|
||||
return true;
|
||||
|
|
48
src/main/java/konogonka/Tools/NPDM/ACI0Provider.java
Normal file
48
src/main/java/konogonka/Tools/NPDM/ACI0Provider.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
package konogonka.Tools.NPDM;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.getLEint;
|
||||
|
||||
public class ACI0Provider {
|
||||
private String magicNum;
|
||||
private byte[] reserved1;
|
||||
private byte[] titleID;
|
||||
private byte[] reserved2;
|
||||
private int fsAccessHeaderOffset;
|
||||
private int fsAccessHeaderSize;
|
||||
private int serviceAccessControlOffset;
|
||||
private int serviceAccessControlSize;
|
||||
private int kernelAccessControlOffset;
|
||||
private int kernelAccessControlSize;
|
||||
private byte[] reserved3;
|
||||
|
||||
public ACI0Provider(byte[] aci0bytes) throws Exception{
|
||||
if (aci0bytes.length < 0x40)
|
||||
throw new Exception("ACI0 size is too short");
|
||||
magicNum = new String(aci0bytes, 0, 0x4, StandardCharsets.UTF_8);
|
||||
reserved1 = Arrays.copyOfRange(aci0bytes, 0x4, 0x10);
|
||||
titleID = Arrays.copyOfRange(aci0bytes, 0x10, 0x18);
|
||||
reserved2 = Arrays.copyOfRange(aci0bytes, 0x18, 0x20);
|
||||
fsAccessHeaderOffset = getLEint(aci0bytes, 0x20);
|
||||
fsAccessHeaderSize = getLEint(aci0bytes, 0x24);
|
||||
serviceAccessControlOffset = getLEint(aci0bytes, 0x28);
|
||||
serviceAccessControlSize = getLEint(aci0bytes, 0x2C);
|
||||
kernelAccessControlOffset = getLEint(aci0bytes, 0x30);
|
||||
kernelAccessControlSize = getLEint(aci0bytes, 0x34);
|
||||
reserved3 = Arrays.copyOfRange(aci0bytes, 0x38, 0x40);
|
||||
}
|
||||
|
||||
public String getMagicNum() { return magicNum; }
|
||||
public byte[] getReserved1() { return reserved1; }
|
||||
public byte[] getTitleID() { return titleID; }
|
||||
public byte[] getReserved2() { return reserved2; }
|
||||
public int getFsAccessHeaderOffset() { return fsAccessHeaderOffset; }
|
||||
public int getFsAccessHeaderSize() { return fsAccessHeaderSize; }
|
||||
public int getServiceAccessControlOffset() { return serviceAccessControlOffset; }
|
||||
public int getServiceAccessControlSize() { return serviceAccessControlSize; }
|
||||
public int getKernelAccessControlOffset() { return kernelAccessControlOffset; }
|
||||
public int getKernelAccessControlSize() { return kernelAccessControlSize; }
|
||||
public byte[] getReserved3() { return reserved3; }
|
||||
}
|
70
src/main/java/konogonka/Tools/NPDM/ACIDProvider.java
Normal file
70
src/main/java/konogonka/Tools/NPDM/ACIDProvider.java
Normal file
|
@ -0,0 +1,70 @@
|
|||
package konogonka.Tools.NPDM;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.*;
|
||||
|
||||
public class ACIDProvider {
|
||||
|
||||
private byte[] rsa2048signature;
|
||||
private byte[] rsa2048publicKey;
|
||||
private String magicNum;
|
||||
private int dataSize;
|
||||
private byte[] reserved1;
|
||||
private byte flag1;
|
||||
private byte flag2;
|
||||
private byte flag3;
|
||||
private byte flag4;
|
||||
private long titleRangeMin;
|
||||
private long titleRangeMax;
|
||||
private int fsAccessControlOffset;
|
||||
private int fsAccessControlSize;
|
||||
private int serviceAccessControlOffset;
|
||||
private int serviceAccessControlSize;
|
||||
private int kernelAccessControlOffset;
|
||||
private int kernelAccessControlSize;
|
||||
private byte[] reserved2;
|
||||
|
||||
public ACIDProvider(byte[] acidBytes) throws Exception{
|
||||
if (acidBytes.length < 0x240)
|
||||
throw new Exception("ACI0 size is too short");
|
||||
rsa2048signature = Arrays.copyOfRange(acidBytes, 0, 0x100);
|
||||
rsa2048publicKey = Arrays.copyOfRange(acidBytes, 0x100, 0x200);
|
||||
magicNum = new String(acidBytes, 0x200, 0x4, StandardCharsets.UTF_8);
|
||||
dataSize = getLEint(acidBytes, 0x204);
|
||||
reserved1 = Arrays.copyOfRange(acidBytes, 0x208, 0x20C);
|
||||
flag1 = acidBytes[0x20C];
|
||||
flag2 = acidBytes[0x20D];
|
||||
flag3 = acidBytes[0x20E];
|
||||
flag4 = acidBytes[0x20F];
|
||||
titleRangeMin = getLElong(acidBytes, 0x210);
|
||||
titleRangeMax = getLElong(acidBytes, 0x218);
|
||||
fsAccessControlOffset = getLEint(acidBytes, 0x220);
|
||||
fsAccessControlSize = getLEint(acidBytes, 0x224);
|
||||
serviceAccessControlOffset = getLEint(acidBytes, 0x228);
|
||||
serviceAccessControlSize = getLEint(acidBytes, 0x22C);
|
||||
kernelAccessControlOffset = getLEint(acidBytes, 0x230);
|
||||
kernelAccessControlSize = getLEint(acidBytes, 0x234);
|
||||
reserved2 = Arrays.copyOfRange(acidBytes, 0x238, 0x240);
|
||||
}
|
||||
|
||||
public byte[] getRsa2048signature() { return rsa2048signature; }
|
||||
public byte[] getRsa2048publicKey() { return rsa2048publicKey; }
|
||||
public String getMagicNum() { return magicNum; }
|
||||
public int getDataSize() { return dataSize; }
|
||||
public byte[] getReserved1() { return reserved1; }
|
||||
public byte getFlag1() { return flag1; }
|
||||
public byte getFlag2() { return flag2; }
|
||||
public byte getFlag3() { return flag3; }
|
||||
public byte getFlag4() { return flag4; }
|
||||
public long getTitleRangeMin() { return titleRangeMin; }
|
||||
public long getTitleRangeMax() { return titleRangeMax; }
|
||||
public int getFsAccessControlOffset() { return fsAccessControlOffset; }
|
||||
public int getFsAccessControlSize() { return fsAccessControlSize; }
|
||||
public int getServiceAccessControlOffset() { return serviceAccessControlOffset; }
|
||||
public int getServiceAccessControlSize() { return serviceAccessControlSize; }
|
||||
public int getKernelAccessControlOffset() { return kernelAccessControlOffset; }
|
||||
public int getKernelAccessControlSize() { return kernelAccessControlSize; }
|
||||
public byte[] getReserved2() { return reserved2; }
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
package konogonka.Tools.NPDM;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import konogonka.Tools.ASuperInFileProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static konogonka.LoperConverter.*;
|
||||
|
||||
public class NPDMProvider {
|
||||
public class NPDMProvider extends ASuperInFileProvider {
|
||||
|
||||
private String magicNum;
|
||||
private byte[] reserved1;
|
||||
|
@ -22,12 +23,63 @@ public class NPDMProvider {
|
|||
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)
|
||||
private int aci0offset; // originally 4-bytes (u-int)
|
||||
private int aci0size; // originally 4-bytes (u-int)
|
||||
private int acidOffset; // originally 4-bytes (u-int)
|
||||
private int acidSize; // originally 4-bytes (u-int)
|
||||
|
||||
public NPDMProvider(File file) throws Exception { this(file, 0); }
|
||||
private ACI0Provider aci0;
|
||||
private ACIDProvider acid;
|
||||
|
||||
public NPDMProvider(PipedInputStream pis) throws Exception{
|
||||
byte[] mainBuf = new byte[0x80];
|
||||
if(pis.read(mainBuf) != 0x80)
|
||||
throw new Exception("NPDMProvider: Failed to read 'META'");
|
||||
aci0offset = getLEint(mainBuf, 0x70);
|
||||
aci0size = getLEint(mainBuf, 0x74);
|
||||
acidOffset = getLEint(mainBuf, 0x78);
|
||||
acidSize = getLEint(mainBuf, 0x7C);
|
||||
byte[] aci0Buf;
|
||||
byte[] acidBuf;
|
||||
if (aci0offset < acidOffset){
|
||||
if (pis.skip(aci0offset - 0x80) != (aci0offset - 0x80))
|
||||
throw new Exception("NPDMProvider: Failed to skip bytes till 'ACI0'");
|
||||
if ((aci0Buf = readFromStream(pis, aci0size)) == null)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACI0'");
|
||||
if (pis.skip(acidOffset - aci0offset - aci0size) != (acidOffset - aci0offset - aci0size))
|
||||
throw new Exception("NPDMProvider: Failed to skip bytes till 'ACID'");
|
||||
if ((acidBuf = readFromStream(pis, acidSize)) == null)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACID'");
|
||||
}
|
||||
else {
|
||||
if (pis.skip(acidOffset - 0x80) != (acidOffset - 0x80))
|
||||
throw new Exception("NPDMProvider: Failed to skip bytes till 'ACID'");
|
||||
if ((acidBuf = readFromStream(pis, acidSize)) == null)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACID'");
|
||||
if (pis.skip(aci0offset - acidOffset - acidSize) != (aci0offset - acidOffset - acidSize))
|
||||
throw new Exception("NPDMProvider: Failed to skip bytes till 'ACI0'");
|
||||
if ((aci0Buf = readFromStream(pis, aci0size)) == null)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACI0'");
|
||||
}
|
||||
magicNum = new String(mainBuf, 0, 4, StandardCharsets.UTF_8);
|
||||
reserved1 = Arrays.copyOfRange(mainBuf, 0x4, 0xC);
|
||||
MMUFlags = mainBuf[0xC];
|
||||
reserved2 = mainBuf[0xD];
|
||||
mainThreadPrio = mainBuf[0xE];
|
||||
mainThreadCoreNum = mainBuf[0xF];
|
||||
reserved3 = Arrays.copyOfRange(mainBuf, 0x10, 0x14);
|
||||
personalMmHeapSize = getLEint(mainBuf, 0x14);
|
||||
version = getLEint(mainBuf, 0x18);
|
||||
mainThreadStackSize = getLElongOfInt(mainBuf, 0x1C);
|
||||
titleName = new String(mainBuf, 0x20, 0x10, StandardCharsets.UTF_8);
|
||||
productCode = Arrays.copyOfRange(mainBuf, 0x30, 0x40);
|
||||
reserved4 = Arrays.copyOfRange(mainBuf, 0x40, 0x70);
|
||||
|
||||
aci0 = new ACI0Provider(aci0Buf);
|
||||
acid = new ACIDProvider(acidBuf);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -51,10 +103,23 @@ public class NPDMProvider {
|
|||
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);
|
||||
aci0offset = getLEint(metaBuf, 0x70);
|
||||
aci0size = getLEint(metaBuf, 0x74);
|
||||
acidOffset = getLEint(metaBuf, 0x78);
|
||||
acidSize = getLEint(metaBuf, 0x7C);
|
||||
// Get ACI0
|
||||
raf.seek(aci0offset);
|
||||
metaBuf = new byte[aci0size]; // TODO: NOTE: we read all size but need only header
|
||||
if (raf.read(metaBuf) != aci0size)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACI0'");
|
||||
aci0 = new ACI0Provider(metaBuf);
|
||||
// Get ACID
|
||||
raf.seek(acidOffset);
|
||||
metaBuf = new byte[acidSize]; // TODO: NOTE: we read all size but need only header
|
||||
if (raf.read(metaBuf) != acidSize)
|
||||
throw new Exception("NPDMProvider: Failed to read 'ACID'");
|
||||
acid = new ACIDProvider(metaBuf);
|
||||
raf.close();
|
||||
}
|
||||
|
||||
public String getMagicNum() { return magicNum; }
|
||||
|
@ -70,8 +135,11 @@ public class NPDMProvider {
|
|||
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; }
|
||||
public int getAci0offset() { return aci0offset; }
|
||||
public int getAci0size() { return aci0size; }
|
||||
public int getAcidOffset() { return acidOffset; }
|
||||
public int getAcidSize() { return acidSize; }
|
||||
|
||||
public ACI0Provider getAci0() { return aci0; }
|
||||
public ACIDProvider getAcid() { return acid; }
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
streamOut.write(dectyptedBlock, 0, extraData);
|
||||
}
|
||||
else {
|
||||
System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock");
|
||||
System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from bock");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
streamOut.write(dectyptedBlock, 0, 0x200 + extraData);
|
||||
}
|
||||
else {
|
||||
System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock");
|
||||
System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from last bock");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package konogonka.Workers;
|
|||
import javafx.concurrent.Task;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.NPDM.NPDMProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -13,6 +14,15 @@ public class AnalyzerNPDM extends Task<NPDMProvider> {
|
|||
private long offset;
|
||||
private LogPrinter logPrinter;
|
||||
|
||||
private ISuperProvider parentProvider;
|
||||
private int fileNo;
|
||||
|
||||
public AnalyzerNPDM(ISuperProvider parentProvider, int fileNo){
|
||||
this.parentProvider = parentProvider;
|
||||
this.fileNo = fileNo;
|
||||
this.logPrinter = new LogPrinter();
|
||||
}
|
||||
|
||||
public AnalyzerNPDM(File file){
|
||||
this(file, 0);
|
||||
}
|
||||
|
@ -27,7 +37,10 @@ public class AnalyzerNPDM extends Task<NPDMProvider> {
|
|||
protected NPDMProvider call() {
|
||||
logPrinter.print("\tStart chain: NPDM", EMsgType.INFO);
|
||||
try{
|
||||
return new NPDMProvider(file, offset);
|
||||
if (parentProvider != null)
|
||||
return new NPDMProvider(parentProvider.getProviderSubFilePipedInpStream(fileNo));
|
||||
else
|
||||
return new NPDMProvider(file, offset);
|
||||
}
|
||||
catch (Exception e){
|
||||
logPrinter.print("\tException: "+e.getMessage(), EMsgType.FAIL);
|
||||
|
|
|
@ -44,6 +44,7 @@ public class NspXciExtractor extends Task<Void> {
|
|||
readBuf = new byte[0x800000];
|
||||
//*** PROGRESS BAR DECORCATIONS START
|
||||
progressHandleFRead += readSize;
|
||||
System.out.println(readSize);
|
||||
try {
|
||||
logPrinter.updateProgress((progressHandleFRead)/(progressHandleFSize/100.0) / 100.0);
|
||||
}catch (InterruptedException ie){
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue