mirror of
https://github.com/Maschell/JNUSTool.git
synced 2024-11-10 18:35:08 +01:00
Added simple GUI
-added simple GUI -fixed download of some meta files
This commit is contained in:
parent
d83f486fa3
commit
20813d4430
92
src/Directory.java
Normal file
92
src/Directory.java
Normal file
@ -0,0 +1,92 @@
|
||||
import java.util.Collection;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
public class Directory {
|
||||
String name = "";
|
||||
TreeMap<String,Directory> folder = new TreeMap<>();
|
||||
TreeMap<String,FEntry> files = new TreeMap<>();
|
||||
|
||||
public Directory get(String s){
|
||||
return folder.get(s);
|
||||
}
|
||||
|
||||
public Directory(String name){
|
||||
setName(name);
|
||||
}
|
||||
|
||||
public boolean containsFolder(String s){
|
||||
return folder.containsKey(s);
|
||||
}
|
||||
|
||||
public Directory getFolder(String s){
|
||||
return folder.get(s);
|
||||
}
|
||||
|
||||
public Directory addFolder(Directory s){
|
||||
return folder.put(s.getName(),s);
|
||||
}
|
||||
public boolean containsFile(String s){
|
||||
return files.containsKey(s);
|
||||
}
|
||||
|
||||
public FEntry getFile(String s){
|
||||
return files.get(s);
|
||||
}
|
||||
|
||||
public FEntry addFile(FEntry s){
|
||||
return files.put(s.getFileName(),s);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Collection<Directory> getFolder() {
|
||||
return folder.values();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Collection<FEntry> getFiles() {
|
||||
return files.values();
|
||||
}
|
||||
|
||||
public void setFiles(TreeMap<String, FEntry> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
System.out.println(name + ":");
|
||||
for(Directory d : folder.values()){
|
||||
System.out.println(d);
|
||||
}
|
||||
for(String s : files.keySet()){
|
||||
System.out.println(s);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public DefaultMutableTreeNode getNodes(){
|
||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode(getName());
|
||||
|
||||
for(Directory f: getFolder()){
|
||||
node.add(f.getNodes());
|
||||
}
|
||||
|
||||
for(FEntry f: getFiles()){
|
||||
node.add(new DefaultMutableTreeNode(f));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -29,8 +29,7 @@ public class Downloader {
|
||||
if(dlFileLength > (dlFileLength/BLOCKSIZE)*BLOCKSIZE){
|
||||
dlFileLength = ((dlFileLength/BLOCKSIZE)*BLOCKSIZE) +BLOCKSIZE;
|
||||
}
|
||||
|
||||
fileOffset = ((fileOffset / BLOCKSIZE) * BLOCKSIZE);
|
||||
|
||||
connection.setRequestProperty("Range", "bytes=" + fileOffset+"-");
|
||||
connection.connect();
|
||||
|
||||
@ -235,17 +234,21 @@ public class Downloader {
|
||||
String [] path = toDownload.getFullPath().split("/");
|
||||
|
||||
String folder = String.format("%016X", titleID) +"/";
|
||||
File folder_ = null;
|
||||
for(int i = 0;i<path.length-1;i++){
|
||||
if(!path[i].equals("")){
|
||||
if(!path[i].equals("")){
|
||||
folder += path[i] + "/";
|
||||
folder_ = new File(folder);
|
||||
if(!folder_.exists()){
|
||||
folder_.mkdir();
|
||||
}
|
||||
}
|
||||
}
|
||||
File folder_ = new File(folder);
|
||||
if(!folder_.exists()) folder_.mkdir();
|
||||
|
||||
|
||||
try {
|
||||
//if(toDownload.isExtractWithHash()){
|
||||
if(path[1].equals("content")){
|
||||
if(!path[1].equals("code") && toDownload.isExtractWithHash()){
|
||||
downloadAndDecryptHash(URL,toDownload.getFileOffset(),toDownload.getFileLength(),toDownload,ticket);
|
||||
}else{
|
||||
downloadAndDecrypt(URL,toDownload.getFileOffset(),toDownload.getFileLength(),toDownload,ticket);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import java.util.List;
|
||||
|
||||
public class FEntry {
|
||||
|
||||
@ -16,10 +17,11 @@ public class FEntry {
|
||||
private long fileLength = 0;
|
||||
private int contentID = 0;
|
||||
private int NUScontentID = 0;
|
||||
private List<String> pathList;
|
||||
|
||||
|
||||
public FEntry(String path, String filename, int contentID,int NUScontentID, long fileOffset, long fileLength, boolean dir,
|
||||
boolean in_nus_title, boolean extract_withHash) {
|
||||
boolean in_nus_title, boolean extract_withHash, List<String> pathList) {
|
||||
setPath(path);
|
||||
setFileName(filename);
|
||||
setContentID(contentID);
|
||||
@ -29,7 +31,7 @@ public class FEntry {
|
||||
setInNusTitle(in_nus_title);
|
||||
setExtractWithHash(extract_withHash);
|
||||
setNUScontentID(NUScontentID);
|
||||
|
||||
setPathList(pathList);
|
||||
}
|
||||
|
||||
public boolean isDir() {
|
||||
@ -117,6 +119,17 @@ public class FEntry {
|
||||
Downloader.getInstance().download(this);
|
||||
|
||||
}
|
||||
|
||||
public List<String> getPathList() {
|
||||
return pathList;
|
||||
}
|
||||
|
||||
public void setPathList(List<String> pathList) {
|
||||
this.pathList = pathList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
46
src/FST.java
46
src/FST.java
@ -14,11 +14,37 @@ public class FST {
|
||||
int totalEntries = 0;
|
||||
int dirEntries = 0;
|
||||
|
||||
private Directory directory = new Directory("root");
|
||||
|
||||
public FST(byte[] decrypteddata, TitleMetaData tmd) throws IOException {
|
||||
parse(decrypteddata,tmd);
|
||||
buildDirectory();
|
||||
}
|
||||
|
||||
private void buildDirectory() {
|
||||
for(FEntry f : getFileEntries()){
|
||||
Directory current = directory;
|
||||
int i = 0;
|
||||
for(String s :f.getPathList()){
|
||||
|
||||
if(current.containsFolder(s)){
|
||||
current = current.get(s);
|
||||
}else{
|
||||
Directory newDir = new Directory(s);
|
||||
current.addFolder(newDir);
|
||||
current = newDir;
|
||||
}
|
||||
i++;
|
||||
if(i==f.getPathList().size()){
|
||||
current.addFile(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void parse(byte[] decrypteddata, TitleMetaData tmd) throws IOException {
|
||||
|
||||
if(!Arrays.equals(Arrays.copyOfRange(decrypteddata, 0, 3), new byte[]{0x46,0x53,0x54})){
|
||||
@ -99,7 +125,7 @@ public class FST {
|
||||
this.totalContentSize += fileLength;
|
||||
if(in_nus_title)this.totalContentSizeInNUS += fileLength;
|
||||
|
||||
|
||||
List<String> pathList = new ArrayList<>();
|
||||
//getting the full path of entry
|
||||
if(dir)
|
||||
{
|
||||
@ -114,20 +140,28 @@ public class FST {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int k = 0;
|
||||
int nameoffoff,nameoff_entrypath;
|
||||
|
||||
for( j=0; j<level; ++j )
|
||||
{
|
||||
nameoffoff = Util.getIntFromBytes(decrypteddata,base_offset+Entry[j]*0x10);
|
||||
k=0;
|
||||
nameoff_entrypath = nameOff + nameoffoff;
|
||||
while(decrypteddata[nameoff_entrypath + k] != 0){k++;}
|
||||
sb.append(new String(Arrays.copyOfRange(decrypteddata,nameoff_entrypath, nameoff_entrypath + k)));
|
||||
String tmpname = new String(Arrays.copyOfRange(decrypteddata,nameoff_entrypath, nameoff_entrypath + k));
|
||||
if(!tmpname.equals("")){
|
||||
pathList.add(tmpname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sb.append(tmpname);
|
||||
sb.append("/");
|
||||
}
|
||||
path = sb.toString();
|
||||
}
|
||||
|
||||
//add this to the List!
|
||||
fileEntries.add(new FEntry(path,filename,contentID,tmd.contents[contentID].ID,fileOffset,fileLength,dir,in_nus_title,extract_withHash));
|
||||
fileEntries.add(new FEntry(path,filename,contentID,tmd.contents[contentID].ID,fileOffset,fileLength,dir,in_nus_title,extract_withHash,pathList));
|
||||
//System.out.println(fileEntries.get(i));
|
||||
}
|
||||
|
||||
@ -218,4 +252,10 @@ public class FST {
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public Directory getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
274
src/JCheckBoxTree.java
Normal file
274
src/JCheckBoxTree.java
Normal file
@ -0,0 +1,274 @@
|
||||
/**
|
||||
* Based on
|
||||
* http://stackoverflow.com/questions/21847411/java-swing-need-a-good-quality-developed-jtree-with-checkboxes/21851201#21851201
|
||||
*/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.DefaultTreeSelectionModel;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
import javax.swing.tree.TreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
public class JCheckBoxTree extends JTree {
|
||||
|
||||
private static final long serialVersionUID = -4194122328392241790L;
|
||||
|
||||
JCheckBoxTree selfPointer = this;
|
||||
|
||||
|
||||
|
||||
// Defining data structure that will enable to fast check-indicate the state of each node
|
||||
// It totally replaces the "selection" mechanism of the JTree
|
||||
private class CheckedNode {
|
||||
boolean isSelected;
|
||||
boolean hasChildren;
|
||||
boolean allChildrenSelected;
|
||||
|
||||
public CheckedNode(boolean isSelected_, boolean hasChildren_, boolean allChildrenSelected_) {
|
||||
isSelected = isSelected_;
|
||||
hasChildren = hasChildren_;
|
||||
allChildrenSelected = allChildrenSelected_;
|
||||
}
|
||||
}
|
||||
HashMap<TreePath, CheckedNode> nodesCheckingState;
|
||||
HashSet<TreePath> checkedPaths = new HashSet<TreePath>();
|
||||
|
||||
// Defining a new event type for the checking mechanism and preparing event-handling mechanism
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
public class CheckChangeEvent extends EventObject {
|
||||
private static final long serialVersionUID = -8100230309044193368L;
|
||||
|
||||
public CheckChangeEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
|
||||
public interface CheckChangeEventListener extends EventListener {
|
||||
public void checkStateChanged(CheckChangeEvent event);
|
||||
}
|
||||
|
||||
public void addCheckChangeEventListener(CheckChangeEventListener listener) {
|
||||
listenerList.add(CheckChangeEventListener.class, listener);
|
||||
}
|
||||
public void removeCheckChangeEventListener(CheckChangeEventListener listener) {
|
||||
listenerList.remove(CheckChangeEventListener.class, listener);
|
||||
}
|
||||
|
||||
void fireCheckChangeEvent(CheckChangeEvent evt) {
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
if (listeners[i] == CheckChangeEventListener.class) {
|
||||
((CheckChangeEventListener) listeners[i + 1]).checkStateChanged(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override
|
||||
public void setModel(TreeModel newModel) {
|
||||
super.setModel(newModel);
|
||||
resetCheckingState();
|
||||
}
|
||||
|
||||
// New method that returns only the checked paths (totally ignores original "selection" mechanism)
|
||||
public TreePath[] getCheckedPaths() {
|
||||
return checkedPaths.toArray(new TreePath[checkedPaths.size()]);
|
||||
}
|
||||
|
||||
// Returns true in case that the node is selected, has children but not all of them are selected
|
||||
public boolean isSelectedPartially(TreePath path) {
|
||||
CheckedNode cn = nodesCheckingState.get(path);
|
||||
return cn.isSelected && cn.hasChildren && !cn.allChildrenSelected;
|
||||
}
|
||||
|
||||
private void resetCheckingState() {
|
||||
nodesCheckingState = new HashMap<TreePath, CheckedNode>();
|
||||
checkedPaths = new HashSet<TreePath>();
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode)getModel().getRoot();
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
addSubtreeToCheckingStateTracking(node);
|
||||
}
|
||||
|
||||
// Creating data structure of the current model for the checking mechanism
|
||||
private void addSubtreeToCheckingStateTracking(DefaultMutableTreeNode node) {
|
||||
TreeNode[] path = node.getPath();
|
||||
TreePath tp = new TreePath(path);
|
||||
CheckedNode cn = new CheckedNode(false, node.getChildCount() > 0, false);
|
||||
nodesCheckingState.put(tp, cn);
|
||||
for (int i = 0 ; i < node.getChildCount() ; i++) {
|
||||
addSubtreeToCheckingStateTracking((DefaultMutableTreeNode) tp.pathByAddingChild(node.getChildAt(i)).getLastPathComponent());
|
||||
}
|
||||
}
|
||||
|
||||
// Overriding cell renderer by a class that ignores the original "selection" mechanism
|
||||
// It decides how to show the nodes due to the checking-mechanism
|
||||
private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {
|
||||
private static final long serialVersionUID = -7341833835878991719L;
|
||||
JCheckBox checkBox;
|
||||
public CheckBoxCellRenderer() {
|
||||
super();
|
||||
this.setLayout(new BorderLayout());
|
||||
checkBox = new JCheckBox();
|
||||
add(checkBox, BorderLayout.CENTER);
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value,
|
||||
boolean selected, boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
|
||||
Object obj = node.getUserObject();
|
||||
TreePath tp = new TreePath(node.getPath());
|
||||
CheckedNode cn = nodesCheckingState.get(tp);
|
||||
if (cn == null) {
|
||||
return this;
|
||||
}
|
||||
checkBox.setSelected(cn.isSelected);
|
||||
if(obj instanceof FEntry){
|
||||
FEntry f = (FEntry) obj;
|
||||
checkBox.setText(f.getFileName());
|
||||
}else{
|
||||
checkBox.setText(obj.toString());
|
||||
}
|
||||
|
||||
checkBox.setOpaque(cn.isSelected && cn.hasChildren && ! cn.allChildrenSelected);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public JCheckBoxTree(NUSTitle nus) {
|
||||
super();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
parent.add(new DefaultMutableTreeNode("hot dogs"));
|
||||
parent.add(new DefaultMutableTreeNode("pizza"));
|
||||
parent.add(new DefaultMutableTreeNode("ravioli"));
|
||||
parent.add(new DefaultMutableTreeNode("bananas"));*/
|
||||
//return ;
|
||||
|
||||
setModel(new DefaultTreeModel(nus.getFst().getDirectory().getNodes()));
|
||||
|
||||
// Disabling toggling by double-click
|
||||
this.setToggleClickCount(0);
|
||||
// Overriding cell renderer by new one defined above
|
||||
CheckBoxCellRenderer cellRenderer = new CheckBoxCellRenderer();
|
||||
this.setCellRenderer(cellRenderer);
|
||||
|
||||
// Overriding selection model by an empty one
|
||||
DefaultTreeSelectionModel dtsm = new DefaultTreeSelectionModel() {
|
||||
private static final long serialVersionUID = -8190634240451667286L;
|
||||
// Totally disabling the selection mechanism
|
||||
public void setSelectionPath(TreePath path) {
|
||||
}
|
||||
public void addSelectionPath(TreePath path) {
|
||||
}
|
||||
public void removeSelectionPath(TreePath path) {
|
||||
}
|
||||
public void setSelectionPaths(TreePath[] pPaths) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Calling checking mechanism on mouse click
|
||||
this.addMouseListener(new MouseListener() {
|
||||
public void mouseClicked(MouseEvent arg0) {
|
||||
TreePath tp = selfPointer.getPathForLocation(arg0.getX(), arg0.getY());
|
||||
if (tp == null) {
|
||||
return;
|
||||
}
|
||||
boolean checkMode = ! nodesCheckingState.get(tp).isSelected;
|
||||
checkSubTree(tp, checkMode);
|
||||
updatePredecessorsWithCheckMode(tp, checkMode);
|
||||
// Firing the check change event
|
||||
fireCheckChangeEvent(new CheckChangeEvent(new Object()));
|
||||
// Repainting tree after the data structures were updated
|
||||
selfPointer.repaint();
|
||||
}
|
||||
public void mouseEntered(MouseEvent arg0) {
|
||||
}
|
||||
public void mouseExited(MouseEvent arg0) {
|
||||
}
|
||||
public void mousePressed(MouseEvent arg0) {
|
||||
}
|
||||
public void mouseReleased(MouseEvent arg0) {
|
||||
}
|
||||
});
|
||||
|
||||
this.setSelectionModel(dtsm);
|
||||
}
|
||||
|
||||
// When a node is checked/unchecked, updating the states of the predecessors
|
||||
protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
|
||||
TreePath parentPath = tp.getParentPath();
|
||||
// If it is the root, stop the recursive calls and return
|
||||
if (parentPath == null) {
|
||||
return;
|
||||
}
|
||||
CheckedNode parentCheckedNode = nodesCheckingState.get(parentPath);
|
||||
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parentPath.getLastPathComponent();
|
||||
parentCheckedNode.allChildrenSelected = true;
|
||||
parentCheckedNode.isSelected = false;
|
||||
for (int i = 0 ; i < parentNode.getChildCount() ; i++) {
|
||||
TreePath childPath = parentPath.pathByAddingChild(parentNode.getChildAt(i));
|
||||
CheckedNode childCheckedNode = nodesCheckingState.get(childPath);
|
||||
// It is enough that even one subtree is not fully selected
|
||||
// to determine that the parent is not fully selected
|
||||
if (! childCheckedNode.allChildrenSelected) {
|
||||
parentCheckedNode.allChildrenSelected = false;
|
||||
}
|
||||
// If at least one child is selected, selecting also the parent
|
||||
if (childCheckedNode.isSelected) {
|
||||
parentCheckedNode.isSelected = true;
|
||||
}
|
||||
}
|
||||
if (parentCheckedNode.isSelected) {
|
||||
checkedPaths.add(parentPath);
|
||||
} else {
|
||||
checkedPaths.remove(parentPath);
|
||||
}
|
||||
// Go to upper predecessor
|
||||
updatePredecessorsWithCheckMode(parentPath, check);
|
||||
}
|
||||
|
||||
// Recursively checks/unchecks a subtree
|
||||
protected void checkSubTree(TreePath tp, boolean check) {
|
||||
CheckedNode cn = nodesCheckingState.get(tp);
|
||||
cn.isSelected = check;
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();
|
||||
for (int i = 0 ; i < node.getChildCount() ; i++) {
|
||||
checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
|
||||
}
|
||||
cn.allChildrenSelected = check;
|
||||
if (check) {
|
||||
checkedPaths.add(tp);
|
||||
} else {
|
||||
checkedPaths.remove(tp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
70
src/NUSGUI.java
Normal file
70
src/NUSGUI.java
Normal file
@ -0,0 +1,70 @@
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
public class NUSGUI extends JFrame {
|
||||
|
||||
private static final long serialVersionUID = 4648172894076113183L;
|
||||
|
||||
public NUSGUI(NUSTitle nus) {
|
||||
super();
|
||||
setSize(800, 600);
|
||||
getContentPane().setLayout(new BorderLayout(0, 0));
|
||||
|
||||
final JCheckBoxTree cbt = new JCheckBoxTree(nus);
|
||||
JScrollPane qPane = new JScrollPane(cbt,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
this.getContentPane().add(qPane);
|
||||
|
||||
|
||||
JButton btnNewButton = new JButton("Download");
|
||||
btnNewButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
new Thread(new Runnable() { public void run() {
|
||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||
List<TitleDownloader> 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));
|
||||
}
|
||||
}
|
||||
pool.invokeAll(list);
|
||||
System.out.println("Done!");
|
||||
}}).start();
|
||||
|
||||
}
|
||||
});
|
||||
getContentPane().add(btnNewButton, BorderLayout.SOUTH);
|
||||
|
||||
/*cbt.addCheckChangeEventListener(new JCheckBoxTree.CheckChangeEventListener() {
|
||||
public void checkStateChanged(JCheckBoxTree.CheckChangeEvent event) {
|
||||
System.out.println("event");
|
||||
TreePath[] paths = cbt.getCheckedPaths();
|
||||
for (TreePath tp : paths) {
|
||||
for (Object pathPart : tp.getPath()) {
|
||||
System.out.print(pathPart + ",");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
});*/
|
||||
|
||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
}
|
||||
}
|
@ -1,14 +1,10 @@
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
public class NUSTitle {
|
||||
private TitleMetaData tmd;
|
||||
private long titleID;
|
||||
private TIK ticket;
|
||||
|
||||
private FST fst;
|
||||
public NUSTitle(long titleId,String key){
|
||||
|
||||
try {
|
||||
@ -17,7 +13,7 @@ public class NUSTitle {
|
||||
Decryption decryption = new Decryption(Util.commonKey,titleId);
|
||||
|
||||
tmd = new TitleMetaData(Downloader.getInstance().downloadTMDToByteArray());
|
||||
|
||||
|
||||
if(key == null){
|
||||
ticket = new TIK(Downloader.getInstance().downloadTicketToByteArray(),tmd.titleID);
|
||||
}else{
|
||||
@ -31,33 +27,13 @@ public class NUSTitle {
|
||||
byte[] encryptedFST = Downloader.getInstance().downloadContentToByteArray(tmd.contents[0].ID);
|
||||
byte[] decryptedFST = decryption.decrypt(encryptedFST);
|
||||
|
||||
FST fst = new FST(decryptedFST,tmd);
|
||||
|
||||
long start = new Date().getTime();
|
||||
fst = new FST(decryptedFST,tmd);
|
||||
|
||||
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");
|
||||
System.out.println("Entries: " + fst.getTotalEntries());
|
||||
System.out.println("Entries: " + fst.getFileCount());
|
||||
System.out.println("Files in NUSTitle: " + fst.getFileCountInNUS());
|
||||
System.out.println("");
|
||||
System.out.println("Downloading all files.");
|
||||
System.out.println("");
|
||||
|
||||
ForkJoinPool pool = ForkJoinPool.commonPool();
|
||||
List<TitleDownloader> list = new ArrayList<>();
|
||||
for(FEntry f: fst.getFileEntries()){
|
||||
if(!f.isDir() && f.isInNUSTitle())
|
||||
list.add(new TitleDownloader(f));
|
||||
}
|
||||
pool.invokeAll(list);
|
||||
|
||||
long runningTime = new Date().getTime() - start;
|
||||
System.out.println("");
|
||||
System.out.println("Done in: " + runningTime/1000.0 + " seconds");
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
@ -65,6 +41,17 @@ public class NUSTitle {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public FST getFst() {
|
||||
return fst;
|
||||
}
|
||||
|
||||
|
||||
public void setFst(FST fst) {
|
||||
this.fst = fst;
|
||||
}
|
||||
|
||||
|
||||
public long getTitleID() {
|
||||
return titleID;
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import java.io.IOException;
|
||||
public class Starter {
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("JNUSTool 0.0.1 - pre alpha - by Maschell");
|
||||
System.out.println();
|
||||
try {
|
||||
readConfig();
|
||||
} catch (IOException e) {
|
||||
@ -20,14 +22,15 @@ public class Starter {
|
||||
if( args.length > 1 && args[1].length() == 32){
|
||||
key = args[1].substring(0, 32);
|
||||
}
|
||||
new NUSTitle(titleID, key);
|
||||
NUSGUI m = new NUSGUI(new NUSTitle(titleID, key));
|
||||
m.setVisible(true);
|
||||
}else{
|
||||
System.out.println("Need parameters: TITLEID [KEY]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void readConfig() throws IOException {
|
||||
public static void readConfig() throws IOException {
|
||||
BufferedReader in = new BufferedReader(new FileReader(new File("config")));
|
||||
Downloader.URL_BASE = in.readLine();
|
||||
Util.commonKey = Util.hexStringToByteArray(in.readLine());
|
||||
|
Loading…
Reference in New Issue
Block a user