diff --git a/src/de/mas/wiiu/jnus/NUSTitleLoader.java b/src/de/mas/wiiu/jnus/NUSTitleLoader.java index a4ad788..9ed5a20 100644 --- a/src/de/mas/wiiu/jnus/NUSTitleLoader.java +++ b/src/de/mas/wiiu/jnus/NUSTitleLoader.java @@ -27,6 +27,9 @@ import de.mas.wiiu.jnus.entities.TMD; import de.mas.wiiu.jnus.entities.Ticket; import de.mas.wiiu.jnus.entities.content.Content; import de.mas.wiiu.jnus.entities.fst.FST; +import de.mas.wiiu.jnus.entities.fst.FSTEntry; +import de.mas.wiiu.jnus.implementations.FSTDataProviderNUSTitle; +import de.mas.wiiu.jnus.interfaces.FSTDataProvider; import de.mas.wiiu.jnus.interfaces.NUSDataProvider; import de.mas.wiiu.jnus.utils.StreamUtils; import de.mas.wiiu.jnus.utils.cryptography.AESDecryption; @@ -63,12 +66,22 @@ public class NUSTitleLoader { } result.setTicket(ticket); + // If we have just content, we don't have a FST. + if (tmd.getAllContents().size() == 1) { + // The only way to check if the key is right, is by trying to decrypt the whole thing. + FSTDataProvider dp = new FSTDataProviderNUSTitle(result); + for (FSTEntry children : dp.getRoot().getChildren()) { + dp.readFile(children); + } + return result; + } + // If we have more than one content, the index 0 is the FST. Content fstContent = tmd.getContentByIndex(0); InputStream fstContentEncryptedStream = dataProvider.getInputStreamFromContent(fstContent, 0, Optional.of(fstContent.getEncryptedFileSize())); byte[] fstBytes = StreamUtils.getBytesFromStream(fstContentEncryptedStream, (int) fstContent.getEncryptedFileSize()); - + if (fstContent.isEncrypted()) { AESDecryption aesDecryption = new AESDecryption(ticket.getDecryptedKey(), new byte[0x10]); if (fstBytes.length % 0x10 != 0) { diff --git a/src/de/mas/wiiu/jnus/entities/fst/FSTEntry.java b/src/de/mas/wiiu/jnus/entities/fst/FSTEntry.java index abf43a5..c5b84a6 100644 --- a/src/de/mas/wiiu/jnus/entities/fst/FSTEntry.java +++ b/src/de/mas/wiiu/jnus/entities/fst/FSTEntry.java @@ -88,6 +88,16 @@ public class FSTEntry { param.setDir(true); return new FSTEntry(param); } + + public static FSTEntry createFSTEntry(FSTEntry parent, String filename, Content content) { + FSTEntryParam param = new FSTEntryParam(); + param.setFileNameSupplier(() -> filename); + param.setFileSize(content.getDecryptedFileSize()); + param.setContent(content); + param.setDir(false); + param.setParent(parent); + return new FSTEntry(param); + } public String getFilename() { if (filename == null) { diff --git a/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java b/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java index f61b8fc..94e8871 100644 --- a/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java +++ b/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java @@ -21,9 +21,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Optional; +import java.util.stream.Collectors; import de.mas.wiiu.jnus.NUSTitle; import de.mas.wiiu.jnus.entities.content.Content; +import de.mas.wiiu.jnus.entities.fst.FST; import de.mas.wiiu.jnus.entities.fst.FSTEntry; import de.mas.wiiu.jnus.interfaces.FSTDataProvider; import de.mas.wiiu.jnus.interfaces.HasNUSTitle; @@ -38,16 +40,30 @@ import lombok.extern.java.Log; @Log public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle { private final NUSTitle title; + private final FSTEntry rootEntry; @Getter @Setter private String name; public FSTDataProviderNUSTitle(NUSTitle title) { this.title = title; this.name = String.format("%016X", title.getTMD().getTitleID()); + + FST fst = title.getFST(); + if (fst != null) { + rootEntry = title.getFST().getRoot(); + } else if (title.getTMD().getContentCount() == 1) { + // If the tmd has only one content file, it has not FST. We have to create our own FST. + Content c = title.getTMD().getAllContents().values().stream().collect(Collectors.toList()).get(0); + FSTEntry root = FSTEntry.getRootFSTEntry(); + FSTEntry.createFSTEntry(root, "data.bin", c); // Will add this title root. + rootEntry = root; + } else { + rootEntry = null; + } } @Override public FSTEntry getRoot() { - return title.getFST().getRoot(); + return rootEntry; } @Override