NCA table/contoller/provider updates
This commit is contained in:
		
							parent
							
								
									643f09fd9e
								
							
						
					
					
						commit
						4e1bacd4fc
					
				
					 20 changed files with 450 additions and 302 deletions
				
			
		|  | @ -14,7 +14,8 @@ Deep WIP multi-tool to work with XCI/NSP/NCA/NRO(?) files | |||
| 
 | ||||
| ### Information taken from | ||||
| * Switch brew wiki | ||||
| * roothorick, shchmue, He and others advices and notes. Thanks! | ||||
| * Original ScriesM software | ||||
| * Thanks to roothorick, shchmue, He and others for their advices, notes and examples | ||||
| 
 | ||||
| ### System requirements | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										70
									
								
								src/main/java/konogonka/Child/ChildWindow.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/main/java/konogonka/Child/ChildWindow.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| package konogonka.Child; | ||||
| 
 | ||||
| import javafx.fxml.FXMLLoader; | ||||
| import javafx.scene.Parent; | ||||
| import javafx.scene.Scene; | ||||
| import javafx.scene.image.Image; | ||||
| import javafx.stage.Stage; | ||||
| import konogonka.Controllers.IRowModel; | ||||
| import konogonka.Controllers.NCA.NCAController; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.Locale; | ||||
| import java.util.ResourceBundle; | ||||
| 
 | ||||
