mirror of
https://github.com/Maschell/JNUSTool.git
synced 2024-12-29 01:21:53 +01:00
Added a lot of things!
Added a settings class! (no runtime configuration atm) added decryption from files added download to files
This commit is contained in:
parent
eb5657ebf6
commit
0e03adf10f
@ -4,7 +4,10 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import de.mas.jnustool.util.Decryption;
|
||||
import de.mas.jnustool.util.Downloader;
|
||||
import de.mas.jnustool.util.ExitException;
|
||||
import de.mas.jnustool.util.Settings;
|
||||
|
||||
public class FEntry {
|
||||
private FST fst;
|
||||
@ -124,7 +127,7 @@ public class FEntry {
|
||||
}
|
||||
|
||||
private void createFolder() {
|
||||
long titleID = fst.getTmd().titleID;
|
||||
long titleID = getTitleID();
|
||||
String [] path = getFullPath().split("/");
|
||||
File f = new File (String.format("%016X", titleID));
|
||||
if(!f.exists())f.mkdir();
|
||||
@ -140,20 +143,71 @@ public class FEntry {
|
||||
}
|
||||
}
|
||||
}
|
||||
f = new File(String.format("%016X", titleID) +"/" +getFullPath().substring(1, getFullPath().length()));
|
||||
|
||||
}
|
||||
public String getDownloadPath(){
|
||||
String [] path = getFullPath().split("/");
|
||||
String folder = String.format("%016X", getTitleID()) +"/";
|
||||
for(int i = 0;i<path.length-1;i++){
|
||||
if(!path[i].equals("")){
|
||||
folder += path[i] + "/";
|
||||
}
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
public void downloadAndDecrypt() throws ExitException {
|
||||
|
||||
createFolder();
|
||||
long titleID = getTitleID();
|
||||
File f = new File(String.format("%016X", titleID) +"/" +getFullPath().substring(1, getFullPath().length()));
|
||||
if(f.exists()){
|
||||
if(f.length() == getFileLength()){
|
||||
System.out.println("Skipping: " + String.format("%8.2f MB ",getFileLength()/1024.0/1024.0) + getFullPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void downloadAndDecrypt() {
|
||||
System.out.println("Downloading: " + String.format("%8.2f MB ", getFileLength()/1024.0/1024.0) + getFullPath());
|
||||
try {
|
||||
if(Settings.useCachedFiles){
|
||||
f = new File(getContentPath());
|
||||
if(f.exists()){
|
||||
if(f.length() == fst.getTmd().contents[this.getContentID()].size){
|
||||
System.out.println("Decrypting: " + String.format("%8.2f MB ", getFileLength()/1024.0/1024.0) + getFullPath());
|
||||
Decryption decrypt = new Decryption(fst.getTmd().getNUSTitle().getTicket());
|
||||
decrypt.decrypt(this,getDownloadPath());
|
||||
return;
|
||||
}else{
|
||||
if(!Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
System.out.println("Cached content has the wrong size! Please check your: "+ getContentPath() + " Downloading not allowed");
|
||||
if(!Settings.skipBrokenFiles){
|
||||
throw new ExitException("");
|
||||
}else{
|
||||
System.out.println("Ignoring the missing file: " + this.getFileName());
|
||||
}
|
||||
}else{
|
||||
System.out.println("Content missing. Downloading the file from the server: " + this.getFileName());
|
||||
}
|
||||
|
||||
}
|
||||
}else{
|
||||
if(!Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
System.out.println("Content missing. Downloading not allowed");
|
||||
if(!Settings.skipBrokenFiles){
|
||||
throw new ExitException("");
|
||||
}else{
|
||||
System.out.println("Ignoring the missing file: " + this.getFileName());
|
||||
}
|
||||
}else{
|
||||
System.out.println("Content missing. Downloading the file from the server: " + this.getFileName());
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Downloading: " + String.format("%8.2f MB ", getFileLength()/1024.0/1024.0) + getFullPath());
|
||||
Downloader.getInstance().downloadAndDecrypt(this);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -168,6 +222,18 @@ public class FEntry {
|
||||
this.pathList = pathList;
|
||||
}
|
||||
|
||||
public String getContentPath() {
|
||||
return fst.getTmd().getContentPath() + "/" + String.format("%08X", getNUScontentID()) + ".app";
|
||||
}
|
||||
|
||||
public long getTitleID() {
|
||||
return fst.getTmd().titleID;
|
||||
}
|
||||
|
||||
public TIK getTicket() {
|
||||
return fst.getTmd().getNUSTitle().getTicket();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2,14 +2,13 @@ package de.mas.jnustool;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class TitleDownloader implements Callable<Integer>
|
||||
public class FEntryDownloader implements Callable<Integer>
|
||||
{
|
||||
|
||||
FEntry f;
|
||||
public void setTitle(FEntry f){
|
||||
this.f = f;
|
||||
}
|
||||
public TitleDownloader(FEntry f){
|
||||
public FEntryDownloader(FEntry f){
|
||||
setTitle(f);
|
||||
}
|
||||
|
@ -1,40 +1,144 @@
|
||||
package de.mas.jnustool;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import de.mas.jnustool.util.Decryption;
|
||||
import de.mas.jnustool.util.Downloader;
|
||||
import de.mas.jnustool.util.Util;
|
||||
import de.mas.jnustool.util.ExitException;
|
||||
import de.mas.jnustool.util.Settings;
|
||||
|
||||
public class NUSTitle {
|
||||
private TitleMetaData tmd;
|
||||
private long titleID;
|
||||
private TIK ticket;
|
||||
private FST fst;
|
||||
public NUSTitle(long titleId,String key){
|
||||
|
||||
private long titleID;
|
||||
public NUSTitle(long titleId,String key) throws ExitException{
|
||||
setTitleID(titleId);
|
||||
try {
|
||||
titleID = titleId;
|
||||
Downloader.getInstance().titleID = titleId;
|
||||
Decryption decryption = new Decryption(Util.commonKey,titleId);
|
||||
|
||||
tmd = new TitleMetaData(Downloader.getInstance().downloadTMDToByteArray());
|
||||
if(Settings.downloadContent){
|
||||
File f = new File(getContentPath());
|
||||
if(!f.exists())f.mkdir();
|
||||
}
|
||||
if(Settings.downloadContent){
|
||||
|
||||
if(key == null){
|
||||
ticket = new TIK(Downloader.getInstance().downloadTicketToByteArray(),tmd.titleID);
|
||||
}else{
|
||||
ticket = new TIK(key,titleId);
|
||||
File f = new File(getContentPath() + "/" + "tmd");
|
||||
if(!(f.exists() && Settings.skipExistingTMDTICKET)){
|
||||
System.out.println("Downloading TMD");
|
||||
Downloader.getInstance().downloadTMD(titleId,getContentPath());
|
||||
}else{
|
||||
System.out.println("Skipped download of TMD. Already existing");
|
||||
}
|
||||
f = new File(getContentPath() + "/" + "cetk");
|
||||
if(!(f.exists() && Settings.skipExistingTMDTICKET)){
|
||||
if(key == null){
|
||||
System.out.print("Downloading Ticket");
|
||||
Downloader.getInstance().downloadTicket(titleId,getContentPath());
|
||||
}
|
||||
}else{
|
||||
System.out.println("Skipped download of ticket. Already existing");
|
||||
}
|
||||
}
|
||||
|
||||
if(Settings.useCachedFiles){
|
||||
File f = new File(getContentPath() + "/" + "tmd");
|
||||
if(f.exists()){
|
||||
System.out.println("Using cached TMD.");
|
||||
tmd = new TitleMetaData(f);
|
||||
}else{
|
||||
System.out.println("No cached TMD found.");
|
||||
}
|
||||
}
|
||||
|
||||
Downloader.getInstance().ticket = ticket;
|
||||
decryption.init(ticket.getDecryptedKey(),0);
|
||||
|
||||
byte[] encryptedFST = Downloader.getInstance().downloadContentToByteArray(tmd.contents[0].ID);
|
||||
if(tmd == null){
|
||||
if(Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
if(Settings.useCachedFiles) System.out.println("Getting missing tmd from Server!");
|
||||
tmd = new TitleMetaData(Downloader.getInstance().downloadTMDToByteArray(titleId));
|
||||
}else{
|
||||
System.out.println("Downloading of missing files is not enabled. Exiting");
|
||||
throw new ExitException("TMD missing.");
|
||||
}
|
||||
}
|
||||
|
||||
if(key != null){
|
||||
System.out.println("Using ticket from parameter.");
|
||||
ticket = new TIK(key,titleId);
|
||||
}else{
|
||||
if(Settings.useCachedFiles){
|
||||
File f = new File(getContentPath() + "/" + "cetk");
|
||||
if(f.exists()){
|
||||
System.out.println("Using cached cetk.");
|
||||
ticket = new TIK(f,titleId);
|
||||
}else{
|
||||
System.out.println("No cached ticket found.");
|
||||
}
|
||||
}
|
||||
if(ticket == null){
|
||||
if(Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
if(Settings.useCachedFiles) System.out.println("getting missing ticket");
|
||||
ticket = new TIK(Downloader.getInstance().downloadTicketToByteArray(titleId),tmd.titleID);
|
||||
}else{
|
||||
System.out.println("Downloading of missing files is not enabled. Exiting");
|
||||
throw new ExitException("Ticket missing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Settings.downloadContent){
|
||||
File f = new File(getContentPath() + "/" + String.format("%08x", tmd.contents[0].ID) + ".app");
|
||||
if(!(f.exists() && Settings.skipExistingFiles)){
|
||||
System.out.println("Downloading FST (" + String.format("%08x", tmd.contents[0].ID) + ")");
|
||||
Downloader.getInstance().downloadContent(titleId,tmd.contents[0].ID,getContentPath());
|
||||
}else{
|
||||
if(f.length() != tmd.contents[0].size){
|
||||
if(Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
System.out.println("FST already existing, but broken. Downloading it again.");
|
||||
Downloader.getInstance().downloadContent(titleId,tmd.contents[0].ID,getContentPath());
|
||||
}else{
|
||||
System.out.println("FST already existing, but broken. No download allowed.");
|
||||
throw new ExitException("FST missing.");
|
||||
}
|
||||
}else{
|
||||
System.out.println("Skipped download of FST. Already existing");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Decryption decryption = new Decryption(ticket.getDecryptedKey(),0);
|
||||
byte[] encryptedFST = null;
|
||||
if(Settings.useCachedFiles){
|
||||
String path = getContentPath() + "/" + String.format("%08x", tmd.contents[0].ID) + ".app";
|
||||
File f = new File(path);
|
||||
if(f.exists()){
|
||||
System.out.println("Using cached FST");
|
||||
Path file = Paths.get(path);
|
||||
encryptedFST = Files.readAllBytes(file);
|
||||
}else{
|
||||
System.out.println("No cached FST (" + String.format("%08x", tmd.contents[0].ID) + ") found.");
|
||||
}
|
||||
}
|
||||
if(encryptedFST == null){
|
||||
if(Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
if(Settings.useCachedFiles)System.out.println("Getting FST from server.");
|
||||
encryptedFST = Downloader.getInstance().downloadContentToByteArray(titleId,tmd.contents[0].ID);
|
||||
}else{
|
||||
System.out.println("Downloading of missing files is not enabled. Exiting");
|
||||
throw new ExitException("");
|
||||
}
|
||||
}
|
||||
byte[] decryptedFST = decryption.decrypt(encryptedFST);
|
||||
|
||||
fst = new FST(decryptedFST,tmd);
|
||||
tmd.setFst(fst);
|
||||
tmd.setNUSTitle(this);
|
||||
|
||||
if(Settings.downloadContent){
|
||||
tmd.downloadContents();
|
||||
}
|
||||
|
||||
System.out.println("Total Size of Content Files: " + ((int)((getTotalContentSize()/1024.0/1024.0)*100))/100.0 +" MB");
|
||||
System.out.println("Total Size of Decrypted Files: " + ((int)((fst.getTotalContentSizeInNUS()/1024.0/1024.0)*100))/100.0 +" MB");
|
||||
@ -49,26 +153,61 @@ public class NUSTitle {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public FST getFst() {
|
||||
return fst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setFst(FST fst) {
|
||||
this.fst = fst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public long getTitleID() {
|
||||
return titleID;
|
||||
public TitleMetaData getTmd() {
|
||||
return tmd;
|
||||
}
|
||||
|
||||
public void setTitleID(long titleID) {
|
||||
this.titleID = titleID;
|
||||
public void setTmd(TitleMetaData tmd) {
|
||||
this.tmd = tmd;
|
||||
}
|
||||
|
||||
public TIK getTicket() {
|
||||
return ticket;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setTicket(TIK ticket) {
|
||||
this.ticket = ticket;
|
||||
}
|
||||
|
||||
public long getTotalContentSize() {
|
||||
return tmd.getTotalContentSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getContentPath() {
|
||||
return getContentPathPrefix() + String.format("%016X", getTitleID());
|
||||
}
|
||||
|
||||
public String getContentPathPrefix() {
|
||||
return "tmp_";
|
||||
}
|
||||
|
||||
|
||||
|
||||
private long getTitleID() {
|
||||
return titleID;
|
||||
}
|
||||
|
||||
private void setTitleID(long titleId) {
|
||||
this.titleID = titleId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
package de.mas.jnustool;
|
||||
|
||||
|
||||
public class Settings {
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import java.io.IOException;
|
||||
|
||||
import de.mas.jnustool.gui.NUSGUI;
|
||||
import de.mas.jnustool.util.Downloader;
|
||||
import de.mas.jnustool.util.ExitException;
|
||||
import de.mas.jnustool.util.Util;
|
||||
|
||||
public class Starter {
|
||||
@ -28,7 +29,13 @@ public class Starter {
|
||||
if( args.length > 1 && args[1].length() == 32){
|
||||
key = args[1].substring(0, 32);
|
||||
}
|
||||
NUSGUI m = new NUSGUI(new NUSTitle(titleID, key), null);
|
||||
NUSGUI m;
|
||||
try {
|
||||
m = new NUSGUI(new NUSTitle(titleID, key), null);
|
||||
} catch (ExitException e) {
|
||||
System.out.println("Error: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
m.setVisible(true);
|
||||
}else{
|
||||
System.out.println("Need parameters: TITLEID [KEY]");
|
||||
|
@ -3,8 +3,18 @@ package de.mas.jnustool;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.mas.jnustool.util.Downloader;
|
||||
import de.mas.jnustool.util.ExitException;
|
||||
import de.mas.jnustool.util.Settings;
|
||||
import de.mas.jnustool.util.Util;
|
||||
|
||||
public class TitleMetaData {
|
||||
@ -27,7 +37,8 @@ public class TitleMetaData {
|
||||
ContentInfo[] contentInfos = new ContentInfo[64]; // 0x1E4
|
||||
Content[] contents; // 0x1E4
|
||||
|
||||
private FST fst;
|
||||
|
||||
private NUSTitle nus;
|
||||
|
||||
private long totalContentSize;
|
||||
|
||||
@ -105,8 +116,7 @@ public class TitleMetaData {
|
||||
type = f.readShort();
|
||||
size = f.readLong();
|
||||
byte[] buffer = new byte[0x20]; // 16 0xB14
|
||||
f.read(buffer,0, 0x20);
|
||||
|
||||
f.read(buffer,0, 0x20);
|
||||
|
||||
this.contents[i] = new Content(ID,index,type,size,buffer);
|
||||
}
|
||||
@ -152,13 +162,50 @@ public class TitleMetaData {
|
||||
public long getTotalContentSize() {
|
||||
return totalContentSize;
|
||||
}
|
||||
|
||||
public FST getFst() {
|
||||
return fst;
|
||||
|
||||
public void downloadContents() throws IOException, ExitException{
|
||||
String tmpPath = getContentPath();
|
||||
File f = new File(tmpPath);
|
||||
if(!f.exists())f.mkdir();
|
||||
|
||||
for(Content c : contents){
|
||||
if(c != contents[0]){
|
||||
f = new File(tmpPath + "/" + String.format("%08X", c.ID ) + ".app");
|
||||
if(f.exists()){
|
||||
if(f.length() == c.size){
|
||||
System.out.println("Skipping Content: " + String.format("%08X", c.ID));
|
||||
}else{
|
||||
if(Settings.downloadWhenCachedFilesMissingOrBroken){
|
||||
System.out.println("Content " +String.format("%08X", c.ID) + " is broken. Downloading it again.");
|
||||
Downloader.getInstance().downloadContent(titleID,c.ID,tmpPath);
|
||||
}else{
|
||||
if(Settings.skipBrokenFiles){
|
||||
System.out.println("Content " +String.format("%08X", c.ID) + " is broken. Ignoring it.");
|
||||
}else{
|
||||
System.out.println("Content " +String.format("%08X", c.ID) + " is broken. Downloading not allowed.");
|
||||
throw new ExitException("Content missing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
System.out.println("Download Content: " + String.format("%08X", c.ID));
|
||||
Downloader.getInstance().downloadContent(titleID,c.ID,tmpPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setFst(FST fst) {
|
||||
this.fst = fst;
|
||||
}
|
||||
public String getContentPath() {
|
||||
return nus.getContentPath();
|
||||
}
|
||||
|
||||
public NUSTitle getNUSTitle() {
|
||||
return nus;
|
||||
}
|
||||
|
||||
public void setNUSTitle(NUSTitle nus) {
|
||||
this.nus = nus;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,10 +13,10 @@ import javax.swing.JScrollPane;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import de.mas.jnustool.Settings;
|
||||
import de.mas.jnustool.FEntry;
|
||||
import de.mas.jnustool.NUSTitle;
|
||||
import de.mas.jnustool.TitleDownloader;
|
||||
import de.mas.jnustool.util.Settings;
|
||||
import de.mas.jnustool.FEntryDownloader;
|
||||
|
||||
public class NUSGUI extends JFrame {
|
||||
|
||||
@ -39,16 +39,19 @@ public class NUSGUI extends JFrame {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new Thread(new Runnable() { public void run() {
|
||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||
List<TitleDownloader> list = new ArrayList<>();
|
||||
List<FEntryDownloader> list = new ArrayList<>();
|
||||
|
||||
|
||||
TreePath[] paths = cbt.getCheckedPaths();
|
||||
for (TreePath tp : paths) {
|
||||
|
||||
Object obj = tp.getPath()[tp.getPath().length-1];
|
||||
if(((DefaultMutableTreeNode)obj).getUserObject() instanceof FEntry){
|
||||
FEntry f = (FEntry) ((DefaultMutableTreeNode)obj).getUserObject();
|
||||
if(!f.isDir() && f.isInNUSTitle())
|
||||
list.add(new TitleDownloader(f));
|
||||
if(!f.isDir() && f.isInNUSTitle()){
|
||||
list.add(new FEntryDownloader(f));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
pool.invokeAll(list);
|
||||
|
@ -2,6 +2,7 @@ package de.mas.jnustool.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -333,6 +334,34 @@ public class Decryption {
|
||||
inputSteam.close();
|
||||
|
||||
}
|
||||
|
||||
public void decrypt(FEntry fileEntry,String outputPath) throws IOException {
|
||||
String [] path = fileEntry.getFullPath().split("/");
|
||||
boolean decryptWithHash = false;
|
||||
if(!path[1].equals("code") && fileEntry.isExtractWithHash()){
|
||||
decryptWithHash = true;
|
||||
}
|
||||
|
||||
long fileOffset = fileEntry.getFileOffset();
|
||||
if(decryptWithHash){
|
||||
int BLOCKSIZE = 0x10000;
|
||||
int HASHBLOCKSIZE = 0xFC00;
|
||||
fileOffset = ((fileEntry.getFileOffset() / HASHBLOCKSIZE) * BLOCKSIZE);
|
||||
}
|
||||
|
||||
|
||||
InputStream input = new FileInputStream(fileEntry.getContentPath());
|
||||
FileOutputStream outputStream = new FileOutputStream(outputPath + "/" + fileEntry.getFileName());
|
||||
|
||||
input.skip(fileOffset);
|
||||
|
||||
if(!decryptWithHash){
|
||||
decryptFile(input, outputStream, fileEntry);
|
||||
}else{
|
||||
decryptFileHash(input, outputStream, fileEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package de.mas.jnustool.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -8,7 +7,6 @@ import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import de.mas.jnustool.FEntry;
|
||||
import de.mas.jnustool.TIK;
|
||||
|
||||
public class Downloader {
|
||||
private static Downloader instance;
|
||||
@ -23,11 +21,9 @@ public class Downloader {
|
||||
|
||||
}
|
||||
|
||||
public long titleID =0;
|
||||
public TIK ticket = null;
|
||||
|
||||
public void downloadAndDecrypt(FEntry toDownload) throws IOException{
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/" + String.format("%08X", toDownload.getNUScontentID());
|
||||
String URL = URL_BASE + "/" + String.format("%016X", toDownload.getTitleID()) + "/" + String.format("%08X", toDownload.getNUScontentID());
|
||||
URL url = new URL(URL);
|
||||
String [] path = toDownload.getFullPath().split("/");
|
||||
boolean decryptWithHash = false;
|
||||
@ -48,10 +44,10 @@ public class Downloader {
|
||||
|
||||
connection.connect();
|
||||
|
||||
Decryption decryption = new Decryption(ticket);
|
||||
Decryption decryption = new Decryption(toDownload.getTicket());
|
||||
|
||||
InputStream input = connection.getInputStream();
|
||||
FileOutputStream outputStream = new FileOutputStream(String.format("%016X", titleID) +"/" + toDownload.getFullPath().substring(1, toDownload.getFullPath().length()));
|
||||
FileOutputStream outputStream = new FileOutputStream(String.format("%016X", toDownload.getTitleID()) +"/" + toDownload.getFullPath().substring(1, toDownload.getFullPath().length()));
|
||||
if(!decryptWithHash){
|
||||
decryption.decryptFile(input, outputStream, toDownload);
|
||||
}else{
|
||||
@ -63,20 +59,23 @@ public class Downloader {
|
||||
|
||||
public static String URL_BASE = "";
|
||||
|
||||
public void downloadTMD(int version) throws IOException {
|
||||
downloadTMD();
|
||||
public void downloadTMD(long titleID,int version,String path) throws IOException {
|
||||
downloadTMD(titleID,path);
|
||||
}
|
||||
public void downloadTMD() throws IOException {
|
||||
public void downloadTMD(long titleID,String path) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/tmd";
|
||||
downloadFile(URL, "tmd");
|
||||
downloadFile(URL, "tmd",path);
|
||||
}
|
||||
public void downloadFile(String fileURL,String filename) throws IOException{
|
||||
public void downloadFile(String fileURL,String filename,String tmpPath) throws IOException{
|
||||
int BUFFER_SIZE = 0x800;
|
||||
URL url = new URL(fileURL);
|
||||
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
InputStream inputStream = httpConn.getInputStream();
|
||||
|
||||
if(tmpPath != null){
|
||||
filename = tmpPath + "/" + filename;
|
||||
}
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(filename);
|
||||
|
||||
int bytesRead = -1;
|
||||
@ -90,20 +89,22 @@ public class Downloader {
|
||||
|
||||
httpConn.disconnect();
|
||||
}
|
||||
public void downloadTicket() throws IOException {
|
||||
|
||||
public void downloadFile(String fileURL,String filename) throws IOException{
|
||||
downloadFile(fileURL, filename,null);
|
||||
}
|
||||
public void downloadTicket(long titleID,String path) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/cetk";
|
||||
downloadFile(URL, "cetk");
|
||||
downloadFile(URL, "cetk",path);
|
||||
}
|
||||
public void downloadContent(int contentID) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/" + String.format("%08X", contentID);
|
||||
downloadFile(URL, String.format("%08X", contentID));
|
||||
|
||||
public void downloadContent(long titleID,int contentID) throws IOException {
|
||||
downloadContent(titleID,contentID, null);
|
||||
}
|
||||
public byte[] downloadContentToByteArray(int contentID) throws IOException {
|
||||
public byte[] downloadContentToByteArray(long titleID,int contentID) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/" + String.format("%08X", contentID);
|
||||
return downloadFileToByteArray(URL);
|
||||
}
|
||||
public byte[] downloadTMDToByteArray() throws IOException {
|
||||
public byte[] downloadTMDToByteArray(long titleID) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/tmd";
|
||||
return downloadFileToByteArray(URL);
|
||||
}
|
||||
@ -141,9 +142,15 @@ public class Downloader {
|
||||
return file;
|
||||
|
||||
}
|
||||
public byte[] downloadTicketToByteArray() throws IOException {
|
||||
public byte[] downloadTicketToByteArray(long titleID) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/cetk";
|
||||
return downloadFileToByteArray(URL);
|
||||
}
|
||||
public void downloadContent(long titleID,int contentID, String tmpPath) throws IOException {
|
||||
String URL = URL_BASE + "/" + String.format("%016X", titleID) + "/" + String.format("%08X", contentID);
|
||||
downloadFile(URL, String.format("%08X", contentID) +".app",tmpPath);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
14
src/de/mas/jnustool/util/ExitException.java
Normal file
14
src/de/mas/jnustool/util/ExitException.java
Normal file
@ -0,0 +1,14 @@
|
||||
package de.mas.jnustool.util;
|
||||
|
||||
public class ExitException extends Exception {
|
||||
|
||||
public ExitException(String string) {
|
||||
super(string);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
12
src/de/mas/jnustool/util/Settings.java
Normal file
12
src/de/mas/jnustool/util/Settings.java
Normal file
@ -0,0 +1,12 @@
|
||||
package de.mas.jnustool.util;
|
||||
|
||||
|
||||
public class Settings {
|
||||
public static boolean downloadContent = false;
|
||||
public static boolean useCachedFiles = false;
|
||||
public static boolean downloadWhenCachedFilesMissingOrBroken = true;
|
||||
public static boolean skipBrokenFiles = false;
|
||||
public static boolean skipExistingFiles = true;
|
||||
public static boolean skipExistingTMDTICKET = true;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user