mirror of
https://github.com/Maschell/JNUSLib.git
synced 2024-11-22 16:09:18 +01:00
Add support for wumad data partitions
This commit is contained in:
parent
6d9cb2b155
commit
3715b757ab
@ -12,6 +12,8 @@ import javax.xml.parsers.ParserConfigurationException;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import de.mas.wiiu.jnus.implementations.FSTDataProviderNUSTitle;
|
import de.mas.wiiu.jnus.implementations.FSTDataProviderNUSTitle;
|
||||||
|
import de.mas.wiiu.jnus.implementations.FSTDataProviderWumadDataPartition;
|
||||||
|
import de.mas.wiiu.jnus.implementations.NUSDataProviderWumad;
|
||||||
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadGamePartition;
|
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadGamePartition;
|
||||||
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadInfo;
|
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadInfo;
|
||||||
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadParser;
|
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadParser;
|
||||||
@ -50,6 +52,10 @@ public class WumadLoader {
|
|||||||
result.add(res);
|
result.add(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (val dataPartition : wumadInfo.getDataPartitions()) {
|
||||||
|
result.add(new FSTDataProviderWumadDataPartition(dataPartition, wumadInfo.getZipFile()));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package de.mas.wiiu.jnus.implementations;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import de.mas.wiiu.jnus.entities.fst.FSTEntry;
|
||||||
|
import de.mas.wiiu.jnus.implementations.wud.wumad.WumadDataPartition;
|
||||||
|
import de.mas.wiiu.jnus.interfaces.FSTDataProvider;
|
||||||
|
import de.mas.wiiu.jnus.utils.StreamUtils;
|
||||||
|
|
||||||
|
public class FSTDataProviderWumadDataPartition implements FSTDataProvider {
|
||||||
|
private final WumadDataPartition dataPartition;
|
||||||
|
private final ZipFile zipFile;
|
||||||
|
|
||||||
|
public FSTDataProviderWumadDataPartition(WumadDataPartition dataPartition, ZipFile zipFile) {
|
||||||
|
this.dataPartition = dataPartition;
|
||||||
|
this.zipFile = zipFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return dataPartition.getPartitionName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FSTEntry getRoot() {
|
||||||
|
return dataPartition.getFST().getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readFileToStream(OutputStream out, FSTEntry entry, long offset, long size) throws IOException {
|
||||||
|
StreamUtils.saveInputStreamToOutputStream(readFileAsStream(entry, offset, size), out, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream readFileAsStream(FSTEntry entry, long offset, long size) throws IOException {
|
||||||
|
ZipEntry zipEntry = zipFile.stream()
|
||||||
|
.filter(e -> e.getName().equals(String.format("p%s.s%04d.00000000.app", dataPartition.getPartitionName(), entry.getContentIndex()))).findFirst()
|
||||||
|
.orElseThrow(() -> new FileNotFoundException());
|
||||||
|
|
||||||
|
InputStream in = zipFile.getInputStream(zipEntry);
|
||||||
|
StreamUtils.skipExactly(in, offset + entry.getFileOffset());
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package de.mas.wiiu.jnus.implementations.wud.wumad;
|
||||||
|
|
||||||
|
import de.mas.wiiu.jnus.entities.fst.FST;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class WumadDataPartition extends WumadPartition {
|
||||||
|
|
||||||
|
@Getter private final FST FST;
|
||||||
|
|
||||||
|
public WumadDataPartition(String partitionName, FST fst) {
|
||||||
|
super(partitionName);
|
||||||
|
this.FST = fst;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,8 +33,13 @@ public class WumadInfo {
|
|||||||
return partitions.stream().filter(p -> p instanceof WumadGamePartition).map(p -> (WumadGamePartition) p).collect(Collectors.toList());
|
return partitions.stream().filter(p -> p instanceof WumadGamePartition).map(p -> (WumadGamePartition) p).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<WumadDataPartition> getDataPartitions() {
|
||||||
|
return partitions.stream().filter(p -> p instanceof WumadDataPartition).map(p -> ((WumadDataPartition) p)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Setter private ZipFile zipFile;
|
@Setter private ZipFile zipFile;
|
||||||
|
|
||||||
WumadInfo() {
|
WumadInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,11 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
@ -33,9 +37,9 @@ import org.xml.sax.SAXException;
|
|||||||
import de.mas.wiiu.jnus.entities.fst.FST;
|
import de.mas.wiiu.jnus.entities.fst.FST;
|
||||||
import de.mas.wiiu.jnus.entities.fst.FSTEntry;
|
import de.mas.wiiu.jnus.entities.fst.FSTEntry;
|
||||||
import de.mas.wiiu.jnus.implementations.wud.GamePartitionHeader;
|
import de.mas.wiiu.jnus.implementations.wud.GamePartitionHeader;
|
||||||
import de.mas.wiiu.jnus.implementations.wud.parser.WUDGamePartition;
|
|
||||||
import de.mas.wiiu.jnus.utils.FSTUtils;
|
import de.mas.wiiu.jnus.utils.FSTUtils;
|
||||||
import de.mas.wiiu.jnus.utils.StreamUtils;
|
import de.mas.wiiu.jnus.utils.StreamUtils;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
public class WumadParser {
|
public class WumadParser {
|
||||||
|
|
||||||
@ -53,31 +57,54 @@ public class WumadParser {
|
|||||||
ZipFile zipFile = new ZipFile(wumadFile);
|
ZipFile zipFile = new ZipFile(wumadFile);
|
||||||
result.setZipFile(zipFile);
|
result.setZipFile(zipFile);
|
||||||
|
|
||||||
// TODO: some .wumad doesn't have SI files.
|
// Let's get all possible partitions
|
||||||
ZipEntry fst = zipFile.getEntry(SI_FST_FILENAME);
|
Map<String, List<ZipEntry>> allPartitions = zipFile.stream().filter(e -> e.getName().startsWith("p"))
|
||||||
|
.collect(Collectors.groupingBy(e -> e.getName().substring(1, 3)));
|
||||||
|
|
||||||
byte[] fstBytes = StreamUtils.getBytesFromStream(zipFile.getInputStream(fst), (int) fst.getSize());
|
Map<String, FSTEntry> gamepartitions = new HashMap<>();
|
||||||
|
|
||||||
FST fstdd = FST.parseFST(fstBytes);
|
// If we have a SI partition, let parse the FST to get all game partitions.
|
||||||
|
ZipEntry siFST = zipFile.getEntry(SI_FST_FILENAME);
|
||||||
|
if (siFST != null) {
|
||||||
|
byte[] fstBytes = StreamUtils.getBytesFromStream(zipFile.getInputStream(siFST), (int) siFST.getSize());
|
||||||
|
|
||||||
for (FSTEntry dirRoot : fstdd.getRoot().getDirChildren()) {
|
FST parsedFST = FST.parseFST(fstBytes);
|
||||||
ZipEntry data = zipFile.getEntry(String.format("sip.s00%s.00000000.app", dirRoot.getFilename()));
|
gamepartitions.putAll(parsedFST.getRoot().getDirChildren().stream().collect(Collectors.toMap(e -> e.getFilename(), e -> e)));
|
||||||
|
}
|
||||||
|
|
||||||
byte[] rawTMD = getFSTEntryAsByte(dirRoot.getFullPath() + "/" + WUD_TMD_FILENAME, dirRoot, zipFile, data)
|
// process all game partitions. Remove the partitions from the "all partitions" list on success.
|
||||||
|
for (val e : gamepartitions.entrySet()) {
|
||||||
|
ZipEntry data = zipFile.getEntry(String.format("sip.s00%s.00000000.app", e.getKey()));
|
||||||
|
|
||||||
|
byte[] rawTMD = getFSTEntryAsByte("/" + e.getKey() + "/" + WUD_TMD_FILENAME, e.getValue(), zipFile, data)
|
||||||
.orElseThrow(() -> new FileNotFoundException());
|
.orElseThrow(() -> new FileNotFoundException());
|
||||||
byte[] rawCert = getFSTEntryAsByte(dirRoot.getFullPath() + "/" + WUD_CERT_FILENAME, dirRoot, zipFile, data)
|
byte[] rawCert = getFSTEntryAsByte("/" + e.getKey() + "/" + WUD_CERT_FILENAME, e.getValue(), zipFile, data)
|
||||||
.orElseThrow(() -> new FileNotFoundException());
|
.orElseThrow(() -> new FileNotFoundException());
|
||||||
byte[] rawTIK = getFSTEntryAsByte(dirRoot.getFullPath() + "/" + WUD_TICKET_FILENAME, dirRoot, zipFile, data)
|
byte[] rawTIK = getFSTEntryAsByte("/" + e.getKey() + "/" + WUD_TICKET_FILENAME, e.getValue(), zipFile, data)
|
||||||
.orElseThrow(() -> new FileNotFoundException());
|
.orElseThrow(() -> new FileNotFoundException());
|
||||||
|
|
||||||
ZipEntry headerEntry = zipFile.getEntry(String.format("p%s.header.bin", dirRoot.getFilename()));
|
ZipEntry headerEntry = zipFile.getEntry(String.format("p%s.header.bin", e.getKey()));
|
||||||
|
|
||||||
byte[] header = StreamUtils.getBytesFromStream(zipFile.getInputStream(headerEntry), (int) headerEntry.getSize());
|
byte[] header = StreamUtils.getBytesFromStream(zipFile.getInputStream(headerEntry), (int) headerEntry.getSize());
|
||||||
|
|
||||||
WumadGamePartition curPartition = new WumadGamePartition(dirRoot.getFilename(), GamePartitionHeader.parseHeader(header), rawTMD, rawCert,
|
WumadGamePartition curPartition = new WumadGamePartition(e.getKey(), GamePartitionHeader.parseHeader(header), rawTMD, rawCert, rawTIK);
|
||||||
rawTIK);
|
|
||||||
|
|
||||||
result.getPartitions().add(curPartition);
|
result.getPartitions().add(curPartition);
|
||||||
|
allPartitions.remove(e.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The remaining partitions are data partitions.
|
||||||
|
for (val e : allPartitions.entrySet()) {
|
||||||
|
ZipEntry fstEntry = e.getValue().stream().filter(f -> f.getName().contains("fst")).findFirst().orElseThrow(() -> new FileNotFoundException());
|
||||||
|
|
||||||
|
byte[] fstBytes = StreamUtils.getBytesFromStream(zipFile.getInputStream(fstEntry), (int) fstEntry.getSize());
|
||||||
|
|
||||||
|
FST parsedFST = FST.parseFST(fstBytes);
|
||||||
|
|
||||||
|
WumadDataPartition curPartition = new WumadDataPartition(e.getKey(), parsedFST);
|
||||||
|
|
||||||
|
result.getPartitions().add(curPartition);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ZipException e) {
|
} catch (ZipException e) {
|
||||||
|
Loading…
Reference in New Issue
Block a user