From 2913ccf8b256b15ec44ff1ffd62dfeb845eb08bf Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 10 Apr 2019 18:52:01 +0200 Subject: [PATCH] - Removed the NUSTitlerLoaderWUD - Instead of just parsing the GI partitions, parse now all non-GM partition as "WUDDataPartition". - Simplified and optimized the WUDInfoParser --- src/de/mas/wiiu/jnus/NUSTitleLoaderWUD.java | 115 ------------------ .../implementations/NUSDataProviderWUDGI.java | 99 --------------- .../wud/parser/WUDDataPartition.java | 14 +++ .../wud/parser/WUDGIPartition.java | 22 ---- .../wud/parser/WUDGIPartitionTitle.java | 71 ----------- .../implementations/wud/parser/WUDInfo.java | 23 +--- .../wud/parser/WUDInfoParser.java | 115 ++++++++---------- 7 files changed, 71 insertions(+), 388 deletions(-) delete mode 100644 src/de/mas/wiiu/jnus/NUSTitleLoaderWUD.java delete mode 100644 src/de/mas/wiiu/jnus/implementations/NUSDataProviderWUDGI.java create mode 100644 src/de/mas/wiiu/jnus/implementations/wud/parser/WUDDataPartition.java delete mode 100644 src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartition.java delete mode 100644 src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartitionTitle.java diff --git a/src/de/mas/wiiu/jnus/NUSTitleLoaderWUD.java b/src/de/mas/wiiu/jnus/NUSTitleLoaderWUD.java deleted file mode 100644 index 5f4d9ba..0000000 --- a/src/de/mas/wiiu/jnus/NUSTitleLoaderWUD.java +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2016-2018 Maschell - * - * This program 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. - * - * This program 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 this program. If not, see . - ****************************************************************************/ -package de.mas.wiiu.jnus; - -import java.io.File; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.List; - -import de.mas.wiiu.jnus.implementations.NUSDataProvider; -import de.mas.wiiu.jnus.implementations.NUSDataProviderWUD; -import de.mas.wiiu.jnus.implementations.NUSDataProviderWUDGI; -import de.mas.wiiu.jnus.implementations.wud.WUDImage; -import de.mas.wiiu.jnus.implementations.wud.parser.WUDInfo; -import de.mas.wiiu.jnus.implementations.wud.parser.WUDInfoParser; -import lombok.val; -import lombok.extern.java.Log; - -@Log -public final class NUSTitleLoaderWUD extends NUSTitleLoader { - - private NUSTitleLoaderWUD() { - super(); - } - - public static List loadNUSTitle(String WUDPath) throws Exception { - return loadNUSTitle(WUDPath, (byte[]) null); - } - - public static List loadNUSTitle(String WUDPath, File key) throws Exception { - byte[] data = Files.readAllBytes(key.toPath()); - if (data == null) { - log.warning("Failed to read the key file."); - return new ArrayList<>(); - } - return loadNUSTitle(WUDPath, data); - } - - public static List loadNUSTitleDev(String WUDPath) throws Exception { - return loadNUSTitle(WUDPath, null, true); - } - - public static List loadNUSTitle(String WUDPath, byte[] titleKey) throws Exception { - return loadNUSTitle(WUDPath, titleKey, false); - } - - public static List loadNUSTitle(String WUDPath, byte[] titleKey, boolean forceNoKey) throws Exception { - byte[] usedTitleKey = titleKey; - File wudFile = new File(WUDPath); - if (!wudFile.exists()) { - log.warning(WUDPath + " does not exist."); - System.exit(1); - } - - WUDImage image = new WUDImage(wudFile); - if (usedTitleKey == null && !forceNoKey) { - File keyFile = new File(wudFile.getParentFile().getPath() + File.separator + Settings.WUD_KEY_FILENAME); - if (!keyFile.exists()) { - log.warning(keyFile.getAbsolutePath() + " does not exist and no title key was provided."); - return new ArrayList<>(); - } - usedTitleKey = Files.readAllBytes(keyFile.toPath()); - } - WUDInfo wudInfo = WUDInfoParser.createAndLoad(image.getWUDDiscReader(), usedTitleKey); - - if (wudInfo == null) { - log.warning("Failed to parse any WUDInfo"); - return new ArrayList<>(); - } - - List result = new ArrayList<>(); - - for (val gamePartition : wudInfo.getGamePartitions()) { - NUSTitleConfig config = new NUSTitleConfig(); - NUSTitleLoader loader = new NUSTitleLoaderWUD(); - - config.setWUDGamePartition(gamePartition); - config.setWUDInfo(wudInfo); - result.add(loader.loadNusTitle(config)); - } - - for (val giPartitionTitle : wudInfo.getGIPartitionTitles()) { - NUSTitleConfig config = new NUSTitleConfig(); - NUSTitleLoader loader = new NUSTitleLoaderWUD(); - - config.setWUDGIPartitionTitle(giPartitionTitle); - config.setWUDInfo(wudInfo); - result.add(loader.loadNusTitle(config)); - } - return result; - } - - @Override - protected NUSDataProvider getDataProvider(NUSTitle title, NUSTitleConfig config) { - if (config.getWUDGIPartitionTitle() != null) { - return new NUSDataProviderWUDGI(title, config.getWUDGIPartitionTitle(), config.getWUDInfo().getWUDDiscReader(), config.getWUDInfo().getTitleKey()); - } - return new NUSDataProviderWUD(title, config.getWUDGamePartition(), config.getWUDInfo().getWUDDiscReader()); - } - -} diff --git a/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWUDGI.java b/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWUDGI.java deleted file mode 100644 index eb60d11..0000000 --- a/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWUDGI.java +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2016-2018 Maschell - * - * This program 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. - * - * This program 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 this program. If not, see . - ****************************************************************************/ -package de.mas.wiiu.jnus.implementations; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Optional; - -import de.mas.wiiu.jnus.NUSTitle; -import de.mas.wiiu.jnus.Settings; -import de.mas.wiiu.jnus.entities.TMD; -import de.mas.wiiu.jnus.entities.content.Content; -import de.mas.wiiu.jnus.implementations.wud.parser.WUDGIPartitionTitle; -import de.mas.wiiu.jnus.implementations.wud.reader.WUDDiscReader; -import lombok.Getter; - -public class NUSDataProviderWUDGI extends NUSDataProvider { - @Getter private final WUDGIPartitionTitle giPartitionTitle; - @Getter private final WUDDiscReader discReader; - - private final byte[] titleKey; - - private final TMD tmd; - - public NUSDataProviderWUDGI(NUSTitle title, WUDGIPartitionTitle giPartitionTitle, WUDDiscReader discReader, byte[] titleKey) { - super(title); - this.giPartitionTitle = giPartitionTitle; - this.discReader = discReader; - this.titleKey = titleKey; - this.tmd = TMD.parseTMD(getRawTMD()); - } - - @Override - public InputStream getInputStreamFromContent(Content content, long fileOffsetBlock, Optional size) throws IOException { - InputStream in = getGiPartitionTitle().getFileAsStream(content.getFilename(), getDiscReader(), fileOffsetBlock, titleKey); - return in; - } - - @Override - public byte[] getChunkFromContent(Content content, long offset, int size) throws IOException { - return getGiPartitionTitle().getFileAsByte(content.getFilename(), getDiscReader(), offset, size, titleKey); - } - - @Override - public byte[] getContentH3Hash(Content content) throws IOException { - return getGiPartitionTitle().getFileAsByte(String.format("%08X.h3", content.getID()), getDiscReader(), titleKey); - } - - public TMD getTMD() { - return tmd; - } - - @Override - public byte[] getRawTMD() { - try { - return getGiPartitionTitle().getFileAsByte(Settings.TMD_FILENAME, getDiscReader(), titleKey); - } catch (IOException e) { - return new byte[0]; - } - } - - @Override - public byte[] getRawTicket() { - try { - return getGiPartitionTitle().getFileAsByte(Settings.TICKET_FILENAME, getDiscReader(), titleKey); - } catch (IOException e) { - return new byte[0]; - } - } - - @Override - public byte[] getRawCert() throws IOException { - try { - return getGiPartitionTitle().getFileAsByte(Settings.CERT_FILENAME, getDiscReader(), titleKey); - } catch (IOException e) { - return new byte[0]; - } - } - - @Override - public void cleanup() { - // We don't need it - } - -} diff --git a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDDataPartition.java b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDDataPartition.java new file mode 100644 index 0000000..5038537 --- /dev/null +++ b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDDataPartition.java @@ -0,0 +1,14 @@ +package de.mas.wiiu.jnus.implementations.wud.parser; + +import de.mas.wiiu.jnus.entities.fst.FST; +import lombok.Getter; + +public class WUDDataPartition extends WUDPartition { + @Getter private final FST FST; + + public WUDDataPartition(String partitionName, long partitionOffset, FST curFST) { + super(partitionName, partitionOffset); + this.FST = curFST; + } + +} diff --git a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartition.java b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartition.java deleted file mode 100644 index 8085ab6..0000000 --- a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartition.java +++ /dev/null @@ -1,22 +0,0 @@ -package de.mas.wiiu.jnus.implementations.wud.parser; - -import java.util.ArrayList; -import java.util.List; - -import de.mas.wiiu.jnus.entities.fst.FST; -import lombok.Getter; -import lombok.val; -import lombok.extern.java.Log; - -@Log -public class WUDGIPartition extends WUDPartition { - @Getter private final List titles = new ArrayList<>(); - - public WUDGIPartition(String partitionName, long partitionOffset, FST fst) { - super(partitionName, partitionOffset); - for (val curDir : fst.getRoot().getDirChildren()) { - titles.add(new WUDGIPartitionTitle(fst, curDir, partitionOffset)); - } - } - -} diff --git a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartitionTitle.java b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartitionTitle.java deleted file mode 100644 index 1e56cef..0000000 --- a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDGIPartitionTitle.java +++ /dev/null @@ -1,71 +0,0 @@ -package de.mas.wiiu.jnus.implementations.wud.parser; - -import java.io.IOException; -import java.io.InputStream; - -import de.mas.wiiu.jnus.Settings; -import de.mas.wiiu.jnus.entities.content.ContentFSTInfo; -import de.mas.wiiu.jnus.entities.fst.FST; -import de.mas.wiiu.jnus.entities.fst.FSTEntry; -import de.mas.wiiu.jnus.implementations.wud.reader.WUDDiscReader; -import de.mas.wiiu.jnus.utils.StreamUtils; -import lombok.Getter; - -public class WUDGIPartitionTitle { - private final FST fst; - private final FSTEntry rootEntry; - - @Getter private final long partitionOffset; - - public WUDGIPartitionTitle(FST fst, FSTEntry rootEntry, long partitionOffset) { - this.fst = fst; - this.rootEntry = rootEntry; - this.partitionOffset = partitionOffset; - } - - public byte[] getFileAsByte(String filename, WUDDiscReader discReader, byte[] titleKey) throws IOException { - FSTEntry entry = getEntryByFilename(rootEntry, filename); - return StreamUtils.getBytesFromStream(getFileAsStream(filename, discReader, 0, titleKey), (int) entry.getFileSize()); - } - - public InputStream getFileAsStream(String filename, WUDDiscReader discReader, long offsetInFile, byte[] titleKey) throws IOException { - FSTEntry entry = getEntryByFilename(rootEntry, filename); - ContentFSTInfo info = fst.getContentFSTInfos().get((int) entry.getContentFSTID()); - return getFileAsStream(info.getOffset(), entry.getFileOffset() + offsetInFile, entry.getFileSize(), discReader, titleKey); - } - - public InputStream getFileAsStream(long contentOffset, long fileoffset, long size, WUDDiscReader discReader, byte[] titleKey) throws IOException { - return discReader.readDecryptedToInputStream(getAbsoluteReadOffset() + contentOffset, fileoffset, size, titleKey, null, false); - } - - public byte[] getFileAsData(long contentOffset, long fileoffset, long size, WUDDiscReader discReader, byte[] titleKey) throws IOException { - return discReader.readDecryptedToByteArray(getAbsoluteReadOffset() + contentOffset, fileoffset, (int) size, titleKey, null, false); - } - - public byte[] getFileAsByte(String filename, WUDDiscReader discReader, long offsetInFile, int size, byte[] titleKey) throws IOException { - FSTEntry entry = getEntryByFilename(rootEntry, filename); - ContentFSTInfo info = fst.getContentFSTInfos().get((int) entry.getContentFSTID()); - - return getFileAsData(info.getOffset(), entry.getFileOffset() + offsetInFile, size, discReader, titleKey); - } - - private long getAbsoluteReadOffset() { - return (long) Settings.WIIU_DECRYPTED_AREA_OFFSET + getPartitionOffset(); - } - - private static FSTEntry getEntryByFilename(FSTEntry root, String filename) { - for (FSTEntry cur : root.getFileChildren()) { - if (cur.getFilename().equalsIgnoreCase(filename)) { - return cur; - } - } - for (FSTEntry cur : root.getDirChildren()) { - FSTEntry dir_result = getEntryByFilename(cur, filename); - if (dir_result != null) { - return dir_result; - } - } - return null; - } - -} diff --git a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfo.java b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfo.java index 42f4fab..9409c0b 100644 --- a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfo.java +++ b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfo.java @@ -16,36 +16,25 @@ ****************************************************************************/ package de.mas.wiiu.jnus.implementations.wud.parser; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import de.mas.wiiu.jnus.implementations.wud.reader.WUDDiscReader; -import lombok.AccessLevel; import lombok.Data; import lombok.Getter; -import lombok.Setter; @Data public class WUDInfo { - private final byte[] titleKey; - + @Getter private final byte[] titleKey; private final WUDDiscReader WUDDiscReader; - private final Map partitions = new HashMap<>(); - - @Getter(AccessLevel.PRIVATE) @Setter(AccessLevel.PROTECTED) private String gamePartitionName; - - public void addPartion(String partitionName, WUDGamePartition partition) { - getPartitions().put(partitionName, partition); - } + private final List partitions = new ArrayList<>(); public List getGamePartitions() { - return partitions.values().stream().filter(p -> p instanceof WUDGamePartition).map(p -> (WUDGamePartition) p).collect(Collectors.toList()); + return partitions.stream().filter(p -> p instanceof WUDGamePartition).map(p -> (WUDGamePartition) p).collect(Collectors.toList()); } - public List getGIPartitionTitles() { - return partitions.values().stream().filter(p -> p instanceof WUDGIPartition).flatMap(p -> ((WUDGIPartition) p).getTitles().stream()) - .collect(Collectors.toList()); + public List getDataPartitions() { + return partitions.stream().filter(p -> p instanceof WUDDataPartition).map(p -> ((WUDDataPartition) p)).collect(Collectors.toList()); } } diff --git a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfoParser.java b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfoParser.java index 4509dfc..2132d65 100644 --- a/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfoParser.java +++ b/src/de/mas/wiiu/jnus/implementations/wud/parser/WUDInfoParser.java @@ -21,11 +21,14 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.text.ParseException; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import de.mas.wiiu.jnus.FSTUtils; import de.mas.wiiu.jnus.Settings; import de.mas.wiiu.jnus.entities.content.ContentFSTInfo; import de.mas.wiiu.jnus.entities.fst.FST; @@ -52,7 +55,7 @@ public final class WUDInfoParser { // } - public static WUDInfo createAndLoad(WUDDiscReader discReader, byte[] titleKey) throws IOException { + public static WUDInfo createAndLoad(WUDDiscReader discReader, byte[] titleKey) throws IOException, ParseException { WUDInfo result = new WUDInfo(titleKey, discReader); byte[] PartitionTocBlock; @@ -66,15 +69,14 @@ public final class WUDInfoParser { // verify DiscKey before proceeding if (!Arrays.equals(Arrays.copyOfRange(PartitionTocBlock, 0, 4), DECRYPTED_AREA_SIGNATURE)) { // log.info("Decryption of PartitionTocBlock failed"); - throw new IOException("Decryption of PartitionTocBlock failed"); + throw new ParseException("Decryption of PartitionTocBlock failed", 0); } - result.getPartitions().clear(); - result.getPartitions().putAll(readGamePartitions(result, PartitionTocBlock)); + result.getPartitions().addAll(parsePartitions(result, PartitionTocBlock)); return result; } - private static Map readGamePartitions(WUDInfo wudInfo, byte[] partitionTocBlock) throws IOException { + private static Collection parsePartitions(WUDInfo wudInfo, byte[] partitionTocBlock) throws IOException, ParseException { ByteBuffer buffer = ByteBuffer.allocate(partitionTocBlock.length); buffer.order(ByteOrder.BIG_ENDIAN); @@ -83,8 +85,7 @@ public final class WUDInfoParser { int partitionCount = (int) ByteUtils.getUnsingedIntFromBytes(partitionTocBlock, 0x1C, ByteOrder.BIG_ENDIAN); - Map internalPartitions = new HashMap<>(); - Map gamePartitions = new HashMap<>(); + Map internalPartitions = new HashMap<>(); // populate partition information from decrypted TOC for (int i = 0; i < partitionCount; i++) { @@ -104,21 +105,14 @@ public final class WUDInfoParser { long partitionOffset = ((tmp * (long) 0x8000) - 0x10000); - WUDPartition partition = new WUDPartition(partitionName, partitionOffset); - - byte[] header = wudInfo.getWUDDiscReader().readEncryptedToByteArray(partition.getPartitionOffset() + 0x10000, 0, 0x8000); - WUDPartitionHeader partitionHeader = WUDPartitionHeader.parseHeader(header); - partition.setPartitionHeader(partitionHeader); - - internalPartitions.put(partitionName, partition); + internalPartitions.put(partitionName, partitionOffset); } val siPartitionOpt = internalPartitions.entrySet().stream().filter(e -> e.getKey().startsWith("SI")).findFirst(); - val siPartitionPair = siPartitionOpt.orElseThrow(() -> new RuntimeException("SI partition not foud.")); + val siPartitionPair = siPartitionOpt.orElseThrow(() -> new ParseException("SI partition not found.", 0)); // siPartition - long siPartitionOffset = siPartitionPair.getValue().getPartitionOffset(); - val siPartition = siPartitionPair.getValue(); + long siPartitionOffset = siPartitionPair.getValue(); byte[] fileTableBlock; @@ -131,66 +125,73 @@ public final class WUDInfoParser { if (!Arrays.equals(Arrays.copyOfRange(fileTableBlock, 0, 4), PARTITION_FILE_TABLE_SIGNATURE)) { log.info("FST Decrpytion failed"); - throw new RuntimeException("Failed to decrypt the FST of the SI partition."); + throw new ParseException("Failed to decrypt the FST of the SI partition.", 0); } FST siFST = FST.parseFST(fileTableBlock, null); + Map partitionsResult = new HashMap<>(); + for (val dirChilden : siFST.getRoot().getDirChildren()) { // The SI partition contains the tmd, cert and tik for every GM partition. - byte[] rawTIK = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_TICKET_FILENAME, siPartition, siFST, wudInfo.getWUDDiscReader(), - wudInfo.getTitleKey()); - byte[] rawTMD = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_TMD_FILENAME, siPartition, siFST, wudInfo.getWUDDiscReader(), - wudInfo.getTitleKey()); - byte[] rawCert = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_CERT_FILENAME, siPartition, siFST, wudInfo.getWUDDiscReader(), - wudInfo.getTitleKey()); + byte[] rawTIK = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_TICKET_FILENAME, siPartitionOffset, siFST, + wudInfo.getWUDDiscReader(), wudInfo.getTitleKey()); + byte[] rawTMD = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_TMD_FILENAME, siPartitionOffset, siFST, + wudInfo.getWUDDiscReader(), wudInfo.getTitleKey()); + byte[] rawCert = getFSTEntryAsByte(dirChilden.getFullPath() + File.separator + WUD_CERT_FILENAME, siPartitionOffset, siFST, + wudInfo.getWUDDiscReader(), wudInfo.getTitleKey()); String partitionName = "GM" + Utils.ByteArrayToString(Arrays.copyOfRange(rawTIK, 0x1DC, 0x1DC + 0x08)); val curPartitionOpt = internalPartitions.entrySet().stream().filter(e -> e.getKey().startsWith(partitionName)).findFirst(); - val curPartitionPair = curPartitionOpt.orElseThrow(() -> new RuntimeException("partition not foud.")); + val curPartitionPair = curPartitionOpt.orElseThrow(() -> new ParseException("partition not foud.", 0)); + long curPartitionOffset = curPartitionPair.getValue(); - WUDGamePartition curPartition = new WUDGamePartition(curPartitionPair.getKey(), curPartitionPair.getValue().getPartitionOffset(), rawTMD, rawCert, - rawTIK); - curPartition.setPartitionHeader(curPartitionPair.getValue().getPartitionHeader()); - gamePartitions.put(curPartitionPair.getKey(), curPartition); + WUDGamePartition curPartition = new WUDGamePartition(curPartitionPair.getKey(), curPartitionOffset, rawTMD, rawCert, rawTIK); + byte[] header = wudInfo.getWUDDiscReader().readEncryptedToByteArray(curPartition.getPartitionOffset() + 0x10000, 0, 0x8000); + WUDPartitionHeader partitionHeader = WUDPartitionHeader.parseHeader(header); + curPartition.setPartitionHeader(partitionHeader); + partitionsResult.put(curPartitionPair.getKey(), curPartition); } - val giPartitions = internalPartitions.entrySet().stream().filter(e -> e.getKey().startsWith("GI")).collect(Collectors.toList()); - for (val giPartition : giPartitions) { - String curPartionName = giPartition.getKey(); - WUDPartition curPartition = giPartition.getValue(); + val dataPartitions = internalPartitions.entrySet().stream().filter(e -> !e.getKey().startsWith("GM")).collect(Collectors.toList()); + for (val dataPartition : dataPartitions) { + String curPartionName = dataPartition.getKey(); + long partitionOffset = dataPartition.getValue(); - byte[] curFileTableBlock = wudInfo.getWUDDiscReader().readDecryptedToByteArray( - Settings.WIIU_DECRYPTED_AREA_OFFSET + curPartition.getPartitionOffset(), 0, 0x8000, wudInfo.getTitleKey(), null, true); + byte[] curFileTableBlock; + if (wudInfo.getTitleKey() == null) { + curFileTableBlock = wudInfo.getWUDDiscReader().readEncryptedToByteArray(Settings.WIIU_DECRYPTED_AREA_OFFSET + partitionOffset, 0, 0x8000); + } else { + curFileTableBlock = wudInfo.getWUDDiscReader().readDecryptedToByteArray(Settings.WIIU_DECRYPTED_AREA_OFFSET + partitionOffset, 0, 0x8000, + wudInfo.getTitleKey(), null, true); + } if (!Arrays.equals(Arrays.copyOfRange(curFileTableBlock, 0, 4), WUDInfoParser.PARTITION_FILE_TABLE_SIGNATURE)) { log.info("FST Decrpytion failed"); - throw new RuntimeException("Failed to decrypt the FST of the SI partition."); + throw new ParseException("Failed to decrypt the FST of the " + curPartionName + " partition.", 0); } FST curFST = FST.parseFST(curFileTableBlock, null); - WUDGIPartition curNewPartition = new WUDGIPartition(curPartionName, curPartition.getPartitionOffset(), curFST); - curPartition.setPartitionHeader(curPartition.getPartitionHeader()); + WUDDataPartition curDataPartition = new WUDDataPartition(curPartionName, partitionOffset, curFST); - gamePartitions.put(curPartionName, curNewPartition); + byte[] header = wudInfo.getWUDDiscReader().readEncryptedToByteArray(curDataPartition.getPartitionOffset() + 0x10000, 0, 0x8000); + WUDPartitionHeader partitionHeader = WUDPartitionHeader.parseHeader(header); + curDataPartition.setPartitionHeader(partitionHeader); + + partitionsResult.put(curPartionName, curDataPartition); } - return gamePartitions; + return partitionsResult.values(); } - private static byte[] getFSTEntryAsByte(String filePath, WUDPartition partition, FST fst, WUDDiscReader discReader, byte[] key) throws IOException { - FSTEntry entry = getEntryByFullPath(fst.getRoot(), filePath); - if(entry == null) { - String errormsg = "FSTEntry with name \"" + filePath + "\" not found."; - log.warning(errormsg); - throw new FileNotFoundException(errormsg); - } + private static byte[] getFSTEntryAsByte(String filePath, long partitionOffset, FST fst, WUDDiscReader discReader, byte[] key) throws IOException { + FSTEntry entry = FSTUtils.getEntryByFullPath(fst.getRoot(), filePath).orElseThrow(() -> new FileNotFoundException(filePath + " was not found.")); ContentFSTInfo info = fst.getContentFSTInfos().get((int) entry.getContentFSTID()); if (key == null) { - return discReader.readEncryptedToByteArray(Settings.WIIU_DECRYPTED_AREA_OFFSET + (long) partition.getPartitionOffset() + (long) info.getOffset(), + return discReader.readEncryptedToByteArray(((long) Settings.WIIU_DECRYPTED_AREA_OFFSET) + partitionOffset + (long) info.getOffset(), entry.getFileOffset(), (int) entry.getFileSize()); } @@ -199,22 +200,8 @@ public final class WUDInfoParser { byteBuffer.position(0x08); byte[] IV = byteBuffer.putLong(entry.getFileOffset() >> 16).array(); - return discReader.readDecryptedToByteArray(Settings.WIIU_DECRYPTED_AREA_OFFSET + (long) partition.getPartitionOffset() + (long) info.getOffset(), - entry.getFileOffset(), (int) entry.getFileSize(), key, IV, false); + return discReader.readDecryptedToByteArray(((long) Settings.WIIU_DECRYPTED_AREA_OFFSET) + partitionOffset + info.getOffset(), entry.getFileOffset(), + (int) entry.getFileSize(), key, IV, false); } - private static FSTEntry getEntryByFullPath(FSTEntry root, String filePath) { - for (FSTEntry cur : root.getFileChildren()) { - if (cur.getFullPath().equals(filePath)) { - return cur; - } - } - for (FSTEntry cur : root.getDirChildren()) { - FSTEntry dir_result = getEntryByFullPath(cur, filePath); - if (dir_result != null) { - return dir_result; - } - } - return null; - } }