126 lines
4.4 KiB
Java
126 lines
4.4 KiB
Java
/*
|
|
Copyright 2018-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.ctraes.AesCtrBufferedInputStream;
|
|
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
import java.io.*;
|
|
import java.nio.file.Files;
|
|
|
|
public class RomFsContentRetrieve implements Runnable{
|
|
private final static Logger log = LogManager.getLogger(RomFsContentRetrieve.class);
|
|
|
|
private final PipedOutputStream streamOut;
|
|
private final long internalFileSize;
|
|
private final long startPosition;
|
|
private final BufferedInputStream bis;
|
|
|
|
RomFsContentRetrieve(File parentFile,
|
|
PipedOutputStream streamOut,
|
|
long internalFileRealPosition,
|
|
long internalFileSize) throws Exception{
|
|
this.streamOut = streamOut;
|
|
this.internalFileSize = internalFileSize;
|
|
|
|
this.startPosition = internalFileRealPosition;
|
|
this.bis = new BufferedInputStream(Files.newInputStream(parentFile.toPath()));
|
|
}
|
|
|
|
RomFsContentRetrieve(File parentFile,
|
|
PipedOutputStream streamOut,
|
|
AesCtrDecryptSimple decryptor,
|
|
long entryOffset,
|
|
long internalFileSize,
|
|
long headersFileDataOffset, //level6Header.getFileDataOffset()
|
|
long level6Offset,
|
|
long ncaOffsetPosition,
|
|
long mediaStartOffset,
|
|
long mediaEndOffset
|
|
) throws Exception{
|
|
log.fatal("Current implementation works incorrectly");
|
|
this.streamOut = streamOut;
|
|
this.internalFileSize = internalFileSize;
|
|
|
|
this.startPosition = entryOffset + mediaStartOffset*0x200 + headersFileDataOffset + level6Offset;
|
|
|
|
this.bis = new AesCtrBufferedInputStream(
|
|
decryptor,
|
|
ncaOffsetPosition,
|
|
mediaStartOffset,
|
|
mediaEndOffset,
|
|
Files.newInputStream(parentFile.toPath())
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
log.trace("Executing thread");
|
|
try {
|
|
skipBytesTillBegining();
|
|
|
|
int readPiece = 8388608;
|
|
long readFrom = 0;
|
|
byte[] readBuffer;
|
|
|
|
while (readFrom < internalFileSize) {
|
|
if (internalFileSize - readFrom < readPiece)
|
|
readPiece = Math.toIntExact(internalFileSize - readFrom);
|
|
readBuffer = new byte[readPiece];
|
|
if (bis.read(readBuffer) != readPiece) {
|
|
log.error("getContent(): Unable to read requested size from file.");
|
|
return;
|
|
}
|
|
streamOut.write(readBuffer);
|
|
readFrom += readPiece;
|
|
}
|
|
} catch (Exception exception) {
|
|
log.error("RomFsProvider -> getContent(): Unable to provide stream", exception);
|
|
}
|
|
finally {
|
|
closeStreams();
|
|
}
|
|
log.trace("Thread died");
|
|
}
|
|
private void skipBytesTillBegining() throws Exception{
|
|
long mustSkip = startPosition;
|
|
long skipped = 0;
|
|
while (mustSkip > 0){
|
|
skipped += bis.skip(mustSkip);
|
|
mustSkip = startPosition - skipped;
|
|
}
|
|
}
|
|
private void closeStreams(){
|
|
try {
|
|
streamOut.close();
|
|
}
|
|
catch (IOException e){
|
|
log.error("RomFsProvider -> getContent(): Unable to close 'StreamOut'");
|
|
}
|
|
try {
|
|
bis.close();
|
|
}
|
|
catch (IOException e){
|
|
log.error("RomFsProvider -> getContent(): Unable to close 'StreamOut'");
|
|
}
|
|
}
|
|
}
|