125 lines
5.0 KiB
Java
125 lines
5.0 KiB
Java
/*
|
|
* Copyright 2019-2022 Dmitry Isaenko
|
|
*
|
|
* This file is part of libKonogonka.
|
|
*
|
|
* libKonogonka is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* libKonogonka is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package libKonogonka.Tools.RomFs;
|
|
|
|
import libKonogonka.Tools.RomFs.view.DirectoryMetaTablePlainView;
|
|
import libKonogonka.Tools.RomFs.view.FileMetaTablePlainView;
|
|
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
|
|
|
import java.io.File;
|
|
import java.io.PipedInputStream;
|
|
import java.io.PipedOutputStream;
|
|
|
|
public class RomFsEncryptedProvider implements IRomFsProvider{
|
|
private final File file;
|
|
private final long level6Offset;
|
|
private final Level6Header level6Header;
|
|
private final FileSystemEntry rootEntry;
|
|
|
|
private final byte[] key; // Used @ createDecryptor only
|
|
private final byte[] sectionCTR; // Used @ createDecryptor only
|
|
private final long mediaStartOffset; // Used @ createDecryptor only
|
|
private final long absoluteOffsetPosition;
|
|
|
|
//private long mediaEndOffset; // We know this, but actually never use
|
|
|
|
// Used only for debug
|
|
private final byte[] directoryMetadataTable;
|
|
private final byte[] fileMetadataTable;
|
|
|
|
public RomFsEncryptedProvider(long level6Offset,
|
|
File encryptedFsImageFile,
|
|
long romFsOffsetPosition,
|
|
byte[] key,
|
|
byte[] sectionCTR,
|
|
long mediaStartOffset
|
|
) throws Exception{
|
|
this(level6Offset, encryptedFsImageFile, romFsOffsetPosition, key, sectionCTR, mediaStartOffset, -1);
|
|
}
|
|
|
|
public RomFsEncryptedProvider(long level6Offset,
|
|
File encryptedFsImageFile,
|
|
long romFsOffsetPosition,
|
|
byte[] key,
|
|
byte[] sectionCTR,
|
|
long mediaStartOffset,
|
|
long mediaEndOffset
|
|
) throws Exception{
|
|
this.key = key;
|
|
this.sectionCTR = sectionCTR;
|
|
this.mediaStartOffset = mediaStartOffset;
|
|
|
|
RomFsEncryptedConstruct construct = new RomFsEncryptedConstruct(encryptedFsImageFile,
|
|
romFsOffsetPosition,
|
|
level6Offset,
|
|
createDecryptor(),
|
|
mediaStartOffset);
|
|
this.file = encryptedFsImageFile;
|
|
this.level6Offset = level6Offset;
|
|
this.level6Header = construct.getHeader();
|
|
this.rootEntry = construct.getRootEntry();
|
|
this.absoluteOffsetPosition = romFsOffsetPosition + (mediaStartOffset * 0x200);
|
|
|
|
this.directoryMetadataTable = construct.getDirectoryMetadataTable();
|
|
this.fileMetadataTable = construct.getFileMetadataTable();
|
|
}
|
|
private AesCtrDecryptSimple createDecryptor() throws Exception{
|
|
return new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200);
|
|
}
|
|
@Override
|
|
public File getFile() { return file; }
|
|
@Override
|
|
public long getLevel6Offset() { return level6Offset; }
|
|
@Override
|
|
public Level6Header getHeader() {return level6Header;}
|
|
@Override
|
|
public FileSystemEntry getRootEntry() { return rootEntry; }
|
|
@Override
|
|
public PipedInputStream getContent(FileSystemEntry entry) throws Exception{
|
|
if (entry.isDirectory())
|
|
throw new Exception("Request of the binary stream for the folder entry is not supported (and doesn't make sense).");
|
|
|
|
PipedOutputStream streamOut = new PipedOutputStream();
|
|
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
|
long internalFileOffset = entry.getOffset();
|
|
long internalFileSize = entry.getSize();
|
|
|
|
Thread contentRetrievingThread = new Thread(new RomFsEncryptedContentRetrieve(
|
|
file,
|
|
streamOut,
|
|
absoluteOffsetPosition,
|
|
createDecryptor(),
|
|
internalFileOffset,
|
|
internalFileSize,
|
|
level6Offset,
|
|
level6Header.getFileDataOffset()
|
|
));
|
|
contentRetrievingThread.start();
|
|
return streamIn;
|
|
}
|
|
@Override
|
|
public void printDebug(){
|
|
level6Header.printDebugInfo();
|
|
new DirectoryMetaTablePlainView(level6Header.getDirectoryMetadataTableLength(), directoryMetadataTable);
|
|
new FileMetaTablePlainView(level6Header.getFileMetadataTableLength(), fileMetadataTable);
|
|
rootEntry.printTreeForDebug();
|
|
}
|
|
}
|