Compare commits
	
		
			3 commits
		
	
	
		
			8225f0fcba
			...
			b6ab72e7fd
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						b6ab72e7fd | ||
| 
							 | 
						270033b3f9 | ||
| 
							 | 
						416e5280a6 | 
| 
						 | 
					@ -6,6 +6,12 @@ Deep WIP multi-tool to work with NS-specific files / filesystem images.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[GNU General Public License v3+](https://github.com/developersu/konogonka/blob/master/LICENSE)
 | 
					[GNU General Public License v3+](https://github.com/developersu/konogonka/blob/master/LICENSE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="screenshots/1.png" alt="drawing" width="250"/> <img src="screenshots/2.png" alt="drawing" width="250"/> <img src="screenshots/3.png" alt="drawing" width="250"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="screenshots/4.png" alt="drawing" width="250"/> <img src="screenshots/5.png" alt="drawing" width="250"/> <img src="screenshots/6.png" alt="drawing" width="250"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<img src="screenshots/7.png" alt="drawing" width="250"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Used libraries & resources
 | 
					### Used libraries & resources
 | 
				
			||||||
* [Bouncy Castle](https://www.bouncycastle.org/) for Java.
 | 
					* [Bouncy Castle](https://www.bouncycastle.org/) for Java.
 | 
				
			||||||
* [Java-XTS-AES](https://github.com/horrorho/Java-XTS-AES) by horrorho with minimal changes.
 | 
					* [Java-XTS-AES](https://github.com/horrorho/Java-XTS-AES) by horrorho with minimal changes.
 | 
				
			||||||
| 
						 | 
					@ -45,6 +51,6 @@ JRE/JDK 8u60 or higher.
 | 
				
			||||||
* [ ] CERT support
 | 
					* [ ] CERT support
 | 
				
			||||||
* [ ] CNMT support
 | 
					* [ ] CNMT support
 | 
				
			||||||
* [ ] NSO support
 | 
					* [ ] NSO support
 | 
				
			||||||
* [ ] RomFS deep-dive
 | 
					* [x] RomFS
 | 
				
			||||||
* [ ] LogPrinter to singleton implementation. 
 | 
					* [ ] LogPrinter to singleton implementation. 
 | 
				
			||||||
* [x] 'Save to folder' option
 | 
					* [x] 'Save to folder' option
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								screenshots/1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 234 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 69 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 132 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 99 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 168 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 114 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								screenshots/7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 146 KiB  | 
| 
						 | 
					@ -110,7 +110,7 @@ public class MainController implements Initializable {
 | 
				
			||||||
            fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
 | 
					            fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files",
 | 
					        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files",
 | 
				
			||||||
                "*.nsp", "*.nsz", "*.xci", "*.nca", "*.tik", "*.xml", "*.npdm", "*.romfs"));
 | 
					                "*.nsp", "*.nsz", "*.xci", "*.nca", "*.tik", "*.xml", "*.npdm", "*.bin"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow());
 | 
					        this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ public class MainController implements Initializable {
 | 
				
			||||||
            case "npdm":
 | 
					            case "npdm":
 | 
				
			||||||
                tabPane.getSelectionModel().select(5);
 | 
					                tabPane.getSelectionModel().select(5);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "romfs":
 | 
					            case "bin":
 | 
				
			||||||
                tabPane.getSelectionModel().select(6);
 | 
					                tabPane.getSelectionModel().select(6);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,7 @@ public class MainController implements Initializable {
 | 
				
			||||||
            case "npdm":
 | 
					            case "npdm":
 | 
				
			||||||
                NPDMTabController.analyze(selectedFile);
 | 
					                NPDMTabController.analyze(selectedFile);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "romfs":
 | 
					            case "bin":
 | 
				
			||||||
                RFSTabController.analyze(selectedFile);
 | 
					                RFSTabController.analyze(selectedFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -198,7 +198,7 @@ public class MainController implements Initializable {
 | 
				
			||||||
            case "tik":
 | 
					            case "tik":
 | 
				
			||||||
            case "xml":
 | 
					            case "xml":
 | 
				
			||||||
            case "npdm":
 | 
					            case "npdm":
 | 
				
			||||||
            case "romfs":
 | 
					            case "bin":
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,7 +147,15 @@ public class RomFsController implements ITabController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void analyze(File file) {
 | 
					    public void analyze(File file) {
 | 
				
			||||||
        Task<RomFsDecryptedProvider> analyzer = Analyzer.analyzeRomFS(file);
 | 
					        long lv6offset = -1;
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					            System.out.println(file.getName().replaceAll("(^.*lv6\\s)|(]\\.bin)", ""));
 | 
				
			||||||
 | 
					            lv6offset = Long.parseLong(file.getName().replaceAll("(^.*lv6\\s)|(]\\.bin)", ""));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception e){
 | 
				
			||||||
 | 
					            e.printStackTrace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Task<RomFsDecryptedProvider> analyzer = Analyzer.analyzeRomFS(file, lv6offset);
 | 
				
			||||||
        analyzer.setOnSucceeded(e->{
 | 
					        analyzer.setOnSucceeded(e->{
 | 
				
			||||||
            RomFsDecryptedProvider provider = analyzer.getValue();
 | 
					            RomFsDecryptedProvider provider = analyzer.getValue();
 | 
				
			||||||
            this.setData(provider);
 | 
					            this.setData(provider);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ import java.io.File;
 | 
				
			||||||
import java.io.PipedInputStream;
 | 
					import java.io.PipedInputStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public interface IRomFsProvider {
 | 
					public interface IRomFsProvider {
 | 
				
			||||||
 | 
					    long getLevel6Offset();
 | 
				
			||||||
    Level6Header getHeader();
 | 
					    Level6Header getHeader();
 | 
				
			||||||
    FileSystemEntry getRootEntry();
 | 
					    FileSystemEntry getRootEntry();
 | 
				
			||||||
    PipedInputStream getContent(FileSystemEntry entry) throws Exception;
 | 
					    PipedInputStream getContent(FileSystemEntry entry) throws Exception;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,20 +23,24 @@ import java.io.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class RomFsDecryptedProvider implements IRomFsProvider{
 | 
					public class RomFsDecryptedProvider implements IRomFsProvider{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final long LEVEL_6_DEFAULT_OFFSET = 0x14000; // TODO: FIX incorrect
 | 
					    private long level6Offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private File file;
 | 
					    private File file;
 | 
				
			||||||
    private Level6Header header;
 | 
					    private Level6Header header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private FileSystemEntry rootEntry;
 | 
					    private FileSystemEntry rootEntry;
 | 
				
			||||||
    // TODO: FIX. LEVEL 6 OFFSET MUST be provided
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public RomFsDecryptedProvider(File decryptedFsImageFile) throws Exception{     // TODO: add default setup AND using meta-data headers from NCA RomFs section (?)
 | 
					    public RomFsDecryptedProvider(File decryptedFsImageFile, long level6Offset) throws Exception{
 | 
				
			||||||
 | 
					        if (level6Offset < 0)
 | 
				
			||||||
 | 
					            throw new Exception("Incorrect Level 6 Offset");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.file = decryptedFsImageFile;
 | 
					        this.file = decryptedFsImageFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(decryptedFsImageFile));
 | 
					        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(decryptedFsImageFile));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        skipBytes(bis, LEVEL_6_DEFAULT_OFFSET);
 | 
					        this.level6Offset = level6Offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        skipBytes(bis, level6Offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        byte[] rawDataChunk = new byte[0x50];
 | 
					        byte[] rawDataChunk = new byte[0x50];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,6 +102,8 @@ public class RomFsDecryptedProvider implements IRomFsProvider{
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
 | 
					    public long getLevel6Offset() { return level6Offset; }
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
    public Level6Header getHeader() { return header; }
 | 
					    public Level6Header getHeader() { return header; }
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public FileSystemEntry getRootEntry() { return rootEntry; }
 | 
					    public FileSystemEntry getRootEntry() { return rootEntry; }
 | 
				
			||||||
| 
						 | 
					@ -114,7 +120,7 @@ public class RomFsDecryptedProvider implements IRomFsProvider{
 | 
				
			||||||
        workerThread = new Thread(() -> {
 | 
					        workerThread = new Thread(() -> {
 | 
				
			||||||
            System.out.println("RomFsDecryptedProvider -> getContent(): Executing thread");
 | 
					            System.out.println("RomFsDecryptedProvider -> getContent(): Executing thread");
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                long subFileRealPosition = LEVEL_6_DEFAULT_OFFSET + header.getFileDataOffset() + entry.getFileOffset();
 | 
					                long subFileRealPosition = level6Offset + header.getFileDataOffset() + entry.getFileOffset();
 | 
				
			||||||
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
 | 
					                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
 | 
				
			||||||
                skipBytes(bis, subFileRealPosition);
 | 
					                skipBytes(bis, subFileRealPosition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ import java.util.Arrays;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class RomFsEncryptedProvider implements IRomFsProvider{
 | 
					public class RomFsEncryptedProvider implements IRomFsProvider{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static long level6Offset;
 | 
					    private long level6Offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private File file;
 | 
					    private File file;
 | 
				
			||||||
    private Level6Header header;
 | 
					    private Level6Header header;
 | 
				
			||||||
| 
						 | 
					@ -176,6 +176,8 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
 | 
				
			||||||
        return metadataTable;
 | 
					        return metadataTable;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public long getLevel6Offset() { return level6Offset; }
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Level6Header getHeader() { return header; }
 | 
					    public Level6Header getHeader() { return header; }
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
| 
						 | 
					@ -189,33 +191,80 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
 | 
				
			||||||
        Thread workerThread;
 | 
					        Thread workerThread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        PipedInputStream streamIn = new PipedInputStream(streamOut);
 | 
					        PipedInputStream streamIn = new PipedInputStream(streamOut);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        workerThread = new Thread(() -> {
 | 
					        workerThread = new Thread(() -> {
 | 
				
			||||||
            System.out.println("RomFsDecryptedProvider -> getContent(): Executing thread");
 | 
					            System.out.println("RomFsDecryptedProvider -> getContent(): Executing thread");
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                long subFileRealPosition = level6Offset + header.getFileDataOffset() + entry.getFileOffset();
 | 
					 | 
				
			||||||
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
 | 
					 | 
				
			||||||
                bis.skip(subFileRealPosition);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                int readPice = 8388608; // 8mb NOTE: consider switching to 1mb 1048576
 | 
					                byte[] encryptedBlock;
 | 
				
			||||||
 | 
					                byte[] dectyptedBlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                long readFrom = 0;
 | 
					                RandomAccessFile raf = new RandomAccessFile(file, "r");
 | 
				
			||||||
                long realFileSize = entry.getFileSize();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                byte[] readBuf;
 | 
					                //0
 | 
				
			||||||
 | 
					                AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while (readFrom < realFileSize) {
 | 
					                long startBlock = (entry.getFileOffset() + header.getFileDataOffset()) / 0x200;
 | 
				
			||||||
                    if (realFileSize - readFrom < readPice)
 | 
					
 | 
				
			||||||
                        readPice = Math.toIntExact(realFileSize - readFrom);    // it's safe, I guarantee
 | 
					                decryptor.skipNext(level6Offset / 0x200 + startBlock);
 | 
				
			||||||
                    readBuf = new byte[readPice];
 | 
					
 | 
				
			||||||
                    if (bis.read(readBuf) != readPice) {
 | 
					                long abosluteOffsetPosition = romFSoffsetPosition + (mediaStartOffset * 0x200);
 | 
				
			||||||
                        System.out.println("RomFsDecryptedProvider -> getContent(): Unable to read requested size from file.");
 | 
					
 | 
				
			||||||
                        return;
 | 
					                raf.seek(abosluteOffsetPosition + level6Offset + startBlock * 0x200);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //1
 | 
				
			||||||
 | 
					                long ignoreBytes = (entry.getFileOffset() + header.getFileDataOffset()) - startBlock * 0x200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ignoreBytes > 0) {
 | 
				
			||||||
 | 
					                    encryptedBlock = new byte[0x200];
 | 
				
			||||||
 | 
					                    if (raf.read(encryptedBlock) == 0x200) {
 | 
				
			||||||
 | 
					                        dectyptedBlock = decryptor.dectyptNext(encryptedBlock);
 | 
				
			||||||
 | 
					                        // If we have extra-small file that is less then a block and even more
 | 
				
			||||||
 | 
					                        if ((0x200 - ignoreBytes) > entry.getFileSize()){
 | 
				
			||||||
 | 
					                            streamOut.write(dectyptedBlock, (int)ignoreBytes, (int) entry.getFileSize());    // safe cast
 | 
				
			||||||
 | 
					                            raf.close();
 | 
				
			||||||
 | 
					                            streamOut.close();
 | 
				
			||||||
 | 
					                            return;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        else {
 | 
				
			||||||
 | 
					                            streamOut.write(dectyptedBlock, (int) ignoreBytes, 0x200 - (int) ignoreBytes);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    streamOut.write(readBuf);
 | 
					                    else {
 | 
				
			||||||
                    readFrom += readPice;
 | 
					                        throw new Exception("RomFsEncryptedProvider(): Unable to get 512 bytes from 1st bock for Directory Metadata Table");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    startBlock++;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                bis.close();
 | 
					                long endBlock = (entry.getFileSize() + ignoreBytes) / 0x200 + startBlock;  // <- pointing to place where any data related to this media-block ends
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //2
 | 
				
			||||||
 | 
					                int extraData = (int) ((endBlock - startBlock)*0x200 - (entry.getFileSize() + ignoreBytes));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (extraData < 0)
 | 
				
			||||||
 | 
					                    endBlock--;
 | 
				
			||||||
 | 
					                //3
 | 
				
			||||||
 | 
					                while ( startBlock < endBlock ) {
 | 
				
			||||||
 | 
					                    encryptedBlock = new byte[0x200];
 | 
				
			||||||
 | 
					                    if (raf.read(encryptedBlock) == 0x200) {
 | 
				
			||||||
 | 
					                        dectyptedBlock = decryptor.dectyptNext(encryptedBlock);
 | 
				
			||||||
 | 
					                        streamOut.write(dectyptedBlock);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        throw new Exception("RomFsEncryptedProvider(): Unable to get 512 bytes from block for Directory Metadata Table");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    startBlock++;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                //4
 | 
				
			||||||
 | 
					                if (extraData != 0){                 // In case we didn't get what we want
 | 
				
			||||||
 | 
					                    encryptedBlock = new byte[0x200];
 | 
				
			||||||
 | 
					                    if (raf.read(encryptedBlock) == 0x200) {
 | 
				
			||||||
 | 
					                        dectyptedBlock = decryptor.dectyptNext(encryptedBlock);
 | 
				
			||||||
 | 
					                        streamOut.write(dectyptedBlock, 0, Math.abs(extraData));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        throw new Exception("RomFsEncryptedProvider(): Unable to get 512 bytes from block for Directory Metadata Table");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                raf.close();
 | 
				
			||||||
                streamOut.close();
 | 
					                streamOut.close();
 | 
				
			||||||
            } catch (Exception e) {
 | 
					            } catch (Exception e) {
 | 
				
			||||||
                System.out.println("RomFsDecryptedProvider -> getContent(): Unable to provide stream");
 | 
					                System.out.println("RomFsDecryptedProvider -> getContent(): Unable to provide stream");
 | 
				
			||||||
| 
						 | 
					@ -226,6 +275,7 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
 | 
				
			||||||
        workerThread.start();
 | 
					        workerThread.start();
 | 
				
			||||||
        return streamIn;
 | 
					        return streamIn;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public File getFile() {
 | 
					    public File getFile() {
 | 
				
			||||||
        return file;
 | 
					        return file;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,14 +161,14 @@ public class Analyzer {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Task<RomFsDecryptedProvider> analyzeRomFS(File file){
 | 
					    public static Task<RomFsDecryptedProvider> analyzeRomFS(File file, long lv6offset){
 | 
				
			||||||
        LogPrinter logPrinter = new LogPrinter();
 | 
					        LogPrinter logPrinter = new LogPrinter();
 | 
				
			||||||
        return new Task<RomFsDecryptedProvider>() {
 | 
					        return new Task<RomFsDecryptedProvider>() {
 | 
				
			||||||
            @Override
 | 
					            @Override
 | 
				
			||||||
            protected RomFsDecryptedProvider call() {
 | 
					            protected RomFsDecryptedProvider call() {
 | 
				
			||||||
                logPrinter.print("\tStart chain: RomFS", EMsgType.INFO);
 | 
					                logPrinter.print("\tStart chain: RomFS", EMsgType.INFO);
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    return new RomFsDecryptedProvider(file);
 | 
					                    return new RomFsDecryptedProvider(file, lv6offset);
 | 
				
			||||||
                } catch (Exception e) {
 | 
					                } catch (Exception e) {
 | 
				
			||||||
                    logPrinter.print(e.getMessage(), EMsgType.FAIL);
 | 
					                    logPrinter.print(e.getMessage(), EMsgType.FAIL);
 | 
				
			||||||
                    return null;
 | 
					                    return null;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,8 +26,12 @@ public class DumbNCA3ContentExtractor extends Task<Void> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected Void call() {
 | 
					    protected Void call() {
 | 
				
			||||||
        logPrinter.print("\tStart dummy extracting: \n"+filesDestPath+"NCAContent_"+ncaNumberInFile+".bin", EMsgType.INFO);
 | 
					        String lv6mark = "";
 | 
				
			||||||
        File contentFile = new File(filesDestPath + "NCAContent_"+ncaNumberInFile+".bin");
 | 
					        if (ncaContent.getRomfs() != null){
 | 
				
			||||||
 | 
					            lv6mark = " [lv6 "+ncaContent.getRomfs().getLevel6Offset()+"]";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        logPrinter.print("\tStart dummy extracting: \n"+filesDestPath+"NCAContent_"+ncaNumberInFile+lv6mark+".bin", EMsgType.INFO);
 | 
				
			||||||
 | 
					        File contentFile = new File(filesDestPath + "NCAContent_"+ncaNumberInFile+lv6mark+".bin");
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            BufferedOutputStream extractedFileBOS = new BufferedOutputStream(new FileOutputStream(contentFile));
 | 
					            BufferedOutputStream extractedFileBOS = new BufferedOutputStream(new FileOutputStream(contentFile));
 | 
				
			||||||
            PipedInputStream pis = ncaContent.getRawDataContentPipedInpStream();
 | 
					            PipedInputStream pis = ncaContent.getRawDataContentPipedInpStream();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@
 | 
				
			||||||
<?import javafx.scene.shape.SVGPath?>
 | 
					<?import javafx.scene.shape.SVGPath?>
 | 
				
			||||||
<?import javafx.scene.text.Font?>
 | 
					<?import javafx.scene.text.Font?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<VBox minHeight="600.0" spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.RFS.RomFsController">
 | 
					<VBox minHeight="750.0" spacing="5.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="konogonka.Controllers.RFS.RomFsController">
 | 
				
			||||||
   <children>
 | 
					   <children>
 | 
				
			||||||
      <TitledPane animated="false" expanded="false" text="Header (Level 6)">
 | 
					      <TitledPane animated="false" expanded="false" text="Header (Level 6)">
 | 
				
			||||||
         <content>
 | 
					         <content>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||