diff --git a/.gitignore b/.gitignore index 305f110..1e38492 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ out/ #Other config.pref +updateCache.pref diff --git a/cmd-instructions.md b/cmd-instructions.md index 4dd0852..a59e8ce 100644 --- a/cmd-instructions.md +++ b/cmd-instructions.md @@ -54,3 +54,8 @@ There exists commands you can use, these are explained here: - Will do a Key-Search in `C:\my rpg mv game\` and shows the Key if found, if not found it will ask if you want to generate it out of encrypted images - Example 2: `java -jar "RPG Maker MV Decrypter.jar" key "C:\my rpg mv game\" false` - Same as Example 1, just don't ask if search on images, it will always do automatically +- __update__ - Updates the Program (Help: `java -jar "RPG Maker MV Decrypter.jar" update help`) + - This Script updates the Program + - Syntax: `java -jar "RPG Maker MV Decrypter.jar" update [(Optional) Sub-Command]` + - Program Update Command: `java -jar "RPG Maker MV Decrypter.jar" update` + - Open "What's new" in your Default-Browser: `java -jar "RPG Maker MV Decrypter.jar" update whatsnew` diff --git a/src/org/petschko/lib/Const.java b/src/org/petschko/lib/Const.java index 70fe4c9..7ea663e 100644 --- a/src/org/petschko/lib/Const.java +++ b/src/org/petschko/lib/Const.java @@ -13,6 +13,7 @@ public class Const { public static final String creator = "Petschko"; public static final String creatorURL = "https://petschko.org/"; + public static final String creatorDonationUrl = "https://www.paypal.me/petschko"; // System Constance's public static final String ds = System.getProperty("file.separator"); diff --git a/src/org/petschko/lib/gui/JOptionPane.java b/src/org/petschko/lib/gui/JOptionPane.java new file mode 100644 index 0000000..84256f7 --- /dev/null +++ b/src/org/petschko/lib/gui/JOptionPane.java @@ -0,0 +1,30 @@ +package org.petschko.lib.gui; + +/** + * Author: Peter Dragicevic + * Authors-Website: https://petschko.org/ + * Date: 20.02.2021 + * Time: 18:17 + *
+ * Notes: - + */ +public class JOptionPane extends javax.swing.JOptionPane { + /** + * Popups a yes/no question popup + * + * @param msg Message to display + * @param title Title of the Popup Window + * @param type Message type (Error, Warning etc) + * @param defaultYes true/false true means that "yes" is preselected + * @return JOptionPane dialog result + */ + public static int yesNoPopupQuestion(String msg, String title, int type, boolean defaultYes) { + String def; + if(defaultYes) + def = "Yes"; + else + def = "No"; + + return JOptionPane.showOptionDialog(null, msg, title, JOptionPane.YES_NO_OPTION, type, null, new String[] {"Yes", "No"}, def); + } +} diff --git a/src/org/petschko/lib/gui/notification/NotificationWindow.java b/src/org/petschko/lib/gui/notification/NotificationWindow.java index 7c243b8..af6d5c3 100644 --- a/src/org/petschko/lib/gui/notification/NotificationWindow.java +++ b/src/org/petschko/lib/gui/notification/NotificationWindow.java @@ -211,14 +211,12 @@ protected void setDefaultTitle() { */ protected int getJOptionType() { switch(this.errorLevel) { - case ERROR_LEVEL_NOTICE: - return JOptionPane.INFORMATION_MESSAGE; case ERROR_LEVEL_WARNING: return JOptionPane.WARNING_MESSAGE; case ERROR_LEVEL_ERROR: - return JOptionPane.ERROR_MESSAGE; case ERROR_LEVEL_FATAL: return JOptionPane.ERROR_MESSAGE; + case ERROR_LEVEL_NOTICE: case ERROR_LEVEL_INFO: default: return JOptionPane.INFORMATION_MESSAGE; diff --git a/src/org/petschko/lib/update/Update.java b/src/org/petschko/lib/update/Update.java new file mode 100644 index 0000000..ce91dab --- /dev/null +++ b/src/org/petschko/lib/update/Update.java @@ -0,0 +1,282 @@ +package org.petschko.lib.update; + +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Author: Peter Dragicevic [peter@petschko.org] + * Authors-Website: http://petschko.org/ + * Date: 05.10.2017 + * Time: 14:37 + * Update: - + * Version: 0.0.1 + * + * Notes: Update Class + */ +public class Update { + private UpdateCache updateCache; + private URL checkVersionUrl; + private URL whatsNewUrl = null; + private URL downloadURL = null; + private Version currentVersion; + private Version newestVersion = null; + private boolean hasNewVersion = false; + private boolean ignoreCache = false; + + /** + * Update Constructor + * + * @param checkVersionUrl - URL to get the newest Version-Number + * @param currentVersion - Current Version + * @throws IOException - IO-Exception + */ + public Update(String checkVersionUrl, String currentVersion) throws IOException { + this.updateCache = new UpdateCache(); + this.checkVersionUrl = new URL(checkVersionUrl); + this.currentVersion = new Version(currentVersion); + + this.init(); + } + + /** + * Update Constructor + * + * @param checkVersionUrl - URL to get the newest Version-Number + * @param currentVersion - Current Version + * @param cacheTime - Cache-Time in Sec + * @throws IOException - IO-Exception + */ + public Update(String checkVersionUrl, String currentVersion, long cacheTime) throws IOException { + this.updateCache = new UpdateCache(cacheTime); + this.checkVersionUrl = new URL(checkVersionUrl); + this.currentVersion = new Version(currentVersion); + + this.init(); + } + + /** + * Update Constructor + * + * @param checkVersionUrl - URL to get the newest Version-Number + * @param currentVersion - Current Version + * @param ignoreCache - Should the Cache be ignored? + * @throws IOException - IO-Exception + */ + public Update(String checkVersionUrl, String currentVersion, boolean ignoreCache) throws IOException { + this.updateCache = new UpdateCache(); + this.checkVersionUrl = new URL(checkVersionUrl); + this.currentVersion = new Version(currentVersion); + this.ignoreCache = ignoreCache; + + this.init(); + } + + /** + * Gets the Whats-New URL + * + * @return - Whats-New URL + */ + public URL getWhatsNewUrl() { + return whatsNewUrl; + } + + /** + * Initiates this instance (may loads cache) + */ + private void init() throws IOException { + if(this.ignoreCache) { + this.getUpdateInfo(); + } else { + if(this.updateCache.loadCache()) { + this.newestVersion = this.updateCache.newestVersionCache; + this.downloadURL = this.updateCache.cachedDownloadUrl; + this.whatsNewUrl = this.updateCache.cachedWhatsNewUrl; + } else { + this.getUpdateInfo(); + } + } + + this.checkVersion(); + } + + /** + * Get all information from the File for the Update process + */ + private void getUpdateInfo() throws IOException { + // Read the Update-URL + InputStream content = this.checkVersionUrl.openStream(); + + + // Convert the read Content to Strings + int c; + int currentString = 0; + StringBuilder version = new StringBuilder(); + StringBuilder downloadUrl = new StringBuilder(); + StringBuilder whatsNewUrl = new StringBuilder(); + + while(true) { + try { + c = content.read(); + + // Exit loop if file reaches end + if(c == -1) + break; + + if(c == (int) ';') + currentString++; + else { + switch(currentString) { + case 0: + version.append((char) c); + break; + case 1: + downloadUrl.append((char) c); + break; + case 2: + whatsNewUrl.append((char) c); + break; + default: + } + } + } catch(IOException e) { + e.printStackTrace(); + break; + } + } + + this.newestVersion = new Version(version.toString().trim()); + + try { + this.downloadURL = new URL(downloadUrl.toString().trim()); + this.whatsNewUrl = new URL(whatsNewUrl.toString().trim()); + } catch(MalformedURLException e) { + e.printStackTrace(); + } + + this.savesCache(); + } + + /** + * Saves new Data to the Cache + */ + private void savesCache() { + this.updateCache.newestVersionCache = this.newestVersion; + this.updateCache.cachedDownloadUrl = this.downloadURL; + this.updateCache.cachedWhatsNewUrl = this.whatsNewUrl; + + this.updateCache.saveCache(); + } + + /** + * Checks if the Version is the newest + */ + private void checkVersion() { + if(this.newestVersion == null) + return; + + if(! this.currentVersion.versionsEqual(this.newestVersion)) + this.hasNewVersion = this.currentVersion.thisIsLowerThan(this.newestVersion); + } + + /** + * Shows if the current Version is the newest + * + * @return - Is newest Version + */ + public boolean isHasNewVersion() { + return this.hasNewVersion; + } + + /** + * Get the newest Version-Number + * + * @return - Newest Version-Number or null if could not read Update-URL + */ + public String getNewestVersion() { + return newestVersion.getVersion(); + } + + /** + * Get the current Version + * + * @return - Current Version + */ + public String getCurrentVersion() { + return currentVersion.getVersion(); + } + + /** + * Starts the updater but not relaunch after update + * + * @param targetJar - Target jar which should be updated + * @param gui - Should the Updater show a GUI window + */ + public void runUpdate(String targetJar, boolean gui) throws UpdateException { + this.runUpdate(targetJar, gui, false, null); + } + + + /** + * Starts the updater + * + * @param targetJar - Target jar which should be updated + * @param gui - Should the Updater show a GUI window + * @param relaunch - Relaunch this Program after Update + * @param relaunchArgs - Args for relaunch, can be null if none + */ + public void runUpdate(String targetJar, boolean gui, boolean relaunch, @Nullable String[] relaunchArgs) throws UpdateException { + File updaterFile = new File("update.jar"); + File targetJarFile = new File(targetJar); + + if(this.newestVersion == null) + throw new UpdateException("Newest Version is not set!", this.currentVersion); + + if(this.newestVersion.versionsEqual(new Version(""))) + throw new UpdateException("Newest Version is empty...", this.currentVersion); + + if(this.newestVersion.versionsEqual(this.currentVersion)) + throw new UpdateException("This Program is already up to date!", this.currentVersion, this.newestVersion); + + if(! targetJarFile.exists() || targetJarFile.isDirectory()) + throw new UpdateException("Can not find the Target-Jar", this.currentVersion); + + if(! updaterFile.exists() || updaterFile.isDirectory()) + throw new UpdateException("Updater not found!", this.currentVersion); + + String[] run = { + "java", + "-jar", + "update.jar", + "\"" + targetJar + "\"", + "\"" + this.downloadURL.toString() + "\"", + gui ? "true" : "false", + relaunch ? "true" : "false" + }; + + // Add args + if(relaunchArgs != null) { + String[] tmp = new String[run.length + relaunchArgs.length]; + int i; + for(i = 0; i < run.length; i++) + tmp[i] = run[i]; + + int n = i; + for(; i < tmp.length; i++) + tmp[i] = relaunchArgs[i - n]; + + run = tmp; + } + + try { + Runtime.getRuntime().exec(run); + } catch (Exception e) { + throw new UpdateException(e.getMessage(), this.currentVersion, e); + } + System.exit(0); + } +} diff --git a/src/org/petschko/lib/update/UpdateCache.java b/src/org/petschko/lib/update/UpdateCache.java new file mode 100644 index 0000000..9ca97d1 --- /dev/null +++ b/src/org/petschko/lib/update/UpdateCache.java @@ -0,0 +1,149 @@ +package org.petschko.lib.update; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.Timestamp; +import java.util.Properties; + +/** + * Author: Peter Dragicevic + * Authors-Website: https://petschko.org/ + * Date: 25.02.2021 + * Time: 16:57 + * + * Notes: - + */ +class UpdateCache { + private static final String PROP_NEWEST_VERSION_CACHE = "newestVersionCache"; + private static final String PROP_CACHED_DOWNLOAD_URL = "cachedDownloadUrl"; + private static final String PROP_WHATS_NEW_URL = "cachedWhatsNewUrl"; + private static final String PROP_LAST_CHECK = "lastCheck"; + private static final String FILE_PATH = "updateCache.pref"; + + private File propertyFile = null; + private Properties properties = null; + private long currentTime; + private long checkAgainAfterSec = 86400; // Default 1 Day + private long lastCheck = 0; + Version newestVersionCache = null; + URL cachedDownloadUrl = null; + URL cachedWhatsNewUrl = null; + + /** + * UpdateCache constructor + */ + UpdateCache() { + this.setTime(); + } + + /** + * UpdateCache constructor + * + * @param checkAgainAfterSec - Checks again after secs from last check, this overwrites default value + */ + UpdateCache(long checkAgainAfterSec) { + this.setTime(); + this.checkAgainAfterSec = checkAgainAfterSec; + } + + /** + * Sets current time + */ + private void setTime() { + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + + this.currentTime = timestamp.getTime() / 1000; + } + + /** + * Loads the cache from a File + * + * @return - true if cache was loaded successfully else false if either not all data provided or need new check + */ + boolean loadCache() { + this.propertyFile = new File(FILE_PATH); + if(! this.propertyFile.exists() || this.propertyFile.isDirectory()) { + this.propertyFile = null; + return false; + } + + this.properties = new Properties(); + Reader reader; + try { + reader = new FileReader(this.propertyFile); + this.properties.load(reader); + } catch(Exception e) { + return false; + } + + // Set the values + this.lastCheck = Long.parseLong(this.properties.getProperty(PROP_LAST_CHECK, "0")); + String cachedVersion = this.properties.getProperty(PROP_NEWEST_VERSION_CACHE, ""); + this.newestVersionCache = cachedVersion.equals("") ? null : new Version(cachedVersion); + try { + this.cachedDownloadUrl = new URL(this.properties.getProperty(PROP_CACHED_DOWNLOAD_URL, "")); + } catch(MalformedURLException e) { + this.cachedDownloadUrl = null; + } + try { + this.cachedWhatsNewUrl = new URL(this.properties.getProperty(PROP_WHATS_NEW_URL, "")); + } catch(MalformedURLException e) { + this.cachedWhatsNewUrl = null; + } + + if(this.cacheToOld()) + return false; + + return this.newestVersionCache != null && this.cachedDownloadUrl != null && this.cachedWhatsNewUrl != null; + } + + /** + * Saves the cache to a File + */ + void saveCache() { + this.lastCheck = this.currentTime; + + if(this.propertyFile == null) + this.propertyFile = new File(FILE_PATH); + + // Create missing file + if(! this.propertyFile.exists()) { + try { + new FileWriter(this.propertyFile).close(); + } catch(IOException e) { + e.printStackTrace(); + + return; + } + + if(! this.propertyFile.exists()) + return; + } + + if(this.properties == null) + this.properties = new Properties(); + + // Set the new values + this.properties.setProperty(PROP_LAST_CHECK, String.valueOf(this.lastCheck)); + this.properties.setProperty(PROP_NEWEST_VERSION_CACHE, this.newestVersionCache.getVersion()); + this.properties.setProperty(PROP_CACHED_DOWNLOAD_URL, this.cachedDownloadUrl.toString()); + this.properties.setProperty(PROP_WHATS_NEW_URL, this.cachedWhatsNewUrl.toString()); + + try { + FileWriter fileWriter = new FileWriter(FILE_PATH); + this.properties.store(fileWriter, "Update Cache File"); + } catch(IOException e) { + e.printStackTrace(); + } + } + + /** + * Shows if the cache is to old + * + * @return - Cache is to Old + */ + private boolean cacheToOld() { + return this.currentTime > this.lastCheck + this.checkAgainAfterSec; + } +} diff --git a/src/org/petschko/lib/update/UpdateException.java b/src/org/petschko/lib/update/UpdateException.java new file mode 100644 index 0000000..2d49760 --- /dev/null +++ b/src/org/petschko/lib/update/UpdateException.java @@ -0,0 +1,254 @@ +package org.petschko.lib.update; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.security.PrivilegedActionException; + +/** + * Author: Peter Dragicevic [peter@petschko.org] + * Authors-Website: https://petschko.org/ + * Date: 05.05.2019 + * Time: 17:02 + * Update: - + * Version: 0.0.1 + * + * Notes: Contains the UpdateException Class + */ +public class UpdateException extends Exception { + private Version currentVersion; + private Version newestVersion = null; + + /** + * Constructs a new exception with {@code null} as its detail message. + * The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param currentVersion - Current Version + */ + public UpdateException(@NotNull Version currentVersion) { + super(); + this.setCurrentVersion(currentVersion); + } + + /** + * Constructs a new exception with {@code null} as its detail message. + * The cause is not initialized, and may subsequently be initialized by a + * call to {@link #initCause}. + * + * @param currentVersion - Current Version + * @param newestVersion - Newest Version or null for none + */ + public UpdateException(@NotNull Version currentVersion, @Nullable Version newestVersion) { + super(); + this.setCurrentVersion(currentVersion); + this.setNewestVersion(newestVersion); + } + + /** + * Constructs a new exception with the specified detail message. The + * cause is not initialized, and may subsequently be initialized by + * a call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + * @param currentVersion - Current Version + */ + public UpdateException(String message, @NotNull Version currentVersion) { + super(message); + this.setCurrentVersion(currentVersion); + } + + /** + * Constructs a new exception with the specified detail message. The + * cause is not initialized, and may subsequently be initialized by + * a call to {@link #initCause}. + * + * @param message the detail message. The detail message is saved for + * later retrieval by the {@link #getMessage()} method. + * @param currentVersion - Current Version + * @param newestVersion - Newest Version or null for none + */ + public UpdateException(String message, @NotNull Version currentVersion, @Nullable Version newestVersion) { + super(message); + this.setCurrentVersion(currentVersion); + this.setNewestVersion(newestVersion); + } + + /** + * Constructs a new exception with the specified detail message and + * cause.
Note that the detail message associated with + * {@code cause} is not automatically incorporated in + * this exception's detail message. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param currentVersion - Current Version + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + */ + public UpdateException(String message, @NotNull Version currentVersion, Throwable cause) { + super(message, cause); + this.setCurrentVersion(currentVersion); + } + + /** + * Constructs a new exception with the specified detail message and + * cause.
Note that the detail message associated with
+ * {@code cause} is not automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param currentVersion - Current Version
+ * @param newestVersion - Newest Version or null for none
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ */
+ public UpdateException(String message, @NotNull Version currentVersion, @Nullable Version newestVersion, Throwable cause) {
+ super(message, cause);
+ this.setCurrentVersion(currentVersion);
+ this.setNewestVersion(newestVersion);
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail
+ * message of (cause==null ? null : cause.toString()) (which
+ * typically contains the class and detail message of cause).
+ * This constructor is useful for exceptions that are little more than
+ * wrappers for other throwables (for example, {@link
+ * PrivilegedActionException}).
+ *
+ * @param currentVersion - Current Version
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ */
+ public UpdateException(@NotNull Version currentVersion, Throwable cause) {
+ super(cause);
+ this.setCurrentVersion(currentVersion);
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail
+ * message of (cause==null ? null : cause.toString()) (which
+ * typically contains the class and detail message of cause).
+ * This constructor is useful for exceptions that are little more than
+ * wrappers for other throwables (for example, {@link
+ * PrivilegedActionException}).
+ *
+ * @param currentVersion - Current Version
+ * @param newestVersion - Newest Version or null for none
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ */
+ public UpdateException(@NotNull Version currentVersion, @Nullable Version newestVersion, Throwable cause) {
+ super(cause);
+ this.setCurrentVersion(currentVersion);
+ this.setNewestVersion(newestVersion);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message,
+ * cause, suppression enabled or disabled, and writable stack
+ * trace enabled or disabled.
+ *
+ * @param message the detail message.
+ * @param currentVersion - Current Version
+ * @param cause the cause. (A {@code null} value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ * @param enableSuppression whether or not suppression is enabled
+ * or disabled
+ * @param writableStackTrace whether or not the stack trace should
+ * be writable
+ */
+ protected UpdateException(String message, @NotNull Version currentVersion, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ this.setCurrentVersion(currentVersion);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message,
+ * cause, suppression enabled or disabled, and writable stack
+ * trace enabled or disabled.
+ *
+ * @param message the detail message.
+ * @param currentVersion - Current Version
+ * @param newestVersion - Newest Version or null for none
+ * @param cause the cause. (A {@code null} value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ * @param enableSuppression whether or not suppression is enabled
+ * or disabled
+ * @param writableStackTrace whether or not the stack trace should
+ * be writable
+ */
+ protected UpdateException(String message, @NotNull Version currentVersion, @Nullable Version newestVersion, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ this.setCurrentVersion(currentVersion);
+ this.setNewestVersion(newestVersion);
+ }
+
+ /**
+ * Get the current Version
+ *
+ * @return - Current Version
+ */
+ public @NotNull Version getCurrentVersion() {
+ return currentVersion;
+ }
+
+ /**
+ * Get the current Version as String
+ *
+ * @return - Current Version as String
+ */
+ public String getCurrentVersionAsString() {
+ return currentVersion.getVersion();
+ }
+
+ /**
+ * Set the current Version
+ *
+ * @param currentVersion - Current Version
+ */
+ private void setCurrentVersion(@NotNull Version currentVersion) {
+ this.currentVersion = currentVersion;
+ }
+
+ /**
+ * Get the newest Version
+ *
+ * @return - Newest Version or null
+ */
+ public @Nullable Version getNewestVersion() {
+ return newestVersion;
+ }
+
+ /**
+ * Get the newest Version as String
+ *
+ * @return - Newest Version as String
+ */
+ public String getNewestVersionAsString() {
+ if(this.newestVersion == null)
+ return "";
+
+ return newestVersion.getVersion();
+ }
+
+ /**
+ * Set the newest Version
+ *
+ * @param newestVersion - Newest Version or null
+ */
+ private void setNewestVersion(@Nullable Version newestVersion) {
+ this.newestVersion = newestVersion;
+ }
+}
diff --git a/src/org/petschko/lib/update/Version.java b/src/org/petschko/lib/update/Version.java
new file mode 100644
index 0000000..dd58036
--- /dev/null
+++ b/src/org/petschko/lib/update/Version.java
@@ -0,0 +1,92 @@
+package org.petschko.lib.update;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Author: Peter Dragicevic [peter@petschko.org]
+ * Authors-Website: https://petschko.org/
+ * Date: 05.05.2019
+ * Time: 17:16
+ * Update: -
+ * Version: 0.0.1
+ *
+ * Notes: Version Class
+ */
+public class Version {
+ private String version;
+
+ /**
+ * Version constructor
+ *
+ * @param version - Version
+ */
+ public Version(@NotNull String version) {
+ this.version = version;
+ }
+
+ /**
+ * Get the Version
+ *
+ * @return - Version
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Compares 2 Versions
+ *
+ * @param version - Version to compare
+ * @return - Versions are equal
+ */
+ public boolean versionsEqual(Version version) {
+ return this.version.equals(version.getVersion());
+ }
+
+ /**
+ * Checks if this Version is lower than the other Version
+ *
+ * @param version - Version to compare
+ * @return - This Version is lower than the other
+ */
+ public boolean thisIsLowerThan(Version version) {
+ String[] thisVersion = this.version.split("\\.");
+ String[] otherVersion = version.version.split("\\.");
+
+ // Ensure same length arrays
+ if(thisVersion.length > otherVersion.length) {
+ String[] tmp = new String[thisVersion.length];
+
+ for(int i = 0; i < tmp.length; i++) {
+ if(i < otherVersion.length)
+ tmp[i] = otherVersion[i];
+ else
+ tmp[i] = "0";
+ }
+
+ otherVersion = tmp;
+ } else if(otherVersion.length > thisVersion.length) {
+ String[] tmp = new String[otherVersion.length];
+
+ for(int i = 0; i < tmp.length; i++) {
+ if(i < thisVersion.length)
+ tmp[i] = thisVersion[i];
+ else
+ tmp[i] = "0";
+ }
+
+ thisVersion = tmp;
+ }
+
+ // Compare Versions
+ for(int n = 0; n < thisVersion.length; n++) {
+ int thisNumber = Integer.parseInt(thisVersion[n]);
+ int otherNumber = Integer.parseInt(otherVersion[n]);
+
+ if(thisNumber < otherNumber)
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/org/petschko/rpgmakermv/decrypt/App.java b/src/org/petschko/rpgmakermv/decrypt/App.java
index b027839..be02b4a 100644
--- a/src/org/petschko/rpgmakermv/decrypt/App.java
+++ b/src/org/petschko/rpgmakermv/decrypt/App.java
@@ -1,6 +1,5 @@
package org.petschko.rpgmakermv.decrypt;
-import org.petschko.lib.Const;
import org.petschko.lib.gui.notification.ErrorWindow;
/**
diff --git a/src/org/petschko/rpgmakermv/decrypt/CMD.java b/src/org/petschko/rpgmakermv/decrypt/CMD.java
index e7b7813..86ea2f8 100644
--- a/src/org/petschko/rpgmakermv/decrypt/CMD.java
+++ b/src/org/petschko/rpgmakermv/decrypt/CMD.java
@@ -16,6 +16,7 @@ class CMD {
static final int STATUS_WARNING = 1;
static final int STATUS_ERROR = -1;
static final String HELP_INDENT = " ";
+ static final String LINE_CMD = "------------------------------------------------------------------------------";
private static final String CMD_HELP = "help";
private static final String CMD_HELP_2 = "-help";
private static final String CMD_HELP_3 = "--help";
@@ -30,6 +31,7 @@ class CMD {
private static final String CMD_GET_KEY_3 = "getkey";
private static final String CMD_GET_KEY_4 = "detectkey";
private static final String CMD_GET_KEY_5 = "keydetect";
+ private static final String UPDATE = "update";
private final String[] args;
@@ -47,9 +49,11 @@ class CMD {
*/
void runCMD() {
// Show Welcome-Message
- System.out.println("------------------------------------------------------------------------------");
+ System.out.println(LINE_CMD);
System.out.println(Config.programName + " - " + Config.version + " by " + Const.creator + " | Command-Line Version");
- System.out.println("------------------------------------------------------------------------------");
+ System.out.println(LINE_CMD);
+
+ CMD_Update.checkForUpdates();
sanitizeArgs();
processArgs();
@@ -66,7 +70,8 @@ private void sanitizeArgs() {
args[0] = args[0].replaceAll("/", "");
if(args.length >= 2) {
- if(isHelpCmd(args[1].toLowerCase().trim()))
+ // Lowercase everything for help & update
+ if(isHelpCmd(args[0].toLowerCase().trim()) || isHelpCmd(args[1].toLowerCase().trim()) || args[0].toLowerCase().equals(UPDATE))
args[1] = args[1].toLowerCase().trim();
}
}
@@ -108,6 +113,9 @@ private void processArgs() {
case CMD_GET_KEY_5:
cmdHandler = new CMD_DetectKey();
break;
+ case UPDATE:
+ cmdHandler = new CMD_Update();
+ break;
default:
boolean invalidCommand = false;
if(! isHelpCmd(args[0]))
diff --git a/src/org/petschko/rpgmakermv/decrypt/CMD_Help.java b/src/org/petschko/rpgmakermv/decrypt/CMD_Help.java
index 5c28cac..989f23d 100644
--- a/src/org/petschko/rpgmakermv/decrypt/CMD_Help.java
+++ b/src/org/petschko/rpgmakermv/decrypt/CMD_Help.java
@@ -38,6 +38,7 @@ public void printHelp() {
//App.showMessage(CMD.HELP_INDENT + " restoreproject - Restores a RPG-MV/MZ Project (Makes it editable again)");
App.showMessage(CMD.HELP_INDENT + " key - Detects the Key and Displays it");
//App.showMessage(CMD.HELP_INDENT + " open - Opens an encrypted Image");
+ App.showMessage(CMD.HELP_INDENT + " update - Updates this Program");
App.showMessage("");
App.showMessage(CMD.HELP_INDENT + "Display detailed help for each command:");
App.showMessage(CMD.HELP_INDENT + " java -jar \"RPG Maker MV Decrypter.jar\" [command] help");
diff --git a/src/org/petschko/rpgmakermv/decrypt/CMD_Open.java b/src/org/petschko/rpgmakermv/decrypt/CMD_Open.java
index 9560d13..456e884 100644
--- a/src/org/petschko/rpgmakermv/decrypt/CMD_Open.java
+++ b/src/org/petschko/rpgmakermv/decrypt/CMD_Open.java
@@ -2,7 +2,6 @@
import java.awt.Desktop;
import java.io.File;
-import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
diff --git a/src/org/petschko/rpgmakermv/decrypt/CMD_Update.java b/src/org/petschko/rpgmakermv/decrypt/CMD_Update.java
new file mode 100644
index 0000000..f670ec4
--- /dev/null
+++ b/src/org/petschko/rpgmakermv/decrypt/CMD_Update.java
@@ -0,0 +1,158 @@
+package org.petschko.rpgmakermv.decrypt;
+
+import org.petschko.lib.update.Update;
+import org.petschko.lib.update.UpdateException;
+
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Author: Peter Dragicevic
+ * Authors-Website: https://petschko.org/
+ * Date: 22.02.2021
+ * Time: 22:38
+ *
+ * Notes: -
+ */
+public class CMD_Update implements CMD_Command {
+ private static final String SUB_CMD_WHATS_NEW = "whatsnew";
+
+ private Update update = null;
+
+ /**
+ * Runs the Command
+ *
+ * @param args - Command-Line commands
+ */
+ @Override
+ public void run(String[] args) {
+ this.update = checkForUpdates(false, true);
+
+ if(this.update != null) {
+ if(args.length >= 2) {
+ String subCmd = args[1];
+
+ // Handle sub CMDs
+ if(subCmd.equals(SUB_CMD_WHATS_NEW)) {
+ this.showWhatsNew();
+ } else {
+ App.showMessage("Sub-Command \"" + subCmd + "\" doesnt exists! See help", CMD.STATUS_WARNING);
+ App.showMessage("");
+ this.printHelp();
+ CMD.exitCMD(CMD.STATUS_WARNING);
+ }
+ return;
+ }
+
+ this.runUpdate();
+ }
+ }
+
+ /**
+ * Runs the Update
+ */
+ private void runUpdate() {
+ if(! this.update.isHasNewVersion()) {
+ System.out.println("You are already using the newest Version!");
+ System.out.println(CMD.LINE_CMD);
+ return;
+ }
+
+ App.showMessage("Starting update...");
+ try {
+ update.runUpdate(Config.jarFileUpdate, false);
+ } catch(UpdateException e) {
+ App.showMessage("Update Failed... Cause: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Opens the Link in whats new
+ */
+ private void showWhatsNew() {
+ if(! this.update.isHasNewVersion()) {
+ System.out.println("You are already using the newest Version!");
+ System.out.println(CMD.LINE_CMD);
+ } else if(Desktop.isDesktopSupported()) {
+ Desktop desktop = Desktop.getDesktop();
+
+ if(desktop.isSupported(Desktop.Action.BROWSE)) {
+ try {
+ URI uri = new URI(this.update.getWhatsNewUrl().toString());
+ desktop.browse(uri);
+ } catch(IOException | URISyntaxException e) {
+ App.showMessage("Can't open \"What's new...\"", CMD.STATUS_ERROR);
+ CMD.exitCMD(CMD.STATUS_ERROR);
+ return;
+ }
+ }
+ } else {
+ App.showMessage("Can't open \"What's new...\"...", CMD.STATUS_ERROR);
+ App.showMessage("This operation isnt supported by your OS!", CMD.STATUS_ERROR);
+ CMD.exitCMD(CMD.STATUS_ERROR);
+ return;
+ }
+
+ CMD.exitCMD(CMD.STATUS_OK);
+ }
+
+ /**
+ * Prints help for the command
+ */
+ @Override
+ public void printHelp() {
+ App.showMessage("Usage: java -jar \"RPG Maker MV Decrypter.jar\" update [(optional) Sub Command]");
+ App.showMessage("");
+ App.showMessage(CMD.HELP_INDENT + "Sub-Commands:");
+ App.showMessage(CMD.HELP_INDENT + " " + SUB_CMD_WHATS_NEW + " - Opens \"Whats new\" in your Browser");
+ App.showMessage("");
+ App.showMessage(CMD.HELP_INDENT + "Updates the Program:");
+ App.showMessage(CMD.HELP_INDENT + " java -jar \"RPG Maker MV Decrypter.jar\" update");
+ App.showMessage("");
+ App.showMessage(CMD.HELP_INDENT + "Show whats new in your Browser:");
+ App.showMessage(CMD.HELP_INDENT + " java -jar \"RPG Maker MV Decrypter.jar\" update " + SUB_CMD_WHATS_NEW);
+ App.showMessage("");
+ }
+
+ /**
+ * Check if there is an update and displays it
+ */
+ static void checkForUpdates() {
+ checkForUpdates(true, false);
+ }
+
+ /**
+ * Check if there is an update and may displays it
+ *
+ * @param output - Shows console output
+ * @param ignoreUpdateCache - Ignored the Update-Cache
+ * @return - Update Object
+ */
+ private static Update checkForUpdates(boolean output, boolean ignoreUpdateCache) {
+ Update update = null;
+
+ try {
+ if(ignoreUpdateCache)
+ update = new Update(Config.updateUrl, Config.versionNumber, true);
+ else
+ update = new Update(Config.updateUrl, Config.versionNumber, Config.updateCheckEverySecs);
+ } catch(IOException e) {
+ System.out.println("Update: Can't check for Updates...");
+ System.out.println(CMD.LINE_CMD);
+ }
+
+ if(update != null) {
+ if(update.isHasNewVersion() && output) {
+ System.out.println("Update: There is a new Version available! New Version: " + update.getNewestVersion());
+ System.out.println();
+ System.out.println("For update run: java -jar \"RPG Maker MV Decrypter.jar\" update");
+ System.out.println("To see whats new (Opens Browser): java -jar \"RPG Maker MV Decrypter.jar\" update "+ SUB_CMD_WHATS_NEW);
+ System.out.println(CMD.LINE_CMD);
+ }
+ }
+
+ return update;
+ }
+}
diff --git a/src/org/petschko/rpgmakermv/decrypt/Config.java b/src/org/petschko/rpgmakermv/decrypt/Config.java
index 840b962..7c21810 100644
--- a/src/org/petschko/rpgmakermv/decrypt/Config.java
+++ b/src/org/petschko/rpgmakermv/decrypt/Config.java
@@ -12,18 +12,23 @@
*/
class Config {
// Program Info
- static final String versionNumber = "0.2.0";
+ static final String versionNumber = "0.3.0";
static final String version = "v" + versionNumber + " Alpha";
static final String programName = "RPG-Maker MV/MZ Decrypter";
static final String projectPageURL = "https://github.com/Petschko/Java-RPG-Maker-MV-Decrypter";
static final String projectBugReportURL = "https://github.com/Petschko/Java-RPG-Maker-MV-Decrypter/issues";
static final String projectLicenceURL = "https://github.com/Petschko/Java-RPG-Maker-MV-Decrypter/blob/master/LICENCE";
static final String authorImage = "/org/petschko/icons/petschko_icon.png";
+ static final String updateUrl = "https://raw.githubusercontent.com/Petschko/Java-RPG-Maker-MV-Decrypter/master/version.txt";
// File-Path-Settings
static final String defaultOutputDir = "output";
static final String preferencesFile = "config.pref";
+ // Misc Settings
+ static final long updateCheckEverySecs = 172800;
+ static final String jarFileUpdate = "RPG Maker MV Decrypter.jar";
+
/**
* Constructor
*/
diff --git a/src/org/petschko/rpgmakermv/decrypt/Decrypter.java b/src/org/petschko/rpgmakermv/decrypt/Decrypter.java
index 605490b..3905b0d 100644
--- a/src/org/petschko/rpgmakermv/decrypt/Decrypter.java
+++ b/src/org/petschko/rpgmakermv/decrypt/Decrypter.java
@@ -104,6 +104,11 @@ private byte[] getRpgHeaderBytes() {
return rpgHeaderBytes;
}
+ /**
+ * Sets RPG-Header Bytes
+ *
+ * @param rpgHeaderBytes - RPG-Header Bytes
+ */
private void setRpgHeaderBytes(byte[] rpgHeaderBytes) {
this.rpgHeaderBytes = rpgHeaderBytes;
}
@@ -354,9 +359,8 @@ boolean checkFakeHeader(byte[] content) {
* @param keyName - Key-Name of the Decryption-Key
* @throws JSONException - Key not Found Exception
* @throws NullPointerException - System-File is null
- * @throws FileSystemException - Can't load File
*/
- void detectEncryptionKeyFromJson(File file, String keyName) throws JSONException, NullPointerException, FileSystemException {
+ void detectEncryptionKeyFromJson(File file, String keyName) throws JSONException, NullPointerException {
try {
if(! file.load())
throw new FileSystemException(file.getFilePath(), "", "Can't load File-Content...");
diff --git a/src/org/petschko/rpgmakermv/decrypt/GUI.java b/src/org/petschko/rpgmakermv/decrypt/GUI.java
index 5fb77b5..34b4511 100644
--- a/src/org/petschko/rpgmakermv/decrypt/GUI.java
+++ b/src/org/petschko/rpgmakermv/decrypt/GUI.java
@@ -22,7 +22,6 @@
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.nio.file.FileSystemException;
import java.util.ArrayList;
/**
@@ -64,7 +63,28 @@ class GUI {
// Assign Listener
this.assignMainMenuListener();
this.setNewOutputDir(App.outputDir);
- // todo implement
+
+ // Add Update-Check
+ if(Functions.strToBool(App.preferences.getConfig(Preferences.autoCheckForUpdates, "true")))
+ new GUI_Update(this, true);
+ }
+
+ /**
+ * Returns the Main-Window
+ *
+ * @return - Main-Window
+ */
+ JFrame getMainWindow() {
+ return mainWindow;
+ }
+
+ /**
+ * Returns the Main-Menu
+ *
+ * @return - Main-Menu
+ */
+ GUI_Menu getMainMenu() {
+ return mainMenu;
}
/**
@@ -108,6 +128,10 @@ private void createMainMenu() {
this.mainMenu.overwriteExistingFiles.setState(true);
} else
this.mainMenu.overwriteExistingFiles.setEnabled(false);
+
+ if(Functions.strToBool(App.preferences.getConfig(Preferences.autoCheckForUpdates, "true")))
+ this.mainMenu.checkForUpdates.setState(true);
+
this.mainMenu.enableOnRPGProject(false);
}
@@ -193,9 +217,13 @@ private void assignMainMenuListener() {
e -> this.mainMenu.overwriteExistingFiles.setEnabled(! this.mainMenu.overwriteExistingFiles.isEnabled())
);
this.mainMenu.overwriteExistingFiles.addActionListener(GUI_ActionListener.switchSetting(Preferences.overwriteFiles));
+ this.mainMenu.checkForUpdates.addActionListener(GUI_ActionListener.switchSetting(Preferences.autoCheckForUpdates));
// -- Decrypt
// -- Tools
// -- Info
+ this.mainMenu.updateProgram.addActionListener(
+ e -> new GUI_Update(this)
+ );
this.mainMenu.reportABug.addActionListener(GUI_ActionListener.openWebsite(Config.projectBugReportURL));
this.mainMenu.about.addActionListener(
e -> this.guiAbout.showWindow()
@@ -281,11 +309,9 @@ private class GUI_Decryption extends SwingWorker