starting re-implementing logic to pipe-streams. Done for PFS0 & HFS0, Updated extractor logic (must be improved later on)
This commit is contained in:
parent
b1d1ae3d1d
commit
4acbf501d5
15 changed files with 315 additions and 84 deletions
|
@ -187,7 +187,8 @@ public class NCAController implements TabController {
|
|||
NCASectionHeaderFourthController.populateTab(ncaProvider.getSectionBlock3());
|
||||
// Section content blocks
|
||||
// TODO: FIX: This code executes getNCAContentPFS0() method twice
|
||||
NCAContentPFS0 ncaContentPFS0 = ncaProvider.getNCAContentPFS0(0);
|
||||
NCAContentPFS0 ncaContentPFS0;
|
||||
ncaContentPFS0 = ncaProvider.getNCAContentPFS0(0);
|
||||
NCASectionContentFirstController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes());
|
||||
ncaContentPFS0 = ncaProvider.getNCAContentPFS0(1);
|
||||
NCASectionContentSecondController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes());
|
||||
|
|
|
@ -6,6 +6,7 @@ import javafx.scene.control.Label;
|
|||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.Controllers.TabController;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.PFS0.IPFS0Provider;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
import konogonka.Workers.AnalyzerNSP;
|
||||
|
@ -47,7 +48,8 @@ public class NSPController implements TabController {
|
|||
|
||||
private void extractFiles(){
|
||||
List<IRowModel> models = tableFilesListController.getFilesForDump();
|
||||
if (models != null && !models.isEmpty()){
|
||||
ISuperProvider provider = tableFilesListController.getProvider();
|
||||
if (models != null && !models.isEmpty() && (provider != null)){
|
||||
|
||||
File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" extracted");
|
||||
try {
|
||||
|
@ -61,7 +63,8 @@ public class NSPController implements TabController {
|
|||
|
||||
extractBtn.setDisable(true);
|
||||
|
||||
NspXciExtractor extractor = new NspXciExtractor(rawFileDataStart, models, dir.getAbsolutePath()+File.separator, selectedFile);
|
||||
//NspXciExtractor extractor = new NspXciExtractor(rawFileDataStart, models, dir.getAbsolutePath()+File.separator, selectedFile); //TODO: REMOVE
|
||||
NspXciExtractor extractor = new NspXciExtractor(provider, models, dir.getAbsolutePath()+File.separator);
|
||||
extractor.setOnSucceeded(e->{
|
||||
extractBtn.setDisable(false);
|
||||
});
|
||||
|
|
|
@ -17,12 +17,12 @@ import javafx.scene.input.MouseButton;
|
|||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.PFS0.IPFS0Provider;
|
||||
import konogonka.Tools.PFS0.PFS0Provider;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
|
@ -31,6 +31,8 @@ public class Pfs0TableViewController implements Initializable {
|
|||
private TableView<Pfs0RowModel> table;
|
||||
private ObservableList<Pfs0RowModel> rowsObsLst;
|
||||
|
||||
private ISuperProvider provider;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
rowsObsLst = FXCollections.observableArrayList();
|
||||
|
@ -146,6 +148,7 @@ public class Pfs0TableViewController implements Initializable {
|
|||
* Add files when user selected them
|
||||
* */
|
||||
public void setNSPToTable(IPFS0Provider pfs){
|
||||
this.provider = pfs;
|
||||
rowsObsLst.clear();
|
||||
Pfs0RowModel.resetNumCnt();
|
||||
if (pfs == null) {
|
||||
|
@ -163,7 +166,7 @@ public class Pfs0TableViewController implements Initializable {
|
|||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* Return list of models checked. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* @return null if no files marked for upload
|
||||
* List<File> if there are files
|
||||
* */
|
||||
|
@ -178,4 +181,5 @@ public class Pfs0TableViewController implements Initializable {
|
|||
}
|
||||
return models;
|
||||
}
|
||||
public ISuperProvider getProvider(){ return provider; }
|
||||
}
|
|
@ -7,6 +7,7 @@ import javafx.scene.control.Label;
|
|||
import javafx.scene.control.TitledPane;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.MediatorControl;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
import konogonka.Tools.XCI.HFS0Provider;
|
||||
import konogonka.Workers.NspXciExtractor;
|
||||
|
||||
|
@ -90,8 +91,9 @@ public class HFSBlockController implements Initializable {
|
|||
List<IRowModel> models;
|
||||
|
||||
models = hfs0tableFilesListMainController.getFilesForDump();
|
||||
ISuperProvider provider = hfs0tableFilesListMainController.getProvider();
|
||||
|
||||
if (models != null && !models.isEmpty()){
|
||||
if (models != null && !models.isEmpty() && (provider != null)){
|
||||
File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" "+type+" extracted");
|
||||
try {
|
||||
dir.mkdir();
|
||||
|
@ -104,7 +106,8 @@ public class HFSBlockController implements Initializable {
|
|||
|
||||
extractMainBtn.setDisable(true);
|
||||
System.out.println(dir.getAbsolutePath()+File.separator);
|
||||
NspXciExtractor extractor = new NspXciExtractor(bodySize, models, dir.getAbsolutePath()+File.separator, selectedFile);
|
||||
//NspXciExtractor extractor = new NspXciExtractor(bodySize, models, dir.getAbsolutePath()+File.separator, selectedFile); // TODO: REMOVE
|
||||
NspXciExtractor extractor = new NspXciExtractor(provider, models, dir.getAbsolutePath()+File.separator);
|
||||
extractor.setOnSucceeded(e->{
|
||||
extractMainBtn.setDisable(false);
|
||||
});
|
||||
|
|
|
@ -17,12 +17,16 @@ import javafx.scene.input.MouseButton;
|
|||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.util.Callback;
|
||||
import konogonka.Controllers.IRowModel;
|
||||
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;
|
||||
|
||||
|
@ -31,6 +35,8 @@ public class Hfs0TableViewController implements Initializable {
|
|||
private TableView<Hfs0RowModel> table;
|
||||
private ObservableList<Hfs0RowModel> rowsObsLst;
|
||||
|
||||
private ISuperProvider provider;
|
||||
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
rowsObsLst = FXCollections.observableArrayList();
|
||||
|
@ -168,12 +174,14 @@ public class Hfs0TableViewController implements Initializable {
|
|||
* Add files when user selected them
|
||||
* */
|
||||
public void setContentToTable(HFS0Provider hfs0){
|
||||
this.provider = hfs0;
|
||||
rowsObsLst.clear();
|
||||
Hfs0RowModel.resetNumCnt();
|
||||
if (hfs0 == null) {
|
||||
table.refresh();
|
||||
return;
|
||||
}
|
||||
// Note: 'i' in here is extra important to be stored in sequence items added.
|
||||
for (int i = 0; i < hfs0.getFilesCnt(); i++){
|
||||
rowsObsLst.add(new Hfs0RowModel(
|
||||
hfs0.getHfs0Files()[i].getName(),
|
||||
|
@ -188,7 +196,7 @@ public class Hfs0TableViewController implements Initializable {
|
|||
table.refresh();
|
||||
}
|
||||
/**
|
||||
* Return files ready for upload. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* Return list of models selected. Requested from NSLMainController only -> uploadBtnAction() //TODO: set undefined
|
||||
* @return null if no files marked for upload
|
||||
* List<File> if there are files
|
||||
* */
|
||||
|
@ -203,4 +211,6 @@ public class Hfs0TableViewController implements Initializable {
|
|||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
public ISuperProvider getProvider(){ return provider; }
|
||||
}
|
8
src/main/java/konogonka/Tools/ISuperProvider.java
Normal file
8
src/main/java/konogonka/Tools/ISuperProvider.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package konogonka.Tools;
|
||||
|
||||
import java.io.PipedInputStream;
|
||||
|
||||
public interface ISuperProvider {
|
||||
PipedInputStream getProviderSubFilePipedInpStream(String subFileName);
|
||||
PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber);
|
||||
}
|
|
@ -45,7 +45,7 @@ public class NCAContentPFS0 {
|
|||
pfs0 = new PFS0Provider(file, pfs0Location);
|
||||
}
|
||||
// If encrypted (regular)
|
||||
else if (ncaSectionBlock.getCryptoType() == 0x3){
|
||||
else if (ncaSectionBlock.getCryptoType() == 0x03){
|
||||
new CryptoSection03(file,
|
||||
offsetPosition,
|
||||
decryptedKey,
|
||||
|
@ -139,8 +139,8 @@ public class NCAContentPFS0 {
|
|||
);
|
||||
}
|
||||
//****************************************___DEBUG___*******************************************************
|
||||
//*
|
||||
File contentFile = new File("/tmp/decryptedNCA0block.pfs0");
|
||||
/*
|
||||
File contentFile = new File("/tmp/decryptedNCA0block_"+offsetPosition+".pfs0");
|
||||
BufferedOutputStream extractedFileOS = new BufferedOutputStream(new FileOutputStream(contentFile));
|
||||
|
||||
raf = new RandomAccessFile(file, "r");
|
||||
|
|
|
@ -252,7 +252,7 @@ public class NCAProvider {
|
|||
|
||||
// If empty Rights ID
|
||||
if (Arrays.equals(rightsId, new byte[0x10])) {
|
||||
key = decryptedKey2; // TODO: Just remember this dumb hach
|
||||
key = decryptedKey2; // TODO: Just remember this dumb hack
|
||||
}
|
||||
else {
|
||||
byte[] rightsIDkey = hexStrToByteArray(keys.get(byteArrToHexString(rightsId)));
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package konogonka.Tools.PFS0;
|
||||
|
||||
public interface IPFS0Provider {
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
||||
public interface IPFS0Provider extends ISuperProvider {
|
||||
boolean isEncrypted();
|
||||
String getMagic();
|
||||
int getFilesCount();
|
||||
|
|
|
@ -22,6 +22,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
private long rawBlockDataStart;
|
||||
|
||||
private PFS0DecryptedStreamProvider pfs0DecryptedStreamProvider;
|
||||
|
||||
// Let's do some fuck
|
||||
private class PFS0DecryptedStreamProvider{
|
||||
private long mediaStartOffset; // * 0x200
|
||||
|
@ -38,7 +39,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
|
||||
public void getStarted(PFS0subFile subFile) throws Exception{
|
||||
|
||||
System.out.println("rawBlockDataStart: "+rawBlockDataStart);
|
||||
System.out.println("rawBlockDataStart (PFS0 Start): "+rawBlockDataStart);
|
||||
System.out.println("Skip blocks: "+rawBlockDataStart/0x200); // aesCtrDecryptSimple.skip(THIS)
|
||||
System.out.println("Skip bytes: "+ (rawBlockDataStart-(rawBlockDataStart/0x200)*0x200)); // write to stream after skiping THIS
|
||||
|
||||
|
@ -255,4 +256,16 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
@Override
|
||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package konogonka.Tools.PFS0;
|
||||
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.RainbowHexDump;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -18,10 +18,12 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
private byte[] padding;
|
||||
private PFS0subFile[] pfs0subFiles;
|
||||
|
||||
private File file;
|
||||
|
||||
public PFS0Provider(File fileWithPfs0) throws Exception{ this(fileWithPfs0, 0); }
|
||||
|
||||
public PFS0Provider(File fileWithPfs0, long pfs0offsetPosition) throws Exception{
|
||||
|
||||
file = fileWithPfs0;
|
||||
RandomAccessFile raf = new RandomAccessFile(fileWithPfs0, "r"); // TODO: replace to bufferedInputStream
|
||||
|
||||
raf.seek(pfs0offsetPosition);
|
||||
|
@ -107,4 +109,73 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
@Override
|
||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber){ // TODO: Throw exceptions?
|
||||
if (subFileNumber >= pfs0subFiles.length) {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists");
|
||||
return null;
|
||||
}
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
Thread workerThread;
|
||||
try{
|
||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||
|
||||
workerThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Executing thread");
|
||||
try {
|
||||
long subFileRealPosition = rawFileDataStart + pfs0subFiles[subFileNumber].getOffset();
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
if (bis.skip(subFileRealPosition) != subFileRealPosition) {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to skip requested offset");
|
||||
return;
|
||||
}
|
||||
|
||||
int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
|
||||
long readFrom = 0;
|
||||
long realFileSize = pfs0subFiles[subFileNumber].getSize();
|
||||
|
||||
byte[] readBuf;
|
||||
|
||||
while (readFrom < realFileSize) {
|
||||
if (realFileSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realFileSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (bis.read(readBuf) != readPice) {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to read requested size from file.");
|
||||
return;
|
||||
}
|
||||
streamOut.write(readBuf);
|
||||
readFrom += readPice;
|
||||
}
|
||||
bis.close();
|
||||
streamOut.close();
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to provide stream");
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Thread died");
|
||||
}
|
||||
});
|
||||
workerThread.start();
|
||||
return streamIn;
|
||||
}
|
||||
catch (IOException ioe){
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to provide stream");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Some sugar
|
||||
* */
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName){
|
||||
for (int i = 0; i < pfs0subFiles.length; i++){
|
||||
if (pfs0subFiles[i].getName().equals(subFileName))
|
||||
return getProviderSubFilePipedInpStream(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
package konogonka.Tools.XCI;
|
||||
|
||||
import konogonka.RainbowHexDump;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static konogonka.LoperConverter.*;
|
||||
|
||||
/**
|
||||
* HFS0
|
||||
* */
|
||||
public class HFS0Provider {
|
||||
public class HFS0Provider implements ISuperProvider {
|
||||
|
||||
private boolean magicHFS0;
|
||||
private int filesCnt;
|
||||
|
@ -23,7 +22,10 @@ public class HFS0Provider {
|
|||
|
||||
private HFS0File[] hfs0Files;
|
||||
|
||||
HFS0Provider(long hfsOffsetPosition, RandomAccessFile raf) throws Exception{
|
||||
private File file;
|
||||
|
||||
HFS0Provider(long hfsOffsetPosition, RandomAccessFile raf, File file) throws Exception{
|
||||
this.file = file; // Will be used @ getHfs0FilePipedInpStream. It's a bad implementation.
|
||||
byte[] hfs0bytes = new byte[16];
|
||||
try{
|
||||
raf.seek(hfsOffsetPosition);
|
||||
|
@ -106,4 +108,72 @@ public class HFS0Provider {
|
|||
|
||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
public HFS0File[] getHfs0Files() { return hfs0Files; }
|
||||
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber){
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
Thread workerThread;
|
||||
if (subFileNumber >= hfs0Files.length) {
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Requested sub file doesn't exists");
|
||||
return null;
|
||||
}
|
||||
try{
|
||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||
|
||||
workerThread = new Thread(() -> {
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Executing thread");
|
||||
try{
|
||||
long subFileRealPosition = rawFileDataStart + hfs0Files[subFileNumber].getOffset();
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
if (bis.skip(subFileRealPosition) != subFileRealPosition) {
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to skip requested offset");
|
||||
return;
|
||||
}
|
||||
|
||||
int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
|
||||
long readFrom = 0;
|
||||
long realFileSize = hfs0Files[subFileNumber].getSize();
|
||||
|
||||
byte[] readBuf;
|
||||
|
||||
while (readFrom < realFileSize){
|
||||
if (realFileSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realFileSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (bis.read(readBuf) != readPice) {
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to read requested size from file.");
|
||||
return;
|
||||
}
|
||||
streamOut.write(readBuf, 0, readPice);
|
||||
readFrom += readPice;
|
||||
}
|
||||
bis.close();
|
||||
streamOut.close();
|
||||
}
|
||||
catch (IOException ioe){
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Thread died");
|
||||
});
|
||||
workerThread.start();
|
||||
return streamIn;
|
||||
}
|
||||
catch (IOException ioe){
|
||||
System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sugar
|
||||
* */
|
||||
@Override
|
||||
public PipedInputStream getProviderSubFilePipedInpStream(String subFileName){
|
||||
for (int i = 0; i < hfs0Files.length; i++){
|
||||
if (hfs0Files[i].getName().equals(subFileName))
|
||||
return getProviderSubFilePipedInpStream(i);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -55,7 +55,7 @@ public class XCIProvider{
|
|||
}
|
||||
xciGamecardCert = new XCIGamecardCert(gamecardCertBytes);
|
||||
|
||||
hfs0ProviderMain = new HFS0Provider(0xf000, raf);
|
||||
hfs0ProviderMain = new HFS0Provider(0xf000, raf, file);
|
||||
if (hfs0ProviderMain.getFilesCnt() < 3){
|
||||
raf.close();
|
||||
throw new Exception("XCI Can't read Gamecard certificate bytes.");
|
||||
|
@ -65,19 +65,19 @@ public class XCIProvider{
|
|||
for (HFS0File hfs0File: hfs0ProviderMain.getHfs0Files()){
|
||||
partition = hfs0File.getName();
|
||||
if (partition.equals("update")) {
|
||||
hfs0ProviderUpdate = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
hfs0ProviderUpdate = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf, file);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("normal")) {
|
||||
hfs0ProviderNormal = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
hfs0ProviderNormal = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf, file);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("secure")) {
|
||||
hfs0ProviderSecure = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
hfs0ProviderSecure = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf, file);
|
||||
continue;
|
||||
}
|
||||
if (partition.equals("logo")) {
|
||||
hfs0ProviderLogo = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf);
|
||||
hfs0ProviderLogo = new HFS0Provider(hfs0ProviderMain.getRawFileDataStart() + hfs0File.getOffset(), raf, file);
|
||||
}
|
||||
}
|
||||
raf.close();
|
||||
|
|
|
@ -4,96 +4,142 @@ import javafx.concurrent.Task;
|
|||
import konogonka.Controllers.IRowModel;
|
||||
import konogonka.ModelControllers.EMsgType;
|
||||
import konogonka.ModelControllers.LogPrinter;
|
||||
import konogonka.Tools.ISuperProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public class NspXciExtractor extends Task<Void> {
|
||||
|
||||
private long rawDataStartPos;
|
||||
private ISuperProvider provider;
|
||||
private List<IRowModel> models;
|
||||
private String filesDestPath;
|
||||
private LogPrinter logPrinter;
|
||||
private File NspXciFile;
|
||||
|
||||
public NspXciExtractor(long rawDataStartPos, List<IRowModel> models, String filesDestPath, File NspXciFile){
|
||||
this.rawDataStartPos = rawDataStartPos;
|
||||
private String filesDestPath;
|
||||
|
||||
public NspXciExtractor(ISuperProvider provider, List<IRowModel> models, String filesDestPath){
|
||||
this.provider = provider;
|
||||
this.models = models;
|
||||
this.filesDestPath = filesDestPath;
|
||||
this.NspXciFile = NspXciFile;
|
||||
this.logPrinter = new LogPrinter();
|
||||
for (IRowModel model : models) {
|
||||
System.out.println(model.getFileName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call() {
|
||||
logPrinter.print("\tStart extracting", EMsgType.INFO);
|
||||
for (IRowModel model: models){
|
||||
logPrinter.print(filesDestPath+model.getFileName(), EMsgType.INFO);
|
||||
protected Void call() { // TODO: add cute progress bar
|
||||
for (IRowModel model : models) {
|
||||
logPrinter.print("\tStart extracting: "+model.getFileName(), EMsgType.INFO);
|
||||
File contentFile = new File(filesDestPath + model.getFileName());
|
||||
try {
|
||||
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(new FileOutputStream(contentFile));
|
||||
PipedInputStream pis = provider.getProviderSubFilePipedInpStream(model.getNumber());
|
||||
|
||||
File contentFile = new File(filesDestPath+model.getFileName());
|
||||
byte[] readBuf = new byte[0x800000]; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
int readSize;
|
||||
while ((readSize = pis.read(readBuf)) > -1) {
|
||||
extractedFileBOS.write(readBuf, 0, readSize);
|
||||
readBuf = new byte[0x800000];
|
||||
}
|
||||
extractedFileBOS.close();
|
||||
} catch (IOException ioe) {
|
||||
logPrinter.print("\tRead/Write error\n\t" + ioe.getMessage(), EMsgType.INFO);
|
||||
return null;
|
||||
} finally {
|
||||
logPrinter.print("\tEnd extracting", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
private long rawDataStartPos;
|
||||
private List<IRowModel> models;
|
||||
private String filesDestPath;
|
||||
private LogPrinter logPrinter;
|
||||
private File NspXciFile;
|
||||
|
||||
long realFileOffset = rawDataStartPos + model.getFileOffset();
|
||||
long realFileSize = model.getFileSize();
|
||||
|
||||
long readFrom = 0;
|
||||
|
||||
int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
byte[] readBuf;
|
||||
public NspXciExtractor(long rawDataStartPos, List<IRowModel> models, String filesDestPath, File NspXciFile){
|
||||
this.rawDataStartPos = rawDataStartPos;
|
||||
this.models = models;
|
||||
this.filesDestPath = filesDestPath;
|
||||
this.NspXciFile = NspXciFile;
|
||||
this.logPrinter = new LogPrinter();
|
||||
}
|
||||
|
||||
try{
|
||||
BufferedOutputStream extractedFileOS = new BufferedOutputStream(new FileOutputStream(contentFile));
|
||||
@Override
|
||||
protected Void call() {
|
||||
logPrinter.print("\tStart extracting", EMsgType.INFO);
|
||||
for (IRowModel model: models){
|
||||
logPrinter.print(filesDestPath+model.getFileName(), EMsgType.INFO);
|
||||
File contentFile = new File(filesDestPath+model.getFileName());
|
||||
|
||||
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(NspXciFile)); // TODO: refactor?
|
||||
if (bufferedInStream.skip(realFileOffset) != realFileOffset) {
|
||||
logPrinter.print("File length is less than offset noted", EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
long realFileOffset = rawDataStartPos + model.getFileOffset();
|
||||
long realFileSize = model.getFileSize();
|
||||
|
||||
while (readFrom < realFileSize){
|
||||
/*
|
||||
if (isCancelled()) // Check if user interrupted process.
|
||||
return false;
|
||||
*/
|
||||
if (realFileSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realFileSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (bufferedInStream.read(readBuf) != readPice) {
|
||||
logPrinter.print("Can't read required chunk from file", EMsgType.FAIL);
|
||||
long readFrom = 0;
|
||||
|
||||
int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
|
||||
byte[] readBuf;
|
||||
|
||||
try{
|
||||
BufferedOutputStream extractedFileOS = new BufferedOutputStream(new FileOutputStream(contentFile));
|
||||
|
||||
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(NspXciFile)); // TODO: refactor?
|
||||
if (bufferedInStream.skip(realFileOffset) != realFileOffset) {
|
||||
logPrinter.print("File length is less than offset noted", EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
|
||||
extractedFileOS.write(readBuf, 0, readPice);
|
||||
while (readFrom < realFileSize){
|
||||
|
||||
// if (isCancelled()) // Check if user interrupted process.
|
||||
// return false;
|
||||
|
||||
if (realFileSize - readFrom < readPice)
|
||||
readPice = Math.toIntExact(realFileSize - readFrom); // it's safe, I guarantee
|
||||
readBuf = new byte[readPice];
|
||||
if (bufferedInStream.read(readBuf) != readPice) {
|
||||
logPrinter.print("Can't read required chunk from file", EMsgType.FAIL);
|
||||
return null;
|
||||
}
|
||||
|
||||
extractedFileOS.write(readBuf, 0, readPice);
|
||||
//-----------------------------------------/
|
||||
try {
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realFileSize/100.0) / 100.0);
|
||||
}catch (InterruptedException ie){
|
||||
getException().printStackTrace(); // TODO: Do something with this
|
||||
}
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
}
|
||||
bufferedInStream.close();
|
||||
extractedFileOS.close();
|
||||
//-----------------------------------------/
|
||||
try {
|
||||
logPrinter.updateProgress((readFrom+readPice)/(realFileSize/100.0) / 100.0);
|
||||
}catch (InterruptedException ie){
|
||||
try{
|
||||
logPrinter.updateProgress(1.0);
|
||||
}
|
||||
catch (InterruptedException ie){
|
||||
getException().printStackTrace(); // TODO: Do something with this
|
||||
}
|
||||
//-----------------------------------------/
|
||||
readFrom += readPice;
|
||||
}
|
||||
bufferedInStream.close();
|
||||
extractedFileOS.close();
|
||||
//-----------------------------------------/
|
||||
try{
|
||||
logPrinter.updateProgress(1.0);
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("\tRead/Write error\n\t"+ioe.getMessage(), EMsgType.INFO);
|
||||
return null;
|
||||
}
|
||||
catch (InterruptedException ie){
|
||||
getException().printStackTrace(); // TODO: Do something with this
|
||||
}
|
||||
//-----------------------------------------/
|
||||
}
|
||||
catch (IOException ioe){
|
||||
logPrinter.print("\tRead/Write error\n\t"+ioe.getMessage(), EMsgType.INFO);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
close();
|
||||
return null;
|
||||
}
|
||||
close();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void close(){
|
||||
logPrinter.print("\tEnd extracting", EMsgType.INFO);
|
||||
logPrinter.close();
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -45,7 +45,7 @@ class XTSTweak {
|
|||
static byte[] nintTweakFunction(long tweakValue) {
|
||||
byte[] bs = new byte[BLOCK_SIZE];
|
||||
byte[] twk = Pack.longToBigEndian(tweakValue);
|
||||
int j = BLOCK_SIZE-twk.length;
|
||||
int j = BLOCK_SIZE - twk.length;
|
||||
for (byte b: twk){
|
||||
bs[j++] = b;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue