From 4acbf501d5eb3d447b97f198067e6e47647a96e2 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Sun, 18 Aug 2019 07:16:24 +0300 Subject: [PATCH] starting re-implementing logic to pipe-streams. Done for PFS0 & HFS0, Updated extractor logic (must be improved later on) --- .../Controllers/NCA/NCAController.java | 3 +- .../Controllers/NSP/NSPController.java | 7 +- .../NSP/Pfs0TableViewController.java | 10 +- .../Controllers/XCI/HFSBlockController.java | 7 +- .../XCI/Hfs0TableViewController.java | 12 +- .../java/konogonka/Tools/ISuperProvider.java | 8 + .../konogonka/Tools/NCA/NCAContentPFS0.java | 6 +- .../java/konogonka/Tools/NCA/NCAProvider.java | 2 +- .../konogonka/Tools/PFS0/IPFS0Provider.java | 4 +- .../Tools/PFS0/PFS0EncryptedProvider.java | 15 +- .../konogonka/Tools/PFS0/PFS0Provider.java | 77 ++++++++- .../konogonka/Tools/XCI/HFS0Provider.java | 80 ++++++++- .../java/konogonka/Tools/XCI/XCIProvider.java | 10 +- .../konogonka/Workers/NspXciExtractor.java | 156 ++++++++++++------ src/main/java/konogonka/xtsaes/XTSTweak.java | 2 +- 15 files changed, 315 insertions(+), 84 deletions(-) create mode 100644 src/main/java/konogonka/Tools/ISuperProvider.java diff --git a/src/main/java/konogonka/Controllers/NCA/NCAController.java b/src/main/java/konogonka/Controllers/NCA/NCAController.java index da3d27b..1842fb2 100644 --- a/src/main/java/konogonka/Controllers/NCA/NCAController.java +++ b/src/main/java/konogonka/Controllers/NCA/NCAController.java @@ -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()); diff --git a/src/main/java/konogonka/Controllers/NSP/NSPController.java b/src/main/java/konogonka/Controllers/NSP/NSPController.java index 2ebb890..7e96dda 100644 --- a/src/main/java/konogonka/Controllers/NSP/NSPController.java +++ b/src/main/java/konogonka/Controllers/NSP/NSPController.java @@ -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 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); }); diff --git a/src/main/java/konogonka/Controllers/NSP/Pfs0TableViewController.java b/src/main/java/konogonka/Controllers/NSP/Pfs0TableViewController.java index 011b63f..ea2c196 100644 --- a/src/main/java/konogonka/Controllers/NSP/Pfs0TableViewController.java +++ b/src/main/java/konogonka/Controllers/NSP/Pfs0TableViewController.java @@ -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 table; private ObservableList 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 if there are files * */ @@ -178,4 +181,5 @@ public class Pfs0TableViewController implements Initializable { } return models; } + public ISuperProvider getProvider(){ return provider; } } \ No newline at end of file diff --git a/src/main/java/konogonka/Controllers/XCI/HFSBlockController.java b/src/main/java/konogonka/Controllers/XCI/HFSBlockController.java index 9b72736..587f18f 100644 --- a/src/main/java/konogonka/Controllers/XCI/HFSBlockController.java +++ b/src/main/java/konogonka/Controllers/XCI/HFSBlockController.java @@ -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 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); }); diff --git a/src/main/java/konogonka/Controllers/XCI/Hfs0TableViewController.java b/src/main/java/konogonka/Controllers/XCI/Hfs0TableViewController.java index 42b8a3d..bcfce2a 100644 --- a/src/main/java/konogonka/Controllers/XCI/Hfs0TableViewController.java +++ b/src/main/java/konogonka/Controllers/XCI/Hfs0TableViewController.java @@ -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 table; private ObservableList 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 if there are files * */ @@ -203,4 +211,6 @@ public class Hfs0TableViewController implements Initializable { } return models; } + + public ISuperProvider getProvider(){ return provider; } } \ No newline at end of file diff --git a/src/main/java/konogonka/Tools/ISuperProvider.java b/src/main/java/konogonka/Tools/ISuperProvider.java new file mode 100644 index 0000000..0ec1c74 --- /dev/null +++ b/src/main/java/konogonka/Tools/ISuperProvider.java @@ -0,0 +1,8 @@ +package konogonka.Tools; + +import java.io.PipedInputStream; + +public interface ISuperProvider { + PipedInputStream getProviderSubFilePipedInpStream(String subFileName); + PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber); +} diff --git a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java index 44c222a..6f012d1 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java +++ b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java @@ -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"); diff --git a/src/main/java/konogonka/Tools/NCA/NCAProvider.java b/src/main/java/konogonka/Tools/NCA/NCAProvider.java index 2d59779..d494ace 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAProvider.java +++ b/src/main/java/konogonka/Tools/NCA/NCAProvider.java @@ -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))); diff --git a/src/main/java/konogonka/Tools/PFS0/IPFS0Provider.java b/src/main/java/konogonka/Tools/PFS0/IPFS0Provider.java index e4d8cd5..ee7a261 100644 --- a/src/main/java/konogonka/Tools/PFS0/IPFS0Provider.java +++ b/src/main/java/konogonka/Tools/PFS0/IPFS0Provider.java @@ -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(); diff --git a/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java b/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java index 429e592..31159b7 100644 --- a/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java +++ b/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java @@ -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; + } } diff --git a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java index a89cc7c..cbdcf36 100644 --- a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java +++ b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java @@ -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; + } } diff --git a/src/main/java/konogonka/Tools/XCI/HFS0Provider.java b/src/main/java/konogonka/Tools/XCI/HFS0Provider.java index d121f1f..947cf91 100644 --- a/src/main/java/konogonka/Tools/XCI/HFS0Provider.java +++ b/src/main/java/konogonka/Tools/XCI/HFS0Provider.java @@ -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; + } } \ No newline at end of file diff --git a/src/main/java/konogonka/Tools/XCI/XCIProvider.java b/src/main/java/konogonka/Tools/XCI/XCIProvider.java index 29cdd9c..796010a 100644 --- a/src/main/java/konogonka/Tools/XCI/XCIProvider.java +++ b/src/main/java/konogonka/Tools/XCI/XCIProvider.java @@ -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(); diff --git a/src/main/java/konogonka/Workers/NspXciExtractor.java b/src/main/java/konogonka/Workers/NspXciExtractor.java index 87f05d7..d683ab0 100644 --- a/src/main/java/konogonka/Workers/NspXciExtractor.java +++ b/src/main/java/konogonka/Workers/NspXciExtractor.java @@ -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 { - private long rawDataStartPos; + private ISuperProvider provider; private List models; - private String filesDestPath; private LogPrinter logPrinter; - private File NspXciFile; - public NspXciExtractor(long rawDataStartPos, List models, String filesDestPath, File NspXciFile){ - this.rawDataStartPos = rawDataStartPos; + private String filesDestPath; + + public NspXciExtractor(ISuperProvider provider, List 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 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 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(); } + */ } \ No newline at end of file diff --git a/src/main/java/konogonka/xtsaes/XTSTweak.java b/src/main/java/konogonka/xtsaes/XTSTweak.java index 83f15cc..3765c12 100644 --- a/src/main/java/konogonka/xtsaes/XTSTweak.java +++ b/src/main/java/konogonka/xtsaes/XTSTweak.java @@ -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; }