- 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<ByteArrayWrapper, Integer> sectorHashes = new HashMap<>();
Map<Integer, Integer> sectorMapping = new TreeMap<>(); 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; int bufferSize = WUDImageCompressedInfo.SECTOR_SIZE;
byte[] blockBuffer = new byte[bufferSize]; byte[] blockBuffer = new byte[bufferSize];
@ -168,8 +168,8 @@ public final class WUDService {
log.warning("Filesize is different"); log.warning("Filesize is different");
return false; return false;
} }
InputStream in1 = firstImage.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE); InputStream in1 = firstImage.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
InputStream in2 = secondImage.getWUDDiscReader().readEncryptedToInputStream(0, WUDImage.WUD_FILESIZE); InputStream in2 = secondImage.getWUDDiscReader().readEncryptedToStream(0, WUDImage.WUD_FILESIZE);
boolean result = true; boolean result = true;
int bufferSize = 1024 * 1024 + 19; int bufferSize = 1024 * 1024 + 19;
@ -249,7 +249,7 @@ public final class WUDService {
} }
log.info("Writing decompressed file to: " + outputFile.getAbsolutePath()); 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); OutputStream out = new FileOutputStream(outputFile);
int bufferSize = 1024 * 1024; 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"); 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; int bufferSize = 1024 * 1024 * 10;
long totalread = 0; long totalread = 0;

View File

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

View File

@ -54,27 +54,6 @@ public class FSTDataProviderWUDDataPartition implements FSTDataProvider {
return getChunkOfData(info.getOffset(), entry.getFileOffset() + offset, size, discReader, titleKey); 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 { public byte[] getChunkOfData(long contentOffset, long fileoffset, long size, WUDDiscReader discReader, byte[] titleKey) throws IOException {
if (titleKey == null) { if (titleKey == null) {
return discReader.readEncryptedToByteArray(partition.getAbsolutePartitionOffset() + contentOffset, fileoffset, (int) size); 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); 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()) { if (size.isPresent()) {
usedSize = size.get(); usedSize = size.get();
} }
return discReader.readEncryptedToInputStream(offset, usedSize); return discReader.readEncryptedToStream(offset, usedSize);
} }
@Override @Override

View File

@ -21,13 +21,13 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import de.mas.wiiu.jnus.implementations.wud.WUDImage; import de.mas.wiiu.jnus.implementations.wud.WUDImage;
import de.mas.wiiu.jnus.utils.PipedInputStreamWithException;
import de.mas.wiiu.jnus.utils.cryptography.AESDecryption; import de.mas.wiiu.jnus.utils.cryptography.AESDecryption;
import lombok.Getter; import lombok.Getter;
import lombok.extern.java.Log; import lombok.extern.java.Log;
@ -40,42 +40,12 @@ public abstract class WUDDiscReader {
this.image = image; 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 { public byte[] readEncryptedToByteArray(long offset, long fileoffset, long size) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
readEncryptedToOutputStream(out, offset + fileoffset, size); readEncryptedToStream(out, offset + fileoffset, size);
return out.toByteArray(); 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 { public byte[] readDecryptedToByteArray(long offset, long fileoffset, long size, byte[] key, byte[] IV, boolean useFixedIV) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -83,7 +53,23 @@ public abstract class WUDDiscReader {
return out.toByteArray(); 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/ * 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 @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 // make sure there is no out-of-bounds read
WUDImageCompressedInfo info = getImage().getCompressedInfo(); WUDImageCompressedInfo info = getImage().getCompressedInfo();

View File

@ -37,7 +37,7 @@ public class WUDDiscReaderSplitted extends WUDDiscReader {
} }
@Override @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); RandomAccessFile input = getFileByOffset(offset);
int bufferSize = 0x8000; int bufferSize = 0x8000;

View File

@ -18,6 +18,7 @@ package de.mas.wiiu.jnus.implementations.wud.reader;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Arrays; import java.util.Arrays;
@ -30,7 +31,7 @@ public class WUDDiscReaderUncompressed extends WUDDiscReader {
} }
@Override @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()); FileInputStream input = new FileInputStream(getImage().getFileHandle());
@ -61,4 +62,11 @@ public class WUDDiscReaderUncompressed extends WUDDiscReader {
outputStream.close(); 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedOutputStream;
import java.util.Optional; import java.util.Optional;
import de.mas.wiiu.jnus.entities.fst.FSTEntry; import de.mas.wiiu.jnus.entities.fst.FSTEntry;
import de.mas.wiiu.jnus.utils.PipedInputStreamWithException;
public interface FSTDataProvider { public interface FSTDataProvider {
public String getName(); public String getName();
@ -34,8 +36,26 @@ public interface FSTDataProvider {
public byte[] readFile(FSTEntry entry, long offset, long size) throws IOException; 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;
} }