| public class ChildWindow { | ||||
|     public ChildWindow(ISuperProvider provider, IRowModel model) throws IOException{ | ||||
|         Stage stageSettings = new Stage(); | ||||
| 
 | ||||
|         stageSettings.setMinWidth(570); | ||||
|         stageSettings.setMinHeight(500); | ||||
| 
 | ||||
|         FXMLLoader loaderSettings; | ||||
| 
 | ||||
|         if (model.getFileName().endsWith(".nca")){ | ||||
|             loaderSettings = new FXMLLoader(getClass().getResource("/FXML/NCA/NCATab.fxml")); | ||||
|         } | ||||
|         else if(model.getFileName().endsWith(".cert")){ | ||||
|             // TODO: IMPLEMENT | ||||
|             return; | ||||
|         } | ||||
|         else if(model.getFileName().endsWith(".tik")){ | ||||
|             // TODO: IMPLEMENT | ||||
|             return; | ||||
|         } | ||||
|         else if(model.getFileName().endsWith(".xml")){ | ||||
|             // TODO: IMPLEMENT | ||||
|             return; | ||||
|         } | ||||
|         else | ||||
|             return; | ||||
| 
 | ||||
|         Locale userLocale = new Locale(Locale.getDefault().getISO3Language()); | ||||
|         ResourceBundle resourceBundle = ResourceBundle.getBundle("locale", userLocale); | ||||
|         loaderSettings.setResources(resourceBundle); | ||||
|         Parent parentAbout = loaderSettings.load(); | ||||
| 
 | ||||
| 
 | ||||
|         // TODO: REFACTOR | ||||
|         if (model.getFileName().endsWith(".nca")){ | ||||
|             NCAController ncaController = loaderSettings.<NCAController>getController(); | ||||
|             ncaController.analyze(provider.getFile(), provider.getRawFileDataStart()+model.getFileOffset()); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         stageSettings.setTitle(model.getFileName()); | ||||
|         stageSettings.getIcons().addAll( | ||||
|                 new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")), | ||||
|                 new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")), | ||||
|                 new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")), | ||||
|                 new Image(getClass().getResourceAsStream("/res/app_icon128x128.png")) | ||||
|         ); | ||||
|         Scene settingsScene = new Scene(parentAbout, 800, 800); | ||||
|         settingsScene.getStylesheets().add("/res/app_light.css"); | ||||
|         stageSettings.setScene(settingsScene); | ||||
|         stageSettings.setMinWidth(550.0); | ||||
|         stageSettings.setMinHeight(550.0); | ||||
|         stageSettings.show(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/main/java/konogonka/Controllers/ITabController.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/java/konogonka/Controllers/ITabController.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| package konogonka.Controllers; | ||||
| 
 | ||||
| import javafx.fxml.Initializable; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| 
 | ||||
| import java.io.File; | ||||
| 
 | ||||
| public interface ITabController extends Initializable { | ||||
|     void analyze(File file); | ||||
|     void analyze(ISuperProvider provider, int subFileNumber); | ||||
|     void resetTab(); | ||||
| } | ||||
|  | @ -6,11 +6,13 @@ import javafx.scene.control.*; | |||
| import javafx.scene.layout.AnchorPane; | ||||
| import javafx.stage.FileChooser; | ||||
| import konogonka.AppPreferences; | ||||
| import konogonka.Child.ChildWindow; | ||||
| import konogonka.Controllers.NCA.NCAController; | ||||
| import konogonka.Controllers.NSP.NSPController; | ||||
| import konogonka.Controllers.XCI.XCIController; | ||||
| import konogonka.MediatorControl; | ||||
| import konogonka.Settings.SettingsWindow; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.net.URL; | ||||
|  | @ -115,6 +117,14 @@ public class MainController implements Initializable { | |||
|         else | ||||
|             splitPane.getItems().add(logPane); | ||||
|     } | ||||
|     public void showContentWindow(ISuperProvider provider, IRowModel model){ | ||||
|         try{ | ||||
|             new ChildWindow(provider, model); | ||||
|         } | ||||
|         catch (IOException e){ | ||||
|             logArea.appendText("\nUnable to create windows for "+model.getFileName()+"\n"+e.getMessage()); | ||||
|         } | ||||
| 
 | ||||
|     }; | ||||
|     public void exit(){ AppPreferences.getInstance().setRecentPath(previouslyOpenedPath); } | ||||
| } | ||||
|  | @ -4,7 +4,8 @@ import javafx.fxml.FXML; | |||
| import javafx.scene.control.Label; | ||||
| import javafx.scene.control.TextField; | ||||
| import konogonka.AppPreferences; | ||||
| import konogonka.Controllers.TabController; | ||||
| import konogonka.Controllers.ITabController; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| import konogonka.Tools.NCA.NCAContentPFS0; | ||||
| import konogonka.Tools.NCA.NCAProvider; | ||||
| import konogonka.Workers.AnalyzerNCA; | ||||
|  | @ -16,7 +17,7 @@ import java.util.ResourceBundle; | |||
| 
 | ||||
| import static konogonka.LoperConverter.byteArrToHexString; | ||||
| 
 | ||||
| public class NCAController implements TabController { | ||||
| public class NCAController implements ITabController { | ||||
| 
 | ||||
|     private File selectedFile; | ||||
|     @FXML | ||||
|  | @ -46,6 +47,7 @@ public class NCAController implements TabController { | |||
|             keyIndexLbl, | ||||
|             ncaSizeLbl, | ||||
|             titleIdLbl, | ||||
|             contentIndexLbl, | ||||
|             sdkVersionLbl, | ||||
|             cryptoType2Lbl, | ||||
|             ticketLbl; | ||||
|  | @ -70,9 +72,12 @@ public class NCAController implements TabController { | |||
|     public void initialize(URL url, ResourceBundle resourceBundle) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void analyze(File file) { | ||||
|     public void analyze(ISuperProvider provider, int subFileNumber){ | ||||
|        // TODO | ||||
|     } | ||||
| 
 | ||||
|     public void analyze(File file, long offset) { | ||||
|         this.selectedFile = file; | ||||
|         HashMap<String, String> keysMap = new HashMap<>(); | ||||
|         keysMap.put("header_key", AppPreferences.getInstance().getHeaderKey()); | ||||
|  | @ -91,7 +96,7 @@ public class NCAController implements TabController { | |||
|                 keysMap.put(pair[0], pair[1]); | ||||
|         } | ||||
| 
 | ||||
|         AnalyzerNCA analyzerNCA = new AnalyzerNCA(file, keysMap); | ||||
|         AnalyzerNCA analyzerNCA = new AnalyzerNCA(file, keysMap, offset); | ||||
|         analyzerNCA.setOnSucceeded(e->{ | ||||
|             populateFields(analyzerNCA.getValue()); | ||||
|         }); | ||||
|  | @ -100,6 +105,11 @@ public class NCAController implements TabController { | |||
|         workThread.start(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void analyze(File file) { | ||||
|         analyze(file, 0); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void resetTab() { | ||||
|         // Header | ||||
|  | @ -115,6 +125,7 @@ public class NCAController implements TabController { | |||
|         sdkVersionLbl.setText("-"); | ||||
|         cryptoType2Lbl.setText("-"); | ||||
|         ticketLbl.setText("-"); | ||||
|         contentIndexLbl.setText("-"); | ||||
|         sha256section1TF.setText("-"); | ||||
|         sha256section2TF.setText("-"); | ||||
|         sha256section3TF.setText("-"); | ||||
|  | @ -156,6 +167,7 @@ public class NCAController implements TabController { | |||
|             keyIndexLbl.setText(Byte.toString(ncaProvider.getKeyIndex())); | ||||
|             ncaSizeLbl.setText(Long.toString(ncaProvider.getNcaSize())); | ||||
|             titleIdLbl.setText(byteArrToHexString(ncaProvider.getTitleId())); | ||||
|             contentIndexLbl.setText(byteArrToHexString(ncaProvider.getContentIndx()));   // | ||||
|             sdkVersionLbl.setText(ncaProvider.getSdkVersion()[3] | ||||
|                     +"."+ncaProvider.getSdkVersion()[2] | ||||
|                     +"."+ncaProvider.getSdkVersion()[1] | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ import javafx.scene.layout.VBox; | |||
| import konogonka.Controllers.NSP.NSPController; | ||||
| import konogonka.LoperConverter; | ||||
| import konogonka.Tools.PFS0.IPFS0Provider; | ||||
| import konogonka.Tools.PFS0.PFS0Provider; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.LinkedList; | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import javafx.fxml.FXML; | |||
| import javafx.scene.control.Button; | ||||
| import javafx.scene.control.Label; | ||||
| import konogonka.Controllers.IRowModel; | ||||
| import konogonka.Controllers.TabController; | ||||
| import konogonka.Controllers.ITabController; | ||||
| import konogonka.MediatorControl; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| import konogonka.Tools.PFS0.IPFS0Provider; | ||||
|  | @ -19,7 +19,7 @@ import java.util.ResourceBundle; | |||
| 
 | ||||
| import static konogonka.LoperConverter.byteArrToHexString; | ||||
| 
 | ||||
| public class NSPController implements TabController { | ||||
| public class NSPController implements ITabController { | ||||
| 
 | ||||
|     @FXML | ||||
|     private Button extractBtn; | ||||
|  | @ -92,6 +92,11 @@ public class NSPController implements TabController { | |||
|      * Start analyze NSP | ||||
|      * */ | ||||
|     @Override | ||||
|     public void analyze(ISuperProvider provider, int subFileNumber){ | ||||
|         // TODO: IMPLEMENT | ||||
|         return; | ||||
|     } | ||||
|     @Override | ||||
|     public void analyze(File selectedFile){ | ||||
|         this.selectedFile = selectedFile; | ||||
|         AnalyzerNSP analyzerNSP = new AnalyzerNSP(selectedFile); | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| package konogonka.Controllers.NSP; | ||||
| 
 | ||||
| import javafx.beans.binding.Bindings; | ||||
| import javafx.beans.property.SimpleBooleanProperty; | ||||
| import javafx.beans.value.ChangeListener; | ||||
| import javafx.beans.value.ObservableValue; | ||||
| import javafx.collections.FXCollections; | ||||
| import javafx.collections.ObservableList; | ||||
| import javafx.event.ActionEvent; | ||||
| import javafx.event.EventHandler; | ||||
| import javafx.fxml.FXML; | ||||
| import javafx.fxml.Initializable; | ||||
|  | @ -17,6 +19,7 @@ import javafx.scene.input.MouseButton; | |||
| import javafx.scene.input.MouseEvent; | ||||
| import javafx.util.Callback; | ||||
| import konogonka.Controllers.IRowModel; | ||||
| import konogonka.MediatorControl; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| import konogonka.Tools.PFS0.IPFS0Provider; | ||||
| 
 | ||||
|  | @ -117,15 +120,30 @@ public class Pfs0TableViewController implements Initializable { | |||
|         uploadColumn.setCellFactory(new Callback<TableColumn<Pfs0RowModel, Boolean>, TableCell<Pfs0RowModel, Boolean>>() { | ||||
|             @Override | ||||
|             public TableCell<Pfs0RowModel, Boolean> call(TableColumn<Pfs0RowModel, Boolean> paramFeatures) { | ||||
|                 CheckBoxTableCell<Pfs0RowModel, Boolean> cell = new CheckBoxTableCell<>(); | ||||
|                 return cell; | ||||
|                 return new CheckBoxTableCell<>(); | ||||
|             } | ||||
|         }); | ||||
|         table.setRowFactory(        // this shit is made to implement context menu. It's such a pain.. | ||||
|                 new Callback<TableView<Pfs0RowModel>, TableRow<Pfs0RowModel>>() { | ||||
|                     @Override | ||||
|                     public TableRow<Pfs0RowModel> call(TableView<Pfs0RowModel> nslRowModelTableView) { | ||||
|                     public TableRow<Pfs0RowModel> call(TableView<Pfs0RowModel> Pfs0RowModelTableView) { | ||||
|                         final TableRow<Pfs0RowModel> row = new TableRow<>(); | ||||
|                         ContextMenu contextMenu = new ContextMenu(); | ||||
| 
 | ||||
|                         MenuItem openMenuItem = new MenuItem("Open"); | ||||
|                         openMenuItem.setOnAction(new EventHandler<ActionEvent>() { | ||||
|                             @Override | ||||
|                             public void handle(ActionEvent actionEvent) { | ||||
|                                 MediatorControl.getInstance().getContoller().showContentWindow(provider, row.getItem());    // TODO: change to something better | ||||
|                             } | ||||
|                         }); | ||||
| 
 | ||||
|                         contextMenu.getItems().addAll(openMenuItem); | ||||
| 
 | ||||
|                         row.setContextMenu(contextMenu); | ||||
|                         row.contextMenuProperty().bind( | ||||
|                                 Bindings.when(Bindings.isNotNull(row.itemProperty())).then(contextMenu).otherwise((ContextMenu)null) | ||||
|                         ); | ||||
|                         row.setOnMouseClicked(new EventHandler<MouseEvent>() {      // Just.. don't ask.. | ||||
|                             @Override | ||||
|                             public void handle(MouseEvent mouseEvent) { | ||||
|  |  | |||
|  | @ -1,10 +0,0 @@ | |||
| package konogonka.Controllers; | ||||
| 
 | ||||
| import javafx.fxml.Initializable; | ||||
| 
 | ||||
| import java.io.File; | ||||
| 
 | ||||
| public interface TabController extends Initializable { | ||||
|     void analyze(File file); | ||||
|     void resetTab(); | ||||
| } | ||||
|  | @ -1,11 +1,11 @@ | |||
| package konogonka.Controllers.XCI; | ||||
| 
 | ||||
| import javafx.fxml.FXML; | ||||
| import javafx.scene.control.Button; | ||||
| import javafx.scene.control.Label; | ||||
| import javafx.scene.control.TextField; | ||||
| import konogonka.AppPreferences; | ||||
| import konogonka.Controllers.TabController; | ||||
| import konogonka.Controllers.ITabController; | ||||
| import konogonka.Tools.ISuperProvider; | ||||
| import konogonka.Tools.XCI.XCIProvider; | ||||
| import konogonka.Workers.AnalyzerXCI; | ||||
| 
 | ||||
|  | @ -15,7 +15,7 @@ import java.util.ResourceBundle; | |||
| 
 | ||||
| import static konogonka.LoperConverter.byteArrToHexString; | ||||
| 
 | ||||
| public class XCIController implements TabController { | ||||
| public class XCIController implements ITabController { | ||||
| 
 | ||||
|     /* Header */ | ||||
|     @FXML | ||||
|  | @ -90,6 +90,11 @@ public class XCIController implements TabController { | |||
|      * Start analyze XCI | ||||
|      * */ | ||||
|     @Override | ||||
|     public void analyze(ISuperProvider provider, int subFileNumber){ | ||||
|         // TODO: IMPLEMENT | ||||
|         return; | ||||
|     } | ||||
|     @Override | ||||
|     public void analyze(File selectedFile){ | ||||
|         HFSBlockController.setSelectedFile(selectedFile); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,8 +1,12 @@ | |||
| package konogonka.Tools; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.PipedInputStream; | ||||
| 
 | ||||
| public interface ISuperProvider { | ||||
|     PipedInputStream getProviderSubFilePipedInpStream(String subFileName); | ||||
|     PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber); | ||||
|     PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception; | ||||
|     PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception; | ||||
| 
 | ||||
|     File getFile(); | ||||
|     long getRawFileDataStart(); | ||||
| } | ||||
|  |  | |||
|  | @ -71,12 +71,12 @@ public class NCAContentPFS0 { | |||
| 
 | ||||
|     private class CryptoSection03{ | ||||
|          | ||||
|         CryptoSection03(File file, long offsetPosition, byte[] decryptedKey, NCASectionBlock ncaSectionBlock, long mediaStartOffset, long mediaEndOffset) throws Exception{ | ||||
|         CryptoSection03(File file, long offsetPosition, byte[] decryptedKey, NCASectionBlock ncaSectionBlock, long mediaStartBlocksOffset, long mediaEndBlocksOffset) throws Exception{ | ||||
|             /*//-------------------------------------------------------------------------------------------------- | ||||
|             System.out.println("Media start location: " + mediaStartOffset); | ||||
|             System.out.println("Media end location:   " + mediaEndOffset); | ||||
|             System.out.println("Media size          : " + (mediaEndOffset-mediaStartOffset)); | ||||
|             System.out.println("Media act. location:  " + (offsetPosition + (mediaStartOffset * 0x200))); | ||||
|             System.out.println("Media start location: " + mediaStartBlocksOffset); | ||||
|             System.out.println("Media end location:   " + mediaEndBlocksOffset); | ||||
|             System.out.println("Media size          : " + (mediaEndBlocksOffset-mediaStartBlocksOffset)); | ||||
|             System.out.println("Media act. location:  " + (offsetPosition + (mediaStartBlocksOffset * 0x200))); | ||||
|             System.out.println("SHA256 hash tbl size: " + ncaSectionBlock.getSuperBlockPFS0().getHashTableSize()); | ||||
|             System.out.println("SHA256 hash tbl offs: " + ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset()); | ||||
|             System.out.println("PFS0 Offs:            " + ncaSectionBlock.getSuperBlockPFS0().getPfs0offset()); | ||||
|  | @ -89,14 +89,14 @@ public class NCAContentPFS0 { | |||
|                 throw new Exception("CryptoSection03: unable to proceed. No decrypted key provided."); | ||||
| 
 | ||||
|             RandomAccessFile raf = new RandomAccessFile(file, "r"); | ||||
|             long abosluteOffsetPosition = offsetPosition + (mediaStartOffset * 0x200); | ||||
|             long abosluteOffsetPosition = offsetPosition + (mediaStartBlocksOffset * 0x200); | ||||
|             raf.seek(abosluteOffsetPosition); | ||||
| 
 | ||||
|             AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaSectionBlock.getSectionCTR(), mediaStartOffset * 0x200); | ||||
|             AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaSectionBlock.getSectionCTR(), mediaStartBlocksOffset * 0x200); | ||||
| 
 | ||||
|             byte[] encryptedBlock; | ||||
|             byte[] dectyptedBlock; | ||||
|             long mediaBlockSize = mediaEndOffset - mediaStartOffset; | ||||
|             long mediaBlocksSize = mediaEndBlocksOffset - mediaStartBlocksOffset; | ||||
|             // Prepare thread to parse encrypted data | ||||
|             PipedOutputStream streamOut = new PipedOutputStream(); | ||||
|             PipedInputStream streamInp = new PipedInputStream(streamOut); | ||||
|  | @ -110,12 +110,12 @@ public class NCAContentPFS0 { | |||
|                     file, | ||||
|                     decryptedKey, | ||||
|                     ncaSectionBlock.getSectionCTR(), | ||||
|                     mediaStartOffset, | ||||
|                     mediaEndOffset | ||||
|                     mediaStartBlocksOffset, | ||||
|                     mediaEndBlocksOffset | ||||
|             )); | ||||
|             pThread.start(); | ||||
|             // Decrypt data | ||||
|             for (int i = 0; i < mediaBlockSize; i++){ | ||||
|             for (int i = 0; i < mediaBlocksSize; i++){ | ||||
|                 encryptedBlock = new byte[0x200]; | ||||
|                 if (raf.read(encryptedBlock) != -1){ | ||||
|                     //dectyptedBlock = aesCtr.decrypt(encryptedBlock); | ||||
|  | @ -139,9 +139,9 @@ public class NCAContentPFS0 { | |||
| 
 | ||||
|             raf = new RandomAccessFile(file, "r"); | ||||
|             raf.seek(abosluteOffsetPosition); | ||||
|             decryptor = new AesCtrDecryptSimple(decryptedKey, ncaSectionBlock.getSectionCTR(), mediaStartOffset * 0x200); | ||||
|             decryptor = new AesCtrDecryptSimple(decryptedKey, ncaSectionBlock.getSectionCTR(), mediaStartBlocksOffset * 0x200); | ||||
| 
 | ||||
|             for (int i = 0; i < mediaBlockSize; i++){ | ||||
|             for (int i = 0; i < mediaBlocksSize; i++){ | ||||
|                 encryptedBlock = new byte[0x200]; | ||||
|                 if (raf.read(encryptedBlock) != -1){ | ||||
|                     //dectyptedBlock = aesCtr.decrypt(encryptedBlock); | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| package konogonka.Tools.NCA; | ||||
| 
 | ||||
| import konogonka.LoperConverter; | ||||
| import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock; | ||||
| import konogonka.xtsaes.XTSAESCipher; | ||||
| import org.bouncycastle.crypto.params.KeyParameter; | ||||
|  | @ -30,6 +29,7 @@ public class NCAProvider { | |||
|     private byte keyIndex;                      // application/ocean/system (kaek index?) | ||||
|     private long ncaSize;                       // Size of this NCA (bytes) | ||||
|     private byte[] titleId; | ||||
|     private byte[] contentIndx; | ||||
|     private byte[] sdkVersion;                  // version ver_revision.ver_micro.vev_minor.ver_major | ||||
|     private byte cryptoType2;                   // keyblob index. Considering as number within application/ocean/system | ||||
|     private byte[] rightsId; | ||||
|  | @ -139,7 +139,8 @@ public class NCAProvider { | |||
|         cryptoType1 = decryptedData[0x206]; | ||||
|         keyIndex = decryptedData[0x207]; | ||||
|         ncaSize = getLElong(decryptedData, 0x208); | ||||
|         titleId = Arrays.copyOfRange(decryptedData, 0x210, 0x21C);   // 0x218 ? | ||||
|         titleId = Arrays.copyOfRange(decryptedData, 0x210, 0x218); | ||||
|         contentIndx = Arrays.copyOfRange(decryptedData, 0x218, 0x21C); | ||||
|         sdkVersion = Arrays.copyOfRange(decryptedData, 0x21c, 0x220); | ||||
|         cryptoType2 = decryptedData[0x220]; | ||||
|         rightsId = Arrays.copyOfRange(decryptedData, 0x230, 0x240); | ||||
|  | @ -214,6 +215,7 @@ public class NCAProvider { | |||
|     public byte getKeyIndex() { return keyIndex; } | ||||
|     public long getNcaSize() { return ncaSize; } | ||||
|     public byte[] getTitleId() { return titleId; } | ||||
|     public byte[] getContentIndx() { return contentIndx; } | ||||
|     public byte[] getSdkVersion() { return sdkVersion; } | ||||
|     public byte getCryptoType2() { return cryptoType2; } | ||||
|     public byte[] getRightsId() { return rightsId; } | ||||
|  | @ -273,7 +275,7 @@ public class NCAProvider { | |||
|         } | ||||
|         switch (sectionNumber) { | ||||
|             case 0: | ||||
|                 return new NCAContentPFS0(file, offset, sectionBlock0, tableEntry0, key);     // TODO: remove decryptedKey2 | ||||
|                 return new NCAContentPFS0(file, offset, sectionBlock0, tableEntry0, key);     // TODO: remove decryptedKey2 ? | ||||
|             case 1: | ||||
|                 return new NCAContentPFS0(file, offset, sectionBlock1, tableEntry1, key); | ||||
|             case 2: | ||||
|  |  | |||
|  | @ -9,6 +9,5 @@ public interface IPFS0Provider extends ISuperProvider { | |||
|     int getStringTableSize(); | ||||
|     byte[] getPadding(); | ||||
| 
 | ||||
|     long getRawFileDataStart(); | ||||
|     PFS0subFile[] getPfs0subFiles(); | ||||
| } | ||||
|  |  | |||
|  | @ -25,8 +25,8 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ | |||
|     private File file; | ||||
|     private byte[] key; | ||||
|     private byte[] sectionCTR; | ||||
|     private long mediaStartOffset; | ||||
|     private long mediaEndOffset; | ||||
|     private long mediaStartOffset;  // In 512-blocks | ||||
|     private long mediaEndOffset;    // In 512-blocks | ||||
| 
 | ||||
|     public PFS0EncryptedProvider(PipedInputStream pipedInputStream, long pfs0offsetPosition, | ||||
|                                  long offsetPositionInFile, | ||||
|  | @ -44,7 +44,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ | |||
|         this.mediaStartOffset = mediaStartOffset; | ||||
|         this.mediaEndOffset = mediaEndOffset; | ||||
|         // pfs0offsetPosition is a position relative to Media block. Lets add pfs0 'header's' bytes count and get raw data start position in media block | ||||
|         rawFileDataStart = -1;      // Set -1 for PFS0EncryptedProvider | ||||
|         rawFileDataStart = -1;                  // Set -1 for PFS0EncryptedProvider | ||||
|         // Detect raw data start position using next var | ||||
|         rawBlockDataStart = pfs0offsetPosition; | ||||
| 
 | ||||
|  | @ -145,145 +145,137 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ | |||
|     public long getRawFileDataStart() { return rawFileDataStart; } | ||||
|     @Override | ||||
|     public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; } | ||||
| 
 | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) { | ||||
|     public File getFile(){ return file; } | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception { | ||||
|         if (subFileNumber >= pfs0subFiles.length) { | ||||
|             System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|             return null; | ||||
|             throw new Exception("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|         } | ||||
|         /*/------------------------------------------------------------------ | ||||
|         System.out.println("Raw Block Data Start (PFS0 Start): " + rawBlockDataStart); | ||||
|         System.out.println("Skipped blocks:                    " + rawBlockDataStart/0x200);                                  // aesCtrDecryptSimple.skip(THIS) | ||||
|         System.out.println("Skip bytes:                        " + (rawBlockDataStart-(rawBlockDataStart/0x200)*0x200));     // write to stream after skiping THIS | ||||
|         *///----------------------------------------------------------------- | ||||
| 
 | ||||
|         Thread workerThread; | ||||
|         PipedOutputStream streamOut = new PipedOutputStream(); | ||||
| 
 | ||||
|         try{ | ||||
|             PipedInputStream streamIn = new PipedInputStream(streamOut); | ||||
|             workerThread = new Thread(() -> { | ||||
|                 System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Executing thread"); | ||||
|                 try { | ||||
|                     BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); | ||||
|                     // Let's store what we're about to skip | ||||
|                     int skipBytes = (int) (offsetPositionInFile + (mediaStartOffset * 0x200)); | ||||
|                     // Check if skip was successful | ||||
| 
 | ||||
|         PipedInputStream streamIn = new PipedInputStream(streamOut); | ||||
|         workerThread = new Thread(() -> { | ||||
|             System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Executing thread"); | ||||
|             try { | ||||
|                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); | ||||
|                 // Let's store what we're about to skip | ||||
|                 int skipBytes = (int) (offsetPositionInFile + (mediaStartOffset * 0x200)); | ||||
|                 // Check if skip was successful | ||||
|                 if (bis.skip(skipBytes) != skipBytes) { | ||||
|                     System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipBytes); | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 AesCtrDecryptSimple aesCtrDecryptSimple = new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200); | ||||
| 
 | ||||
|                 byte[] encryptedBlock; | ||||
|                 byte[] dectyptedBlock; | ||||
| 
 | ||||
|                 //----------------------------- Pre-set: skip non-necessary data -------------------------------- | ||||
| 
 | ||||
|                 long startBlock = (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) / 0x200;            // <- pointing to place where actual data starts | ||||
| 
 | ||||
|                 if (startBlock > 0) { | ||||
|                     aesCtrDecryptSimple.skipNext(startBlock); | ||||
|                     skipBytes = (int)(startBlock * 0x200); | ||||
|                     if (bis.skip(skipBytes) != skipBytes) { | ||||
|                         System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipBytes); | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     AesCtrDecryptSimple aesCtrDecryptSimple = new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200); | ||||
| 
 | ||||
|                     byte[] encryptedBlock; | ||||
|                     byte[] dectyptedBlock; | ||||
| 
 | ||||
|                     //----------------------------- Pre-set: skip non-necessary data -------------------------------- | ||||
| 
 | ||||
|                     long startBlock = (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) / 0x200;            // <- pointing to place where actual data starts | ||||
| 
 | ||||
|                     if (startBlock > 0) { | ||||
|                         aesCtrDecryptSimple.skipNext(startBlock); | ||||
|                         skipBytes = (int)(startBlock * 0x200); | ||||
|                         if (bis.skip(skipBytes) != skipBytes) { | ||||
|                             System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipBytes); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     //----------------------------- Step 1: get starting bytes from the end of the junk block -------------------------------- | ||||
| 
 | ||||
|                     // Since our data could be located in position with some offset from the decrypted block, let's skip bytes left. Considering the case when data is not aligned to block | ||||
|                     skipBytes = (int) ( (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - startBlock * 0x200); // <- How much bytes shall we skip to reach requested data start of sub-file | ||||
| 
 | ||||
|                     if (skipBytes > 0) { | ||||
|                         encryptedBlock = new byte[0x200]; | ||||
|                         if (bis.read(encryptedBlock) == 0x200) { | ||||
|                             dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                             // If we have extra-small file that is less then a block and even more | ||||
|                             if ((0x200 - skipBytes) > pfs0subFiles[subFileNumber].getSize()){ | ||||
|                                 streamOut.write(dectyptedBlock, skipBytes, (int) pfs0subFiles[subFileNumber].getSize());    // safe cast | ||||
|                                 return; | ||||
|                             } | ||||
|                             else | ||||
|                                 streamOut.write(dectyptedBlock, skipBytes, 0x200 - skipBytes); | ||||
|                         } | ||||
|                         else { | ||||
|                             System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                             return; | ||||
|                         } | ||||
|                         startBlock++; | ||||
|                     } | ||||
| 
 | ||||
|                     long endBlock = pfs0subFiles[subFileNumber].getSize() / 0x200 + startBlock;  // <- pointing to place where any data related to this media-block ends | ||||
| 
 | ||||
|                     //----------------------------- Step 2: Detect if we have junk data on the end of the final block -------------------------------- | ||||
|                     int extraData = (int)(rawBlockDataStart+pfs0subFiles[subFileNumber].getOffset()+pfs0subFiles[subFileNumber].getSize() - (endBlock*0x200));  // safe cast | ||||
|                     if (extraData < 0){ | ||||
|                         endBlock--; | ||||
|                     } | ||||
|                     //----------------------------- Step 3: Read main part of data -------------------------------- | ||||
|                     // Here we're reading main amount of bytes. We can read only less bytes. | ||||
|                     while ( startBlock < endBlock) { | ||||
|                         encryptedBlock = new byte[0x200]; | ||||
|                         if (bis.read(encryptedBlock) == 0x200) { | ||||
|                             //dectyptedBlock = aesCtr.decrypt(encryptedBlock); | ||||
|                             dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                             // Writing decrypted data to pipe | ||||
|                             streamOut.write(dectyptedBlock); | ||||
|                         } | ||||
|                         else { | ||||
|                             System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from bock"); | ||||
|                             return; | ||||
|                         } | ||||
|                         startBlock++; | ||||
|                     } | ||||
|                     //----------------------------- Step 4: Read what's left -------------------------------- | ||||
|                     // Now we have to find out if data overlaps to one more extra block | ||||
|                     if (extraData > 0){                 // In case we didn't get what we want | ||||
|                         encryptedBlock = new byte[0x200]; | ||||
|                         if (bis.read(encryptedBlock) == 0x200) { | ||||
|                             dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                             streamOut.write(dectyptedBlock, 0, extraData); | ||||
|                         } | ||||
|                         else { | ||||
|                             System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                     else if (extraData < 0){                // In case we can get more than we need | ||||
|                         encryptedBlock = new byte[0x200]; | ||||
|                         if (bis.read(encryptedBlock) == 0x200) { | ||||
|                             dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                             streamOut.write(dectyptedBlock, 0, 0x200 + extraData); | ||||
|                         } | ||||
|                         else { | ||||
|                             System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                     bis.close(); | ||||
|                     streamOut.close(); | ||||
|                 } | ||||
|                 catch (Exception e){ | ||||
|                     System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): "+e.getMessage()); | ||||
|                     e.printStackTrace(); | ||||
| 
 | ||||
|                 //----------------------------- Step 1: get starting bytes from the end of the junk block -------------------------------- | ||||
| 
 | ||||
|                 // Since our data could be located in position with some offset from the decrypted block, let's skip bytes left. Considering the case when data is not aligned to block | ||||
|                 skipBytes = (int) ( (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - startBlock * 0x200); // <- How much bytes shall we skip to reach requested data start of sub-file | ||||
| 
 | ||||
|                 if (skipBytes > 0) { | ||||
|                     encryptedBlock = new byte[0x200]; | ||||
|                     if (bis.read(encryptedBlock) == 0x200) { | ||||
|                         dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                         // If we have extra-small file that is less then a block and even more | ||||
|                         if ((0x200 - skipBytes) > pfs0subFiles[subFileNumber].getSize()){ | ||||
|                             streamOut.write(dectyptedBlock, skipBytes, (int) pfs0subFiles[subFileNumber].getSize());    // safe cast | ||||
|                             return; | ||||
|                         } | ||||
|                         else | ||||
|                             streamOut.write(dectyptedBlock, skipBytes, 0x200 - skipBytes); | ||||
|                     } | ||||
|                     else { | ||||
|                         System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                         return; | ||||
|                     } | ||||
|                     startBlock++; | ||||
|                 } | ||||
|                 System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Thread died"); | ||||
| 
 | ||||
|                 long endBlock = pfs0subFiles[subFileNumber].getSize() / 0x200 + startBlock;  // <- pointing to place where any data related to this media-block ends | ||||
| 
 | ||||
|                 //----------------------------- Step 2: Detect if we have junk data on the end of the final block -------------------------------- | ||||
|                 int extraData = (int)(rawBlockDataStart+pfs0subFiles[subFileNumber].getOffset()+pfs0subFiles[subFileNumber].getSize() - (endBlock*0x200));  // safe cast | ||||
|                 if (extraData < 0){ | ||||
|                     endBlock--; | ||||
|                 } | ||||
|                 //----------------------------- Step 3: Read main part of data -------------------------------- | ||||
|                 // Here we're reading main amount of bytes. We can read only less bytes. | ||||
|                 while ( startBlock < endBlock) { | ||||
|                     encryptedBlock = new byte[0x200]; | ||||
|                     if (bis.read(encryptedBlock) == 0x200) { | ||||
|                         //dectyptedBlock = aesCtr.decrypt(encryptedBlock); | ||||
|                         dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                         // Writing decrypted data to pipe | ||||
|                         streamOut.write(dectyptedBlock); | ||||
|                     } | ||||
|                     else { | ||||
|                         System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from bock"); | ||||
|                         return; | ||||
|                     } | ||||
|                     startBlock++; | ||||
|                 } | ||||
|                 //----------------------------- Step 4: Read what's left -------------------------------- | ||||
|                 // Now we have to find out if data overlaps to one more extra block | ||||
|                 if (extraData > 0){                 // In case we didn't get what we want | ||||
|                     encryptedBlock = new byte[0x200]; | ||||
|                     if (bis.read(encryptedBlock) == 0x200) { | ||||
|                         dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                         streamOut.write(dectyptedBlock, 0, extraData); | ||||
|                     } | ||||
|                     else { | ||||
|                         System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|                 else if (extraData < 0){                // In case we can get more than we need | ||||
|                     encryptedBlock = new byte[0x200]; | ||||
|                     if (bis.read(encryptedBlock) == 0x200) { | ||||
|                         dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); | ||||
|                         streamOut.write(dectyptedBlock, 0, 0x200 + extraData); | ||||
|                     } | ||||
|                     else { | ||||
|                         System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|                 bis.close(); | ||||
|                 streamOut.close(); | ||||
|             } | ||||
|             catch (Exception e){ | ||||
|                 System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): "+e.getMessage()); | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Thread died"); | ||||
| 
 | ||||
| 
 | ||||
|             }); | ||||
|             workerThread.start(); | ||||
|             return streamIn; | ||||
|         } | ||||
|         catch (IOException ioe){ | ||||
|             System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to provide stream"); | ||||
|             return null; | ||||
|         } | ||||
|         }); | ||||
|         workerThread.start(); | ||||
|         return streamIn; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) { | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception{ | ||||
|         for (int i = 0; i < pfs0subFiles.length; i++){ | ||||
|             if (pfs0subFiles[i].getName().equals(subFileName)) | ||||
|                 return getProviderSubFilePipedInpStream(i); | ||||
|  |  | |||
|  | @ -110,68 +110,61 @@ public class PFS0Provider implements IPFS0Provider{ | |||
|     @Override | ||||
|     public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; } | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber){        // TODO: Throw exceptions? | ||||
|     public File getFile(){ return file; } | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception{        // TODO: Throw exceptions? | ||||
|         if (subFileNumber >= pfs0subFiles.length) { | ||||
|             System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|             return null; | ||||
|             throw new Exception("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|         } | ||||
|         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; | ||||
|                         } | ||||
|         PipedInputStream streamIn = new PipedInputStream(streamOut); | ||||
| 
 | ||||
|                         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 = new Thread(() -> { | ||||
|             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; | ||||
|                 } | ||||
|             }); | ||||
|             workerThread.start(); | ||||
|             return streamIn; | ||||
|         } | ||||
|         catch (IOException ioe){ | ||||
|             System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to provide stream"); | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|                 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; | ||||
|     } | ||||
|     /** | ||||
|      * Some sugar | ||||
|      * */ | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName){ | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception { | ||||
|         for (int i = 0; i < pfs0subFiles.length; i++){ | ||||
|             if (pfs0subFiles[i].getName().equals(subFileName)) | ||||
|                 return getProviderSubFilePipedInpStream(i); | ||||
|  |  | |||
|  | @ -105,71 +105,65 @@ public class HFS0Provider implements ISuperProvider { | |||
|     public int getFilesCnt() { return filesCnt; } | ||||
|     public boolean isPaddingHfs0() { return paddingHfs0; } | ||||
|     public int getStringTableSize() { return stringTableSize; } | ||||
| 
 | ||||
|     @Override | ||||
|     public long getRawFileDataStart() { return rawFileDataStart; } | ||||
|     public HFS0File[] getHfs0Files() { return hfs0Files; } | ||||
| 
 | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber){ | ||||
|     public File getFile(){ return file; } | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) throws Exception{ | ||||
|         PipedOutputStream streamOut = new PipedOutputStream(); | ||||
|         Thread workerThread; | ||||
|         if (subFileNumber >= hfs0Files.length) { | ||||
|             System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|             return null; | ||||
|             throw new Exception("HFS0Provider -> getHfs0FilePipedInpStream(): Requested sub file doesn't exists"); | ||||
|         } | ||||
|         try{ | ||||
|             PipedInputStream streamIn = new PipedInputStream(streamOut); | ||||
|         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"); | ||||
|         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; | ||||
|                     } | ||||
| 
 | ||||
|                     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(); | ||||
|                     streamOut.write(readBuf, 0, readPice); | ||||
|                     readFrom += readPice; | ||||
|                 } | ||||
|                 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; | ||||
|         } | ||||
|                 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; | ||||
|     } | ||||
|     /** | ||||
|      * Sugar | ||||
|      * */ | ||||
|     @Override | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName){ | ||||
|     public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) throws Exception { | ||||
|         for (int i = 0; i < hfs0Files.length; i++){ | ||||
|             if (hfs0Files[i].getName().equals(subFileName)) | ||||
|                 return getProviderSubFilePipedInpStream(i); | ||||
|  |  | |||
|  | @ -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.NCA.NCAProvider; | ||||
| 
 | ||||
| import java.io.File; | ||||
|  | @ -11,11 +12,18 @@ import java.util.HashMap; | |||
| public class AnalyzerNCA extends Task<NCAProvider> { | ||||
| 
 | ||||
|     private File file; | ||||
|     private long offset; | ||||
|     private LogPrinter logPrinter; | ||||
|     private HashMap<String, String> keysMap; | ||||
| 
 | ||||
| 
 | ||||
|     public AnalyzerNCA(File file, HashMap<String, String> keysMap){ | ||||
|         this(file, keysMap, 0); | ||||
|     } | ||||
| 
 | ||||
|     public AnalyzerNCA(File file, HashMap<String, String> keysMap, long offset){ | ||||
|         this.file = file; | ||||
|         this.offset = offset; | ||||
|         this.logPrinter = new LogPrinter(); | ||||
|         this.keysMap = keysMap; | ||||
|     } | ||||
|  | @ -27,7 +35,7 @@ public class AnalyzerNCA extends Task<NCAProvider> { | |||
|         NCAProvider ncaProvider; | ||||
| 
 | ||||
|         try { | ||||
|             ncaProvider = new NCAProvider(file, keysMap); | ||||
|             ncaProvider = new NCAProvider(file, keysMap, offset); | ||||
|         }catch (Exception e){ | ||||
|             logPrinter.print(e.getMessage(), EMsgType.FAIL); | ||||
|             ncaProvider = null; | ||||
|  |  | |||
|  | @ -22,9 +22,6 @@ public class NspXciExtractor extends Task<Void> { | |||
|         this.models = models; | ||||
|         this.filesDestPath = filesDestPath; | ||||
|         this.logPrinter = new LogPrinter(); | ||||
|         for (IRowModel model : models) { | ||||
|             System.out.println(model.getFileName()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -60,8 +57,8 @@ public class NspXciExtractor extends Task<Void> { | |||
|                     getException().printStackTrace();               // TODO: Do something with this | ||||
|                 } | ||||
|                 extractedFileBOS.close(); | ||||
|             } catch (IOException ioe) { | ||||
|                 logPrinter.print("\tRead/Write error\n\t" + ioe.getMessage(), EMsgType.INFO); | ||||
|             } catch (Exception ioe) { | ||||
|                 logPrinter.print("\tExtracting issue\n\t" + ioe.getMessage(), EMsgType.INFO); | ||||
|                 return null; | ||||
|             } finally { | ||||
|                 logPrinter.print("\tEnd extracting", EMsgType.INFO); | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ | |||
|                         <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" vgrow="SOMETIMES" /> | ||||
|                         <RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" /> | ||||
|                         <RowConstraints maxHeight="30.0" minHeight="30.0" vgrow="SOMETIMES" /> | ||||
|  | @ -72,7 +73,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="13"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="14"> | ||||
|                               <children> | ||||
|                               <Label text="0x240" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -108,7 +109,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="11"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="12"> | ||||
|                               <children> | ||||
|                               <Label text="0x220" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -135,7 +136,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="10"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="11"> | ||||
|                               <children> | ||||
|                               <Label text="0x21C" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -144,7 +145,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="12"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="13"> | ||||
|                               <children> | ||||
|                               <Label text="0x230" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -162,7 +163,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="14"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="15"> | ||||
|                               <children> | ||||
|                               <Label text="0x280" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -171,7 +172,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="15"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="16"> | ||||
|                               <children> | ||||
|                               <Label text="0x300" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -243,7 +244,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="15"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="16"> | ||||
|                               <children> | ||||
|                               <Label text="0x10*0x4(0x40)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -252,7 +253,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="14"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="15"> | ||||
|                               <children> | ||||
|                               <Label text="0x20*0x4(0x80)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -261,7 +262,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="13"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="14"> | ||||
|                               <children> | ||||
|                               <Label text="0x10*0x4(0x40)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -324,7 +325,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="10"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="11"> | ||||
|                               <children> | ||||
|                               <Label text="0x4" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -333,7 +334,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="11"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="12"> | ||||
|                               <children> | ||||
|                               <Label text="0x1" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -342,7 +343,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="12"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="13"> | ||||
|                               <children> | ||||
|                               <Label text="0x10" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -362,7 +363,7 @@ | |||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="6"> | ||||
|                               <children> | ||||
|                               <Label text="Crypto Type. Only used stating with 3.0.0. Normally 0. 2 = Crypto supported starting with 3.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                               <Label text="Old Key Generation. Only used stating with 3.0.0. Normally 0. 2 = Crypto supported starting with 3.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|                                     <Insets left="5.0" right="5.0" /> | ||||
|                                  </padding> | ||||
|  | @ -387,7 +388,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="10"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="11"> | ||||
|                               <children> | ||||
|                               <Label text="sdk_version. byte0 usually 0? Known minimum-value(0x000B0000). Calc: byte3.byte2.byte1.byte0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -396,16 +397,16 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="11"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="12"> | ||||
|                               <children> | ||||
|                               <Label text="Crypto-Type2. Selects which crypto-sysver to use. 0x3 = 3.0.1, 0x4 = 4.0.0, 0x5 = 5.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                               <Label text="Key Generation. Selects which crypto-sysver to use. 0x3 = 3.0.1, 0x4 = 4.0.0, 0x5 = 5.0.0." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|                                     <Insets left="5.0" right="5.0" /> | ||||
|                                  </padding> | ||||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="12"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="13"> | ||||
|                               <children> | ||||
|                               <Label text="Rights ID (title.keys key-name to decrypt)" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -414,7 +415,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="13"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.columnSpan="2" GridPane.rowIndex="14"> | ||||
|                               <children> | ||||
|                                  <VBox spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <children> | ||||
|  | @ -437,7 +438,7 @@ | |||
|                                  </VBox> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="14"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="15"> | ||||
|                               <children> | ||||
|                               <Label text="Table of SHA256 hashes, over each 0x200-byte Section Header Block." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -446,7 +447,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="15"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="16"> | ||||
|                               <children> | ||||
|                               <Label text="Key area" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -518,7 +519,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="10"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="11"> | ||||
|                               <children> | ||||
|                               <Label fx:id="sdkVersionLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -527,7 +528,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="11"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="12"> | ||||
|                               <children> | ||||
|                               <Label fx:id="cryptoType2Lbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -536,7 +537,7 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="12"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="13"> | ||||
|                               <children> | ||||
|                               <Label fx:id="ticketLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                  <padding> | ||||
|  | @ -564,7 +565,7 @@ | |||
|                               <TextField fx:id="rsa2048twoTF" editable="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="14"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="15"> | ||||
|                               <children> | ||||
|                                  <VBox spacing="3.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <children> | ||||
|  | @ -579,7 +580,7 @@ | |||
|                                  </VBox> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="15"> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="16"> | ||||
|                               <children> | ||||
|                                  <VBox spacing="3.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <padding> | ||||
|  | @ -648,6 +649,42 @@ | |||
|                               </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.rowIndex="10"> | ||||
|                               <children> | ||||
|                                  <Label text="0x218" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <padding> | ||||
|                                        <Insets left="5.0" right="5.0" /> | ||||
|                                     </padding> | ||||
|                                  </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="1" GridPane.rowIndex="10"> | ||||
|                               <children> | ||||
|                                  <Label text="0x4" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <padding> | ||||
|                                        <Insets left="5.0" right="5.0" /> | ||||
|                                     </padding> | ||||
|                                  </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="2" GridPane.rowIndex="10"> | ||||
|                               <children> | ||||
|                                  <Label text="Content Index" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <padding> | ||||
|                                        <Insets left="5.0" right="5.0" /> | ||||
|                                     </padding> | ||||
|                                  </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                            <AnchorPane styleClass="customGrid" GridPane.columnIndex="3" GridPane.rowIndex="10"> | ||||
|                               <children> | ||||
|                                  <Label fx:id="contentIndexLbl" text="-" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> | ||||
|                                     <padding> | ||||
|                                        <Insets left="5.0" right="5.0" /> | ||||
|                                     </padding> | ||||
|                                  </Label> | ||||
|                               </children> | ||||
|                            </AnchorPane> | ||||
|                      </children> | ||||
|                   </GridPane> | ||||
|                </children> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Dmitry Isaenko
						Dmitry Isaenko