- Replace the readFileAsStream (to InputStream) function with a default implementation in the FSTDataProvider interface. This way the implementations only need to provide a function to write into a outputstream.

- Optimize the readEncryptedToStream function on the DiscReader. The normal wud reader don't need to pipe the stream anymore.
This commit is contained in:
Maschell 2019-04-11 13:27:21 +02:00
parent 89d5927acd
commit fbceae0558
9 changed files with 92 additions and 112 deletions

View File

@ -110,7 +110,7 @@ public final class WUDService {
Map<ByteArrayWrapper, Integer> sectorHashes = new HashMap<>();
Map<Integer, Integer> sectorMapping = new TreeMap<>();
InputStream in = image.getWUDDiscReader().readEncryptedToInputStream(0, image.getWUDFileSize());
InputStream in = image.getWUDDiscReader().readEncryptedToStream(0, image.getWUDFileSize());
int bufferSize = WUDImageCompressedInfo.SECTOR_SIZE;
byte[] blockBuffer = new byte[bufferSize];
@ -168,8 +168,8 @@ public final class WUDService {
log.warning("Filesize is different");
return false;
}
InputStream in1 = firstImage.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE);
InputStream in2 = secondImage.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE);
InputStream in1 = firstImage.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
InputStream in2 = secondImage.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
boolean result = true;
int bufferSize = 1024 * 1024 + 19;
@ -249,7 +249,7 @@ public final class WUDService {
}
log.info("Writing decompressed file to: " + outputFile.getAbsolutePath());
InputStream in = image.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE);
InputStream in = image.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
OutputStream out = new FileOutputStream(outputFile);
int bufferSize = 1024 * 1024;
@ -295,7 +295,7 @@ public final class WUDService {
log.info("The input file is splitted. The calculated hash is the hash of the corresponding .wud file, not this splitted .wud");
}
InputStream in = image.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE);
InputStream in = image.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
int bufferSize = 1024 * 1024 * 10;
long totalread = 0;

View File

