JNUSTool/src/main/java/de/mas/wiiu/jnus/jnustool/util/UpdateListManager.java

286 lines
13 KiB
Java

package de.mas.wiiu.jnus.jnustool.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import de.mas.wiiu.jnus.jnustool.FEntry;
import de.mas.wiiu.jnus.jnustool.Logger;
import de.mas.wiiu.jnus.jnustool.NUSTitle;
public class UpdateListManager {
public static List<NUSTitleInformation> getTitles() {
boolean preSettings = Settings.logToPrintLn;
Logger.log("Loading "+ Settings.updateCSVPath);
List<NUSTitleInformation> updatelist = readUpdateCSV();
if(Settings.updateCSVFromServer){
Logger.log("Getting a new updatelist from the server");
trustAllCerts();
int version = getUpdateListVersion();
Logger.log("Downloading updatelist v" + version);
List<NUSTitleInformation> newupdatelist = getUpdateList(version);
Settings.logToPrintLn = false;
updatelist = new ArrayList<>(checkUpdateList(updatelist,newupdatelist));
Settings.logToPrintLn = preSettings;
if(newVersions.get() + newTitle.get() > 0){
Logger.log("Got " + (newVersions.get() + newTitle.get()) + " new updates.");
Logger.log("New versions: "+ newVersions.get());
Logger.log("New titles : "+ newTitle.get());
try {
Writer fr = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(Settings.updateCSVPath), "UTF-8"));
BufferedWriter bw = new BufferedWriter(fr);
for(NUSTitleInformation title : updatelist){
bw.write(title.toString() +"\r\n");
}
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Logger.log("Wrote them to " + Settings.updateCSVPath);
Logger.messageBox("Updated the " + Settings.updateCSVPath + "!");
}else{
Logger.log("Everything is up to date!");
}
}
return updatelist;
}
static AtomicInteger count = new AtomicInteger(0);
static AtomicInteger newVersions = new AtomicInteger(0);
static AtomicInteger newTitle = new AtomicInteger(0);
private static Collection<NUSTitleInformation> checkUpdateList(List<NUSTitleInformation> oldList,List<NUSTitleInformation> newList){
Map<Long,NUSTitleInformation> csvListMap = new HashMap<>();
for(NUSTitleInformation n : oldList){
if(!csvListMap.containsKey(n.getTitleID())){
csvListMap.put(n.getTitleID(),n);
}
}
List<NUSTitleInformation> needsDownload = new ArrayList<>();
for(NUSTitleInformation newTitleInfo : newList){
if((newTitleInfo.getTitleID()| 0x0000000E00000000L) != newTitleInfo.getTitleID())continue;
if(csvListMap.containsKey(newTitleInfo.getTitleID()| 0x0000000E00000000L)){
NUSTitleInformation existing = csvListMap.get(newTitleInfo.getTitleID()| 0x0000000E00000000L);
int existingVersion = existing.getVersion();
int newVersion = newTitleInfo.getVersion();
if(newVersion > existingVersion){
existing.addVersion(newVersion);
newVersions.incrementAndGet();
System.out.println("Found new update: " + newTitleInfo.getTitleIDAsString() + " now v" + newVersion + " instead of v" + existingVersion);
}else{
//System.out.println("No new version for" + existing.getLongnameEN());
}
}else{
newTitle.incrementAndGet();
System.out.println("Found new update: " + newTitleInfo.getTitleIDAsString()+ " v" + newTitleInfo.getVersion());
needsDownload.add(newTitleInfo);
}
}
ForkJoinPool pool = ForkJoinPool.commonPool();
List<Callable<NUSTitleInformation>> tasks = new ArrayList<>();
final int size = needsDownload.size();
for(NUSTitleInformation n : needsDownload){
final NUSTitleInformation test = n;
tasks.add(new Callable<NUSTitleInformation>() {
@Override
public NUSTitleInformation call() throws Exception {
NUSTitleInformation newinformation = null;
NUSTitle foo = new NUSTitle(test.getTitleID()| 0x0000000E00000000L, -1, null);
FEntry testa = foo.getFst().metaFENtry;
byte[] metaxml = null;
if(testa != null){
try {
metaxml = testa.downloadAsByteArray();
InputStream stream = new ByteArrayInputStream(metaxml);
newinformation = foo.readMeta(stream);
newinformation.setTitleID(newinformation.getTitleID() | 0x0000000E00000000L); //Force update
newinformation.addVersion(test.getVersion());
System.out.println(String.format("( %03d of %03d) ", count.incrementAndGet(),size) +"Downloaded information for " + test.getTitleIDAsString());
stream.close();
} catch (IOException e) {
System.out.println("Downloading information for " + test.getTitleIDAsString() + " failed");
}
}
return newinformation;
}
});
}
for(Future<NUSTitleInformation> future :pool.invokeAll(tasks)){
NUSTitleInformation newinfo = null;
try {
newinfo = future.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println("Downloading information failed");
continue;
}
if(newinfo != null){
csvListMap.put(newinfo.getTitleID(), newinfo);
}
}
return csvListMap.values();
}
private static void trustAllCerts() {
//Lets ignore the cert warning.
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){return null;}
public void checkClientTrusted(X509Certificate[] certs, String authType){}
public void checkServerTrusted(X509Certificate[] certs, String authType){}
}};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
;
}
}
private static int getUpdateListVersion(){
try {
byte[] version_xml = Downloader.getInstance().downloadHTTPSFileToByteArray(Settings.updateListVersionURL);
InputStream stream = new ByteArrayInputStream(version_xml);
int version = readVersionNumber(stream);
stream.close();
return version;
} catch (IOException e1) {
return 0;
}
}
private static List<NUSTitleInformation> getUpdateList(int version) {
List<NUSTitleInformation> list = new ArrayList<>();
try {
byte[] update_list = Downloader.getInstance().downloadHTTPSFileToByteArray(String.format(Settings.updateListURL, version));
if(update_list == null){
return list;
}
InputStream stream = new ByteArrayInputStream(update_list);
list = parseUpdateListXML(stream);
stream.close();
} catch (IOException e1) {
System.err.println("Error while downloading the updatelist!");
e1.printStackTrace();
}
return list;
}
public static List<NUSTitleInformation> parseUpdateListXML(InputStream bis) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
List<NUSTitleInformation> list = new ArrayList<>();
try {
builder = factory.newDocumentBuilder();
Document document = builder.parse(bis);
NodeList titles = document.getElementsByTagName("title");
for(int i = 0;i<titles.getLength();i++){
Node title = titles.item(i);
if(title.getChildNodes().getLength() < 2) continue;
String titleID = title.getChildNodes().item(0).getTextContent();
String version = title.getChildNodes().item(1).getTextContent();
NUSTitleInformation nusTitle = new NUSTitleInformation();
nusTitle.setTitleID(Util.StringToLong(titleID));
nusTitle.addVersion(version);
list.add(nusTitle);
}
} catch (ParserConfigurationException | SAXException | IOException e) {
Logger.log("Error while parsing the updatelist");
}
return list;
}
public static int readVersionNumber(InputStream bis) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document document = builder.parse(bis);
return Integer.parseInt(document.getElementsByTagName("version").item(0).getTextContent());
} catch (ParserConfigurationException | SAXException | IOException e) {
Logger.log("Error while parsing the meta files");
}
return 0;
}
@SuppressWarnings("resource")
private static List<NUSTitleInformation> readUpdateCSV() {
if(Settings.updateCSVPath == null) return null;
BufferedReader in = null;
List<NUSTitleInformation> list = new ArrayList<>();
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(new File(Settings.updateCSVPath)), "UTF-8"));
String line;
while((line = in.readLine()) != null){
String[] infos = line.split(";");
if(infos.length != 8) {
Logger.messageBox("Updatelist is broken! A new updatelist will be created.");
Logger.log("Updatelist is broken! A new updatelist will be created.");
return list;
}
long titleID = Util.StringToLong(infos[0].replace("-", ""));
int region = Integer.parseInt(infos[1]);
String content_platform = infos[2];
String company_code = infos[3];
String product_code = infos[4];
String ID6 = infos[5];
String longnameEN = infos[6];
String[] versions = infos[7].split(",");
NUSTitleInformation info = new NUSTitleInformation(titleID, longnameEN, ID6, product_code, content_platform, company_code, region,versions);
list.add(info);
}
in.close();
} catch (IOException | NumberFormatException e) {
try {
if(in != null)in.close();
} catch (IOException e1) {
}
Logger.messageBox("Updatelist is broken or missing. A new updatelist will be created.");
Logger.log("Updatelist is broken! A new updatelist will be created.");
return new ArrayList<>();
}
return list;
}
}