@ -17,11 +17,9 @@
package de.mas.wiiu.jnus.implementations;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedOutputStream;
import java.util.Optional;
import de.mas.wiiu.jnus.NUSTitle;
@ -31,8 +29,6 @@ import de.mas.wiiu.jnus.interfaces.FSTDataProvider;
import de.mas.wiiu.jnus.interfaces.HasNUSTitle;
import de.mas.wiiu.jnus.interfaces.NUSDataProvider;
import de.mas.wiiu.jnus.utils.CheckSumWrongException;
import de.mas.wiiu.jnus.utils.PipedInputStreamWithException;
import de.mas.wiiu.jnus.utils.StreamUtils;
import de.mas.wiiu.jnus.utils.Utils;
import de.mas.wiiu.jnus.utils.cryptography.NUSDecryption;
import lombok.Getter;
@ -57,52 +53,17 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle {
@Override
public byte[] readFile(FSTEntry entry, long offset, long size) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
readFileToOutputStream(out, entry, offset, size);
} catch (CheckSumWrongException e) {
throw new IOException(e);
}
readFileToStream(out, entry, offset, Optional.of(size));
return out.toByteArray();
}
@Override
public InputStream readFileAsStream(FSTEntry entry, long offset, Optional<Long> size) throws IOException {
long filesize = size.orElse(entry.getFileSize());
try {
return readFileAsInputStream(entry, offset, filesize);
} catch (CheckSumWrongException e) {
throw new IOException(e);
}
}
public PipedInputStreamWithException readFileAsInputStream(FSTEntry entry, long offset, long size) throws IOException, CheckSumWrongException {
PipedInputStreamWithException in = new PipedInputStreamWithException();
PipedOutputStream out = new PipedOutputStream(in);
new Thread(() -> {
try {
readFileToOutputStream(out, entry, offset, size);
in.throwException(null);
} catch (Exception e) {
in.throwException(e);
}
}).start();
return in;
}
@Override
public void readFileToStream(OutputStream outputStream, FSTEntry entry) throws IOException {
try {
readFileToOutputStream(outputStream, entry, 0, entry.getFileSize());
} catch (CheckSumWrongException e) {
throw new IOException(e);
}
}
public boolean readFileToOutputStream(OutputStream out, FSTEntry entry, long offset, long size) throws IOException, CheckSumWrongException {
public void readFileToStream(OutputStream out, FSTEntry entry, long offset, Optional<Long> size) throws IOException {
long fileOffset = entry.getFileOffset() + offset;
long fileOffsetBlock = fileOffset;
long usedSize = size.orElse(entry.getFileSize());
if (entry.getContent().isHashed()) {
fileOffsetBlock = (fileOffset / 0xFC00) * 0x10000;
@ -113,10 +74,14 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle {
fileOffsetBlock -= 16;
}
}
return decryptFSTEntryToStream(entry, out, size, fileOffset, fileOffsetBlock);
try {
decryptFSTEntryToStream(entry, out, fileOffsetBlock, fileOffset, usedSize);
} catch (CheckSumWrongException e) {
throw new IOException(e);
}
}
public boolean decryptFSTEntryToStream(FSTEntry entry, OutputStream outputStream, long fileSize, long fileOffset, long fileOffsetBlock)
private boolean decryptFSTEntryToStream(FSTEntry entry, OutputStream outputStream, long fileOffsetBlock, long fileOffset, long fileSize)
throws IOException, CheckSumWrongException {
if (entry.isNotInPackage() || entry.getContent() == null) {
outputStream.close();
@ -195,5 +160,4 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle {
public NUSTitle getNUSTitle() {
return title;
}
}

View File

@ -54,27 +54,6 @@ public class FSTDataProviderWUDDataPartition implements FSTDataProvider {
return getChunkOfData(info.getOffset(), entry.getFileOffset() + offset, size, discReader, titleKey);
}
@Override
public void readFileToStream(OutputStream out, FSTEntry entry) throws IOException {
ContentFSTInfo info = partition.getFST().getContentFSTInfos().get((int) entry.getContentFSTID());
if (titleKey == null) {
discReader.readEncryptedToOutputStream(out, partition.getAbsolutePartitionOffset() + info.getOffset() + entry.getFileOffset(), entry.getFileSize());
}
discReader.readDecryptedToOutputStream(out, partition.getAbsolutePartitionOffset() + info.getOffset(), entry.getFileOffset(), entry.getFileSize(),
titleKey, null, false);
}
@Override
public InputStream readFileAsStream(FSTEntry entry, long offset, Optional<Long> size) throws IOException {
ContentFSTInfo info = partition.getFST().getContentFSTInfos().get((int) entry.getContentFSTID());
long fileSize = size.orElse(entry.getFileSize());
if (titleKey == null) {
return discReader.readEncryptedToInputStream(partition.getAbsolutePartitionOffset() + info.getOffset() + entry.getFileOffset() + offset, fileSize);
}
return discReader.readDecryptedToInputStream(partition.getAbsolutePartitionOffset() + info.getOffset(), entry.getFileOffset() + offset, fileSize,
titleKey, null, false);
}
public byte[] getChunkOfData(long contentOffset, long fileoffset, long size, WUDDiscReader discReader, byte[] titleKey) throws IOException {
if (titleKey == null) {
return discReader.readEncryptedToByteArray(partition.getAbsolutePartitionOffset() + contentOffset, fileoffset, (int) size);
@ -82,4 +61,27 @@ public class FSTDataProviderWUDDataPartition implements FSTDataProvider {
return discReader.readDecryptedToByteArray(partition.getAbsolutePartitionOffset() + contentOffset, fileoffset, (int) size, titleKey, null, false);
}
@Override
public void readFileToStream(OutputStream out, FSTEntry entry, long offset, Optional<Long> size) throws IOException {
ContentFSTInfo info = partition.getFST().getContentFSTInfos().get((int) entry.getContentFSTID());
long usedSize = size.orElse(entry.getFileSize());
if (titleKey == null) {
discReader.readEncryptedToStream(out, partition.getAbsolutePartitionOffset() + info.getOffset() + entry.getFileOffset() + offset, usedSize);
}
discReader.readDecryptedToOutputStream(out, partition.getAbsolutePartitionOffset() + info.getOffset(), entry.getFileOffset() + offset, usedSize,
titleKey, null, false);
}
@Override
public InputStream readFileAsStream(FSTEntry entry, long offset, Optional<Long> size) throws IOException {
if (titleKey == null) {
ContentFSTInfo info = partition.getFST().getContentFSTInfos().get((int) entry.getContentFSTID());
long usedSize = size.orElse(entry.getFileSize());
return discReader.readEncryptedToStream(partition.getAbsolutePartitionOffset() + info.getOffset() + entry.getFileOffset() + offset, usedSize);
}
return FSTDataProvider.super.readFileAsStream(entry, offset, size);
}
}

View File

@ -58,7 +58,7 @@ public class NUSDataProviderWUD implements NUSDataProvider {
if (size.isPresent()) {
usedSize = size.get();
}
return discReader.readEncryptedToInputStream(offset, usedSize);
return discReader.readEncryptedToStream(offset, usedSize);
}
@Override

View File

@ -21,13 +21,13 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.Arrays;
import de.mas.wiiu.jnus.implementations.wud.WUDImage;
import de.mas.wiiu.jnus.utils.PipedInputStreamWithException;
import de.mas.wiiu.jnus.utils.cryptography.AESDecryption;
import lombok.Getter;
import lombok.extern.java.Log;
@ -40,42 +40,12 @@ public abstract class WUDDiscReader {
this.image = image;
}
public InputStream readEncryptedToInputStream(long offset, long size) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
new Thread(() -> {
try {
readEncryptedToOutputStream(out, offset, size);
} catch (IOException e) {
e.printStackTrace();
}
}, "readEncryptedToInputStream@" + this.hashCode()).start();
return in;
}
public byte[] readEncryptedToByteArray(long offset, long fileoffset, long size) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
readEncryptedToOutputStream(out, offset + fileoffset, size);
readEncryptedToStream(out, offset + fileoffset, size);
return out.toByteArray();
}
public InputStream readDecryptedToInputStream(long clusterOffset, long offset, long size, byte[] key, byte[] IV, boolean useFixedIV) throws IOException {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);
new Thread(() -> {
try {
readDecryptedToOutputStream(out, clusterOffset, offset, size, key, IV, useFixedIV);
} catch (IOException e) {
e.printStackTrace();
}
}, "readDecryptedToInputStream@" + this.hashCode()).start();
return in;
}
public byte[] readDecryptedToByteArray(long offset, long fileoffset, long size, byte[] key, byte[] IV, boolean useFixedIV) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -83,7 +53,23 @@ public abstract class WUDDiscReader {
return out.toByteArray();
}
public abstract void readEncryptedToOutputStream(OutputStream out, long offset, long size) throws IOException;
public abstract void readEncryptedToStream(OutputStream out, long offset, long size) throws IOException;
public InputStream readEncryptedToStream(long offset, long size) throws IOException {
PipedInputStreamWithException in = new PipedInputStreamWithException();
PipedOutputStream out = new PipedOutputStream(in);
new Thread(() -> {
try {
readEncryptedToStream(out, offset, size);
in.throwException(null);
} catch (Exception e) {
in.throwException(e);
}
}).start();
return in;
}
/**
*

View File

@ -36,7 +36,7 @@ public class WUDDiscReaderCompressed extends WUDDiscReader {
* Expects the .wux format by Exzap. You can more infos about it here. https://gbatemp.net/threads/wii-u-image-wud-compression-tool.397901/
*/
@Override
public void readEncryptedToOutputStream(OutputStream out, long offset, long size) throws IOException {
public void readEncryptedToStream(OutputStream out, long offset, long size) throws IOException {
// make sure there is no out-of-bounds read
WUDImageCompressedInfo info = getImage().getCompressedInfo();

View File

@ -37,7 +37,7 @@ public class WUDDiscReaderSplitted extends WUDDiscReader {
}
@Override
public void readEncryptedToOutputStream(OutputStream outputStream, long offset, long size) throws IOException {
public void readEncryptedToStream(OutputStream outputStream, long offset, long size) throws IOException {
RandomAccessFile input = getFileByOffset(offset);
int bufferSize = 0x8000;

View File

@ -18,6 +18,7 @@ package de.mas.wiiu.jnus.implementations.wud.reader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
@ -30,7 +31,7 @@ public class WUDDiscReaderUncompressed extends WUDDiscReader {
}
@Override
public void readEncryptedToOutputStream(OutputStream outputStream, long offset, long size) throws IOException {
public void readEncryptedToStream(OutputStream outputStream, long offset, long size) throws IOException {
FileInputStream input = new FileInputStream(getImage().getFileHandle());
@ -61,4 +62,11 @@ public class WUDDiscReaderUncompressed extends WUDDiscReader {
outputStream.close();
}
@Override
public InputStream readEncryptedToStream(long offset, long size) throws IOException {
FileInputStream input = new FileInputStream(getImage().getFileHandle());
StreamUtils.skipExactly(input, offset);
return input;
}
}

View File

@ -19,9 +19,11 @@ package de.mas.wiiu.jnus.interfaces;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedOutputStream;
import java.util.Optional;
import de.mas.wiiu.jnus.entities.fst.FSTEntry;
import de.mas.wiiu.jnus.utils.PipedInputStreamWithException;
public interface FSTDataProvider {
public String getName();
@ -34,8 +36,26 @@ public interface FSTDataProvider {
public byte[] readFile(FSTEntry entry, long offset, long size) throws IOException;
public InputStream readFileAsStream(FSTEntry entry, long offset, Optional<Long> size) throws IOException;
default public InputStream readFileAsStream(FSTEntry entry, long offset, Optional<Long> size) throws IOException {
PipedInputStreamWithException in = new PipedInputStreamWithException();
PipedOutputStream out = new PipedOutputStream(in);
public void readFileToStream(OutputStream out, FSTEntry entry) throws IOException;
new Thread(() -> {
try {
readFileToStream(out, entry, offset, size);
in.throwException(null);
} catch (Exception e) {
in.throwException(e);
}
}).start();
return in;
}
default public void readFileToStream(OutputStream out, FSTEntry entry, long offset) throws IOException {
readFileToStream(out, entry, offset, Optional.empty());
}
public void readFileToStream(OutputStream out, FSTEntry entry, long offset, Optional<Long> size) throws IOException;
}