├── .gitignore ├── LICENCE ├── README.md ├── cmd-instructions.md ├── deployment ├── start.bat ├── start.sh └── update.jar ├── pom.xml ├── src └── main │ ├── java │ └── org │ │ └── petschko │ │ ├── lib │ │ ├── CellRenderer.java │ │ ├── Const.java │ │ ├── File.java │ │ ├── Functions.java │ │ ├── Image.java │ │ ├── UserPref.java │ │ ├── exceptions │ │ │ └── PathException.java │ │ ├── gui │ │ │ ├── GUI_About.java │ │ │ ├── JDirectoryChooser.java │ │ │ ├── JImageLabel.java │ │ │ ├── JLabelExtra.java │ │ │ ├── JLabelWrap.java │ │ │ ├── JOptionPane.java │ │ │ ├── JPanelLine.java │ │ │ └── notification │ │ │ │ ├── ErrorWindow.java │ │ │ │ ├── InfoWindow.java │ │ │ │ └── NotificationWindow.java │ │ └── update │ │ │ ├── Update.java │ │ │ ├── UpdateCache.java │ │ │ ├── UpdateException.java │ │ │ └── Version.java │ │ └── rpgmakermv │ │ └── decrypt │ │ ├── App.java │ │ ├── Config.java │ │ ├── Decrypter.java │ │ ├── Finder.java │ │ ├── Preferences.java │ │ ├── RPG_Project.java │ │ ├── cmd │ │ ├── CMD.java │ │ ├── Decrypt.java │ │ ├── DetectKey.java │ │ ├── Encrypt.java │ │ ├── Help.java │ │ ├── I_CMD.java │ │ ├── Open.java │ │ ├── Restore.java │ │ ├── RestoreProject.java │ │ └── Update.java │ │ └── gui │ │ ├── About.java │ │ ├── ActionListener.java │ │ ├── FileInfo.java │ │ ├── GUI.java │ │ ├── Menu.java │ │ ├── ProjectInfo.java │ │ ├── Update.java │ │ ├── WorkerDecryption.java │ │ ├── WorkerDirectoryClearing.java │ │ ├── WorkerEncryption.java │ │ └── WorkerOpenRPGDir.java │ └── resources │ └── icons │ └── petschko_icon.png └── version.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Class Files 2 | *.class 3 | 4 | # Mobile Tools for Java (J2ME) 5 | .mtj.tmp/ 6 | 7 | # Package Files # 8 | *.jar 9 | *.war 10 | *.ear 11 | 12 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 13 | hs_err_pid* 14 | 15 | # IDE-Directories 16 | .idea/ 17 | 18 | #Output 19 | target/ 20 | output/ 21 | out/ 22 | 23 | #Other 24 | src/main/java/META-INF/MANIFEST.MF 25 | config.pref 26 | updateCache.pref 27 | RPG Maker MV Decrypter.iml 28 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Peter Dragicevic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IMPORTANT: Project MOVED to [Gitlab.com](https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter) 2 | 3 | Please look there for updates/Bug-Reports - This Github Repo will be Read-Only by now 4 | 5 | https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter 6 | 7 | ---- 8 | 9 | # Petschko's RPG-Maker-MV/MZ File-Decrypter (Java-Version) 10 | 11 | ## What's that? 12 | This Project is used to decrypt RPG-Maker-MV/MZ-Resource-Files that are encrypted with the Build-In-Encryption of the RPG-Maker. 13 | 14 | This Project is also able to decrypt whole RPG-Directories. It's similar to [my previous Project](https://gitlab.com/Petschko/RPG-Maker-MV-Decrypter) but more comfortable. 15 | 16 | ### Which Files can be decrypted with this Program? 17 | You can decrypt the Build-In-Encrypted Files from the RPG Maker MV or MZ. They usually have the extension `.rpgmvp`, `.rpgmvm`, `.rpgmvo`, `.png_`, `.m4a_` or `.ogg_`. 18 | 19 | ## Requirements 20 | - Java 8 or higher 21 | - Any OS (Linux, Windows, IOS etc) 22 | 23 | ## Installation 24 | - [Download this ZIP (!!Alpha!!) - Version: 0.4.2](https://petschko.org/upload/projects/java-rpg-maker-decrypter/RPG_Maker_MV_Decrypter_jar_0.4.2.zip) or Clone/Download the Project and make yourself a JAR-File 25 | - Put it where ever you want (Don't forget to extract, if you downloaded the ZIP xP) 26 | 27 | ### Dependencies (Only needed when creating yourself a JAR) 28 | - [org.json](https://github.com/douglascrockford/JSON-java) 29 | 30 | ## How to use 31 | ### (Normal) With Graphical interface 32 | - Just double-click on the JAR then the Program should start *(If not try the BAT-File - Windows only)* 33 | - Click on the Menu "File" then "Open" 34 | - Browse to the RPG-Maker MV Project which you want decrypt 35 | - Select the Main-Directory of the Project (The Folder where the Game.exe is) on click on "Choose Directory" 36 | - You can also put the Program right into your Game-Directory and select the option "Select Project from current Directory" 37 | - Wait for a short moment =) 38 | - If there are Files listed and a Decryption-Key is in the Text-Box you're ready to Decrypt 39 | - Then go into the Menu and click "Decrypt" -> "All Files" 40 | - After a short moment you're done =) 41 | - You can find the Files now within the "Output"-Directory, which is in the same Directory as this Program. *(If you not changed it already via "File" -> "Change Output-Directory...")* 42 | 43 | - (Not yet implemented) You can also Decrypt single/multiple Files - Select them in the Project-Files Tab after that you go to "Decrypter" -> "Selected Files" 44 | - You can also Re-Encrypt Files (For example if you translated text on images for the Game) 45 | - You can also check out the "Option"-Menu and check if the settings fit to you =) 46 | - (Not yet implemented) You can find this "Manual" also within the "Info"-Menu 47 | 48 | ### Run with CMD - For automation / the guys who like it :3 49 | 50 | In some case it can be useful to do stuff via the commandline. For example, you want to mod a game and make it easy for the user to mod it (like they just need to start a .bat/.sh file which does the stuff) 51 | 52 | - To see the global help (with all sub-commands) type in `java -jar "RPG Maker MV Decrypter.jar" help` 53 | - To see the detailed help of a specific command type in `java -jar "RPG Maker MV Decrypter.jar" [command] help` 54 | - Example (display decrypt help): `java -jar "RPG Maker MV Decrypter.jar" decrypt help` 55 | 56 | For details use and examples how to use it see [CMD Instructions](cmd-instructions.md) 57 | 58 | ## Motivation behind this 59 | As Art-Creator for the RPG-Maker by myself, it is sometimes hard to figure out, if somebody is using Resources from you *(and may violate the licence like giving no credit or using a Non-Commercial-Resource in a Commercial Game for example)*. 60 | 61 | I don't have time to play through all the games (even if I want^^). So I just quick look at the files, but it's only possible if the files are not encrypted... 62 | 63 | Sad for me, more People use the build in Encryption from the RPG-Maker-MV, so that's why I wrote this Program - To get a quick look at the Files without playing the whole Game =) May some other Artists will find this useful too. 64 | 65 | It can be also useful for Translators, e.g. when you want to make a Game available for different Regions. *(IMO you should ask the Creator of the Game first! - Sometimes it's not possible...)* 66 | 67 | I'm also interested in Encryption in general, so this was a good base to learn, since the MV-Encryption is very weak - But it's great that's simple, because it will not slow down weak machines! *(See below)* 68 | 69 | ### Why is the encryption of my Game useless in this case? 70 | Sometimes there is a nice Picture that you may save for yourself. You would even do with without this Decrypter by making a Screenshot (or record the Sound) >.< 71 | 72 | So you see there is no need for encryption in RPG-Maker Games... If someone wants to get the Files, he will be able to get them, this also happens to AAA Games. 73 | You can't encrypt your Files 100%, because the Game has to decrypt them by itself, to display them... (Or Play) - And since you are able to play the Game offline, you have to provide the Decryption Method and the Key. 74 | 75 | ### But somebody will steal my assets 76 | Yeah, that may happen but as said before, you can't stop them anyway (Even without Decrypter). Even if you use a more powerful Encryption - it will just slow down your Game on weak Machines. 77 | Everybody is allowed to save anything for (!)personal use **only**(!) - But you're **not allowed** to create a Game with them. Except it's a free Resource, then you have to follow the Licence of the Resource-Creator! 78 | So please DON'T steal stuff, as Artist I know how much time such stuff take, so DON'T do it! 79 | 80 | ### Why as Java-Project? | Advantages 81 | This Java-Decrypter is better for whole Directories or automated Scripts. It was easier to do it with Java, because you are very limited with JavaScript. (File-Access / Saving etc) 82 | Why Java? - Because I know this Language xP - Feel free to port it to an other language, which may doesn't require the installation of a Run-Time-Environment... 83 | 84 | **Advantages using this in comparison to my previous Project:** 85 | - Works with whole Directories 86 | - It detects Encrypted Files by itself 87 | - It Auto-Saves & Rename Decrypted-Files for you! 88 | - It keeps the Directory-Structure 89 | - You can specify an Output-Directory 90 | - It's able to Detect the Encryption File & Key by its own 91 | - Less buggy and faster than my JavaScript Version, because I'm independent of Browsers and Charset-Problems... 92 | - You can use Command-Line to if you want 93 | - You can, may use it for Modding? Idk I've heard that some do 94 | - Will add a restore Project Function in the future 95 | - You can en/disable the verification of the 16Byte Fake-Header 96 | - If you disable the verification, it will just cut away the Fake-Header aka the first 16 Bytes of the File *(Useful when Decrypter-Signature changes)* 97 | - If you enable the verification it will check if the Files-Header is correct (aka if it's a real Encrypted File) 98 | 99 | ## Be Fair! 100 | You are **not allowed** to use the Decrypted Files (**if its not allowed by the origin Resource-Licence**). 101 | Please **don't steal, reuse or share stuff in Public**! That's not the idea of this Program! 102 | 103 | You can save them for **Personal-Use only**. If the origin Licence allow use you can use them of course, but please follow the Licences! 104 | 105 | **If that's your Project** and you simply lost your Origin-Files, **you have the same rights**, to do stuff with them, **as before** =) 106 | 107 | ## Donate 108 | 109 | If you like this Project and want to thank me may consider to [Donate](https://www.paypal.me/petschko). I appreciate anything, which helps the Project (Pull-Requests, Bug Report etc), these are more worth than Donations but I'm happy for every amount as well. ^.^ 110 | 111 | ## Contact 112 | - E-Mail me if you have questions (no bug reporting please): peter@petschko.org 113 | - You can also tell me you like it or not >.< Of course you can make improvement suggestions if you want 114 | - Please report Bugs here on gitlab.com use the "[Issue](https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter/-/issues)"-Section on this Project 115 | -------------------------------------------------------------------------------- /cmd-instructions.md: -------------------------------------------------------------------------------- 1 | I put the detailed Command-Line explanation here since not many people use it and its pretty "long" 2 | 3 | Everything what's explained here is also explained in the help-commands within the Program. 4 | 5 | # Command explanation 6 | 7 | Before we start: 8 | - You only need the params which are marked as __(Req.)__. All other params are optional. 9 | - If a path contains a space use the quotations "" around: `"D:\games\Project with Space\"` 10 | - Remember that IOS & Linux not have a Drive-Letter nor using the `\ ` as Directory-Separator; use `/` instead when you're using Linux/MacOS 11 | - Important: If you just Type `java -jar "RPG Maker MV Decrypter.jar"` the Program will start with GUI 12 | - You can also use the Help-Command with `java -jar "RPG Maker MV Decrypter.jar" help` 13 | - The Script ends with "Done." Then you're done. 14 | 15 | There exists commands you can use, these are explained here: 16 | - __decrypt__ - Decrypts all Files (Help: `java -jar "RPG Maker MV Decrypter.jar" decrypt help`) 17 | - The Script will decrypt all Files in the target dir 18 | - Simple-Syntax: `java -jar "RPG Maker MV Decrypter.jar" decrypt [(Req.) target path] [output path] [verifyRpgDir (false|true)] [ignoreFakeHeader (true|false)]` 19 | - Full-Syntax: `java -jar "RPG Maker MV Decrypter.jar" decrypt [(Req.) target path] [output path] [verifyRpgDir (false|true)] [ignoreFakeHeader (true|false)] [headerLen (number)] [hsignature] [hversion] [hremain]` 20 | - Example 1: `java -jar "RPG Maker MV Decrypter.jar" decrypt D:\games\Project1\` 21 | - Decrypts the game located in `D:\games\Project1\` and saves files to the output dir of this program 22 | - Example 2: `java -jar "RPG Maker MV Decrypter.jar" decrypt D:\games\Project1\ D:\games\Project1\` 23 | - Decrypts the game located in `D:\games\Project1\` and saves files in the game dir _(preserves structure)_ 24 | - Example 3: `java -jar "RPG Maker MV Decrypter.jar" decrypt D:\games\Project1\ D:\games\Project1\ false true d41d8cd98f00b204e9800998ecf8427e` 25 | - Like example 2, just using the Decryption key `d41d8cd98f00b204e9800998ecf8427e` 26 | - You can do more things with `decrypt` please use the help to see more details 27 | - __restore__ - Restores all PNG-Files without a Key (Help: `java -jar "RPG Maker MV Decrypter.jar" restore help`) 28 | - The Script will restore all Files in the target dir _(no key needed)_ 29 | - Simple-Syntax: `java -jar "RPG Maker MV Decrypter.jar" restore [(Req.) target path] [output path] [verifyRpgDir (false|true)] [ignoreFakeHeader (true|false)]` 30 | - Full-Syntax: `java -jar "RPG Maker MV Decrypter.jar" restore [(Req.) target path] [output path] [verifyRpgDir (false|true)] [ignoreFakeHeader (true|false)] [headerLen (number)]` 31 | - Example 1: `java -jar "RPG Maker MV Decrypter.jar" restore "C:\my rpg mv game\"` 32 | - Restores all Images in `C:\my rpg mv game\` and saves files to the output dir of this program 33 | - Example 2: `java -jar "RPG Maker MV Decrypter.jar" restore "C:\my rpg mv game\" "C:\my rpg mv game\"` 34 | - Restores all Images in `C:\my rpg mv game\` and saves the restored images also to the game _(preserves structure)_ 35 | - Example 3: `java -jar "RPG Maker MV Decrypter.jar" restore "C:\my rpg mv game\" "C:\my rpg mv game\" true false` 36 | - Like Example 2, just adding that the Script should verify it's a RPG-MV/MZ dir and the MV/MZ-Header on the files is correct 37 | - __encrypt__ - Encrypts all Files (Help: `java -jar "RPG Maker MV Decrypter.jar" ecrypt help`) 38 | - This Script (Re-)Encrypts all Files in the target dir 39 | - This Script NEEDs a Key (so it must be either in the Target-dir - `System.json`-File) or given as Parameter 40 | - Simple-Syntax: `java -jar "RPG Maker MV Decrypter.jar" encrypt [(Req.) target path] [output path] [to MV (true|false)] [key (auto|keyValue)]` 41 | - Full-Syntax: `java -jar "RPG Maker MV Decrypter.jar" encrypt [(Req.) target path] [output path] [to MV (true|false)] [key (auto|keyValue)] [headerLen (number)] [hsignature] [hversion] [hremain]` 42 | - Example 1: `java -jar "RPG Maker MV Decrypter.jar" encrypt "C:\my rpg mv game\"` 43 | - Encrypts all resource Files in `C:\my rpg mv game\` to the MV-Format with the detected Key 44 | - Example 2: `java -jar "RPG Maker MV Decrypter.jar" encrypt "C:\my rpg mz game\" output false` 45 | - Encrypts all resource File in `C:\my rpg mz game\` to the output dir of this program in the MZ-Format 46 | - Example 3: `java -jar "RPG Maker MV Decrypter.jar" encrypt "C:\my rpg mz game\" output false d41d8cd98f00b204e9800998ecf8427e` 47 | - Same as Example 2, just using a manual given Key: `d41d8cd98f00b204e9800998ecf8427e` 48 | - You can do more things with `encrypt` please use the help to see more details 49 | - __key__ - Detects and displays the Key (Help: `java -jar "RPG Maker MV Decrypter.jar" key help`) 50 | - This Script shows the Key of the given directory/project 51 | - Simple-Syntax: `java -jar "RPG Maker MV Decrypter.jar" key [(Req.) target path] [ask before image keysearch (true|false)]` 52 | - Full-Syntax: `java -jar "RPG Maker MV Decrypter.jar" key [(Req.) target path] [ask before image keysearch (true|false)] [headerLen (number)]` 53 | - Example 1: `java -jar "RPG Maker MV Decrypter.jar" key "C:\my rpg mv game\"` 54 | - 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 55 | - Example 2: `java -jar "RPG Maker MV Decrypter.jar" key "C:\my rpg mv game\" false` 56 | - Same as Example 1, just don't ask if search on images, it will always do automatically 57 | - __update__ - Updates the Program (Help: `java -jar "RPG Maker MV Decrypter.jar" update help`) 58 | - This Script updates the Program 59 | - Syntax: `java -jar "RPG Maker MV Decrypter.jar" update [(Optional) Sub-Command]` 60 | - Program Update Command: `java -jar "RPG Maker MV Decrypter.jar" update` 61 | - Open "What's new" in your Default-Browser: `java -jar "RPG Maker MV Decrypter.jar" update whatsnew` 62 | -------------------------------------------------------------------------------- /deployment/start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | java -jar "RPG Maker MV Decrypter.jar" 3 | pause 4 | -------------------------------------------------------------------------------- /deployment/start.sh: -------------------------------------------------------------------------------- 1 | java -jar "RPG Maker MV Decrypter.jar" -------------------------------------------------------------------------------- /deployment/update.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Petschko/Java-RPG-Maker-MV-Decrypter/b6eb85c2aafacc07f14a6ee1d3def707e8721b3d/deployment/update.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.petschko 5 | rpgmaker-mv-decrypter 6 | 0.4.2 7 | jar 8 | 9 | Petschko's RPG-Maker-MV/MZ File-Decrypter 10 | This Project is used to Decrypt RPG-Maker MV/MZ Projects 11 | https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter 12 | 13 | 14 | Peter Dragicevic 15 | peter@petschko.org 16 | https://petschko.org/ 17 | 18 | 19 | 20 | 21 | MIT 22 | 23 | 24 | 25 | 26 | UTF-8 27 | 8 28 | ${java.version} 29 | ${java.version} 30 | 31 | 32 | 33 | 34 | org.json 35 | json 36 | 20230227 37 | 38 | 39 | 40 | 41 | RPG Maker MV Decrypter ${project.version} 42 | 43 | 44 | 45 | src/main/resources 46 | 47 | 48 | 49 | 50 | 51 | maven-assembly-plugin 52 | 53 | 54 | jar-with-dependencies 55 | 56 | false 57 | 58 | 59 | org.petschko.rpgmakermv.decrypt.App 60 | 61 | 62 | ${project.version} 63 | 64 | 65 | 66 | 67 | 68 | package 69 | 70 | single 71 | 72 | 73 | 74 | 75 | 76 | org.codehaus.mojo 77 | exec-maven-plugin 78 | 3.1.0 79 | 80 | 81 | 82 | java 83 | 84 | 85 | 86 | 87 | org.petschko.rpgmakermv.decrypt.App 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/CellRenderer.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.io.File; 6 | 7 | /** 8 | * @author trenton-telge 9 | */ 10 | public class CellRenderer extends DefaultListCellRenderer { 11 | private static final long serialVersionUID = 1L; 12 | private String relativePath = null; 13 | 14 | @Override 15 | public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 16 | if (value instanceof File) { 17 | File file = (File) value; 18 | String fileText = file.getName(); 19 | 20 | if(relativePath != null) 21 | fileText = file.getPath().replace(relativePath, ""); 22 | 23 | setText(fileText); 24 | 25 | if (isSelected) { 26 | setBackground(list.getSelectionBackground()); 27 | setForeground(list.getSelectionForeground()); 28 | } else { 29 | setBackground(list.getBackground()); 30 | setForeground(list.getForeground()); 31 | } 32 | 33 | setEnabled(list.isEnabled()); 34 | setFont(list.getFont()); 35 | setOpaque(true); 36 | } 37 | 38 | return this; 39 | } 40 | 41 | /** 42 | * Sets the Relative Path of the Project 43 | * 44 | * @param path - Path of the Project 45 | */ 46 | public void setRelativePath(String path) { 47 | if(path != null) 48 | path = org.petschko.lib.File.ensureDSonEndOfPath(path); 49 | 50 | this.relativePath = path; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/Const.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class Const { 7 | public static final String CREATOR = "Petschko"; 8 | public static final String CREATOR_URL = "https://petschko.org/"; 9 | public static final String CREATOR_DONATION_URL = "https://www.paypal.me/petschko"; 10 | 11 | // System Constance's 12 | public static final String DS = System.getProperty("file.separator"); 13 | public static final String NEW_LINE = System.getProperty("line.separator"); 14 | 15 | /** 16 | * Constructor 17 | */ 18 | private Const() { 19 | // VOID - This is a Static-Class 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/Functions.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib; 2 | 3 | import javax.swing.AbstractButton; 4 | import java.awt.Desktop; 5 | import java.awt.event.ActionListener; 6 | import java.net.URI; 7 | import java.net.URISyntaxException; 8 | import java.net.URL; 9 | 10 | /** 11 | * @author Peter Dragicevic 12 | */ 13 | public class Functions { 14 | /** 15 | * Returns a boolean Value depending of the String-Content 16 | * 17 | * @param str - String to Check 18 | * @return - true if string contains "true" or "1" else false 19 | */ 20 | public static boolean strToBool(String str) { 21 | if(str == null) 22 | str = ""; 23 | str = str.toLowerCase(); 24 | 25 | return str.equals("1") || str.equals("true"); 26 | } 27 | 28 | /** 29 | * Opens a Website in the Browser 30 | * 31 | * @param uri - Target URI 32 | */ 33 | public static void openWebsite(URI uri) { 34 | Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 35 | 36 | if(desktop == null) 37 | return; 38 | 39 | if(desktop.isSupported(Desktop.Action.BROWSE)) { 40 | try { 41 | desktop.browse(uri); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | } 47 | 48 | /** 49 | * Opens a Website in the Browser 50 | * 51 | * @param url - Target URL 52 | */ 53 | public static void openWebsite(URL url) { 54 | try { 55 | Functions.openWebsite(url.toURI()); 56 | } catch (URISyntaxException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | /** 62 | * Opens a Website in the Browser 63 | * 64 | * @param url - Target URI as String 65 | */ 66 | public static void openWebsite(String url) { 67 | try { 68 | Functions.openWebsite(new URI(url)); 69 | } catch(URISyntaxException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | 74 | /** 75 | * Removes all Action-Listeners from Buttons 76 | * 77 | * @param abstractButton - Button where to remove all ActionListeners 78 | */ 79 | public static void buttonRemoveAllActionListeners(AbstractButton abstractButton) { 80 | ActionListener[] actionListeners = abstractButton.getActionListeners(); 81 | 82 | for(ActionListener al : actionListeners) { 83 | abstractButton.removeActionListener(al); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/Image.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | import java.awt.image.BufferedImage; 6 | 7 | /** 8 | * @author Peter Dragicevic 9 | */ 10 | public class Image { 11 | private BufferedImage bufferedImage; 12 | 13 | /** 14 | * Image constructor 15 | * 16 | * @param bufferedImage - Buffered Image 17 | */ 18 | public Image(BufferedImage bufferedImage) { 19 | this.bufferedImage = bufferedImage; 20 | } 21 | 22 | /** 23 | * Resize the Image 24 | * 25 | * @param newWidth - New Width 26 | * @param newHeight - New Height 27 | */ 28 | public void resize(int newWidth, int newHeight) { 29 | if(this.bufferedImage == null) 30 | return; 31 | 32 | BufferedImage newImage = Image.drawNewPicture(newWidth, newHeight); 33 | Graphics g = newImage.getGraphics(); 34 | 35 | g.drawImage(this.bufferedImage, 0, 0, newWidth, newHeight, null); 36 | 37 | this.bufferedImage = newImage; 38 | } 39 | 40 | /** 41 | * Returns the width of the Image 42 | * 43 | * @return - Width of the Image or null if not set 44 | */ 45 | public int getWidth() { 46 | return bufferedImage.getWidth(); 47 | } 48 | 49 | /** 50 | * Returns the height of the Image 51 | * 52 | * @return - Height if the Image or null if not set 53 | */ 54 | public int getHeight() { 55 | return bufferedImage.getHeight(); 56 | } 57 | 58 | /** 59 | * Returns the BufferedImage 60 | * 61 | * @return - Buffered Image 62 | */ 63 | public BufferedImage getBufferedImage() { 64 | return bufferedImage; 65 | } 66 | 67 | /** 68 | * 69 | * @param x - width of the new picture 70 | * @param y - height of the new picture 71 | * @return - New Picture (transparency) 72 | * @throws NumberFormatException - Invalid-Values 73 | */ 74 | public static BufferedImage drawNewPicture(int x, int y) throws NumberFormatException { 75 | if (x <= 0 || y <= 0) 76 | throw new NumberFormatException("drawNewPicture: x and y can't be <= 0!"); 77 | 78 | BufferedImage bi = new BufferedImage(x, y, BufferedImage.TYPE_INT_ARGB); 79 | Graphics g = bi.getGraphics(); 80 | 81 | Color transparency = new Color(0, 0, 0, 0); 82 | g.setColor(transparency); 83 | g.fillRect(0, 0, x, y); 84 | 85 | return bi; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/UserPref.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib; 2 | 3 | import java.io.FileReader; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.io.Reader; 7 | import java.util.Properties; 8 | 9 | /** 10 | * @author Peter Dragicevic 11 | */ 12 | public abstract class UserPref { 13 | private Properties properties = null; 14 | private String filePath; 15 | 16 | /** 17 | * UserPrefs Constructor 18 | * 19 | * @param filePath - File-Path to UserPref-File 20 | */ 21 | public UserPref(String filePath) { 22 | this.setFilePath(filePath); 23 | 24 | if(filePath != null) 25 | this.load(); 26 | } 27 | 28 | /** 29 | * Returns the Properties Object 30 | * 31 | * @return - Properties Object 32 | */ 33 | private Properties getProperties() { 34 | return properties; 35 | } 36 | 37 | /** 38 | * Sets the Properties Object 39 | * 40 | * @param properties - Properties Object 41 | */ 42 | protected void setProperties(Properties properties) { 43 | this.properties = properties; 44 | } 45 | 46 | /** 47 | * Returns the File-Path of the Properties File 48 | * 49 | * @return - File-Path of the Properties File or null if not set 50 | */ 51 | public String getFilePath() { 52 | return filePath; 53 | } 54 | 55 | /** 56 | * Sets the File-Path of the Properties File 57 | * 58 | * @param filePath - File-Path of the Properties File 59 | */ 60 | public void setFilePath(String filePath) { 61 | this.filePath = filePath; 62 | } 63 | 64 | /** 65 | * Loads the Properties of the User from a File 66 | * 67 | * @return - true of Properties where loaded else false 68 | */ 69 | public boolean load() { 70 | if(this.getFilePath() == null) 71 | return this.loadDefaults(); 72 | 73 | if(! File.existsFile(this.getFilePath())) 74 | return this.loadDefaults(); 75 | 76 | // Try to read the File 77 | Properties p = new Properties(); 78 | Reader reader; 79 | try { 80 | reader = new FileReader(this.getFilePath()); 81 | p.load(reader); 82 | } catch(Exception e) { 83 | e.printStackTrace(); 84 | 85 | return loadDefaults(); 86 | } finally { 87 | this.setProperties(p); 88 | } 89 | 90 | return true; 91 | } 92 | 93 | /** 94 | * Loads the Default settings 95 | * 96 | * @return - true if the Properties where loaded correctly 97 | */ 98 | public abstract boolean loadDefaults(); 99 | 100 | /** 101 | * Saves the Properties of the User to a File 102 | * 103 | * @return - true if the Save was successful else false 104 | */ 105 | public boolean save() { 106 | if(this.getFilePath() == null || this.getProperties() == null) 107 | return false; 108 | 109 | // Check if File Exists if not try to create it 110 | if(! File.existsFile(this.getFilePath(), true)) 111 | return false; 112 | 113 | try { 114 | FileWriter fileWriter = new FileWriter(this.getFilePath()); 115 | this.getProperties().store(fileWriter, "User Config File"); 116 | } catch(IOException e) { 117 | e.printStackTrace(); 118 | 119 | return false; 120 | } 121 | 122 | return true; 123 | } 124 | 125 | /** 126 | * Returns the requested Property-Value with a Fallback-Value 127 | * @param configKey - Property-Key (Name) 128 | * @return - Property-Value 129 | */ 130 | public String getConfig(String configKey) { 131 | return getConfig(configKey, null); 132 | } 133 | 134 | /** 135 | * Returns the requested Property-Value or the Fallback-Value 136 | * 137 | * @param configKey - Property-Key (Name) 138 | * @param fallbackValue - Fallback-Value if the Key is not set or null to ignore 139 | * @return - Property-Value 140 | */ 141 | public String getConfig(String configKey, String fallbackValue) { 142 | if(this.getProperties() == null) 143 | this.load(); 144 | 145 | if(fallbackValue == null) 146 | return this.getProperties().getProperty(configKey); 147 | 148 | // Try to add the Property if not exists 149 | if(this.getProperties().getProperty(configKey) == null) 150 | this.setConfig(configKey, fallbackValue); 151 | 152 | return this.getProperties().getProperty(configKey, fallbackValue); 153 | } 154 | 155 | /** 156 | * Sets a Value to the Properties Object 157 | * 158 | * @param configKey - Property-Key (Name) 159 | * @param newValue - New Value for this Properties-Key 160 | */ 161 | public void setConfig(String configKey, String newValue) { 162 | if(this.getProperties() == null) 163 | this.load(); 164 | 165 | this.getProperties().setProperty(configKey, newValue); 166 | } 167 | 168 | /** 169 | * Switches a Boolean "String" value to the opposite Boolean "String" Value if the value is not a Boolean String it doesn't change anything 170 | * 171 | * @param configKey - Config Key of the Value to switch 172 | */ 173 | public void switchBoolConfig(String configKey) { 174 | String config = this.getConfig(configKey); 175 | 176 | // Config doesn't exists 177 | if(config == null) 178 | config = "false"; 179 | 180 | config = config.toLowerCase(); 181 | 182 | // Only switch on boolean values 183 | if(config.equals("true") || config.equals("false") || config.equals("1") || config.equals("0")) { 184 | boolean newValue = ! Functions.strToBool(config); 185 | 186 | this.setConfig(configKey, Boolean.toString(newValue)); 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/exceptions/PathException.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.exceptions; 2 | 3 | import java.security.PrivilegedActionException; 4 | 5 | /** 6 | * @author Peter Dragicevic 7 | */ 8 | public class PathException extends Exception { 9 | private final String path; 10 | 11 | /** 12 | * Constructs a new throwable with {@code null} as its detail message. 13 | * The cause is not initialized, and may subsequently be initialized by a 14 | * call to {@link #initCause}. 15 | * 16 | *

The {@link #fillInStackTrace()} method is called to initialize 17 | * the stack trace data in the newly created throwable. 18 | * 19 | * @param path - Path of the Exception 20 | */ 21 | public PathException(String path) { 22 | super(); 23 | this.path = path; 24 | } 25 | 26 | /** 27 | * Constructs a new throwable with the specified detail message. The 28 | * cause is not initialized, and may subsequently be initialized by 29 | * a call to {@link #initCause}. 30 | * 31 | *

The {@link #fillInStackTrace()} method is called to initialize 32 | * the stack trace data in the newly created throwable. 33 | * 34 | * @param message the detail message. The detail message is saved for 35 | * later retrieval by the {@link #getMessage()} method. 36 | * @param path - Path of the Exception 37 | */ 38 | public PathException(String message, String path) { 39 | super(message); 40 | this.path = path; 41 | } 42 | 43 | /** 44 | * Constructs a new throwable with the specified detail message and 45 | * cause.

Note that the detail message associated with 46 | * {@code cause} is not automatically incorporated in 47 | * this throwable's detail message. 48 | * 49 | *

The {@link #fillInStackTrace()} method is called to initialize 50 | * the stack trace data in the newly created throwable. 51 | * 52 | * @param message the detail message (which is saved for later retrieval 53 | * by the {@link #getMessage()} method). 54 | * @param path - Path of the Exception 55 | * @param cause the cause (which is saved for later retrieval by the 56 | * {@link #getCause()} method). (A {@code null} value is 57 | * permitted, and indicates that the cause is nonexistent or 58 | * unknown.) 59 | */ 60 | public PathException(String message, String path, Throwable cause) { 61 | super(message, cause); 62 | this.path = path; 63 | } 64 | 65 | /** 66 | * Constructs a new throwable with the specified cause and a detail 67 | * message of {@code (cause==null ? null : cause.toString())} (which 68 | * typically contains the class and detail message of {@code cause}). 69 | * This constructor is useful for throwables that are little more than 70 | * wrappers for other throwables (for example, {@link 71 | * PrivilegedActionException}). 72 | * 73 | *

The {@link #fillInStackTrace()} method is called to initialize 74 | * the stack trace data in the newly created throwable. 75 | * 76 | * @param path - Path of the Exception 77 | * @param cause the cause (which is saved for later retrieval by the 78 | * {@link #getCause()} method). (A {@code null} value is 79 | * permitted, and indicates that the cause is nonexistent or 80 | * unknown.) 81 | */ 82 | public PathException(String path, Throwable cause) { 83 | super(cause); 84 | this.path = path; 85 | } 86 | 87 | /** 88 | * Constructs a new throwable with the specified detail message, 89 | * cause, {@linkplain #addSuppressed suppression} enabled or 90 | * disabled, and writable stack trace enabled or disabled. If 91 | * suppression is disabled, {@link #getSuppressed} for this object 92 | * will return a zero-length array and calls to {@link 93 | * #addSuppressed} that would otherwise append an exception to the 94 | * suppressed list will have no effect. If the writable stack 95 | * trace is false, this constructor will not call {@link 96 | * #fillInStackTrace()}, a {@code null} will be written to the 97 | * {@code stackTrace} field, and subsequent calls to {@code 98 | * fillInStackTrace} and {@link 99 | * #setStackTrace(StackTraceElement[])} will not set the stack 100 | * trace. If the writable stack trace is false, {@link 101 | * #getStackTrace} will return a zero length array. 102 | * 103 | *

Note that the other constructors of {@code Throwable} treat 104 | * suppression as being enabled and the stack trace as being 105 | * writable. Subclasses of {@code Throwable} should document any 106 | * conditions under which suppression is disabled and document 107 | * conditions under which the stack trace is not writable. 108 | * Disabling of suppression should only occur in exceptional 109 | * circumstances where special requirements exist, such as a 110 | * virtual machine reusing exception objects under low-memory 111 | * situations. Circumstances where a given exception object is 112 | * repeatedly caught and rethrown, such as to implement control 113 | * flow between two sub-systems, is another situation where 114 | * immutable throwable objects would be appropriate. 115 | * 116 | * @param message the detail message. 117 | * @param path - Path of the Exception 118 | * @param cause the cause. (A {@code null} value is permitted, 119 | * and indicates that the cause is nonexistent or unknown.) 120 | * @param enableSuppression whether or not suppression is enabled or disabled 121 | * @param writableStackTrace whether or not the stack trace should be 122 | * writable 123 | * @see OutOfMemoryError 124 | * @see NullPointerException 125 | * @see ArithmeticException 126 | */ 127 | protected PathException(String message, String path, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 128 | super(message, cause, enableSuppression, writableStackTrace); 129 | this.path = path; 130 | } 131 | 132 | /** 133 | * Gets the Path 134 | * 135 | * @return - Path of the Exception 136 | */ 137 | public String getPath() { 138 | return path; 139 | } 140 | 141 | /** 142 | * Returns the detail message string of this throwable. 143 | * 144 | * @return the detail message string of this {@code Throwable} instance 145 | * (which may be {@code null}). 146 | */ 147 | @Override 148 | public String getMessage() { 149 | return super.getMessage() + " | Path: " + (this.getPath() == null ? "null" : this.getPath()); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/GUI_About.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import javax.swing.JButton; 4 | import javax.swing.JComponent; 5 | import javax.swing.JDialog; 6 | import javax.swing.JFrame; 7 | import java.awt.Component; 8 | import java.awt.GraphicsEnvironment; 9 | import java.awt.HeadlessException; 10 | import java.awt.event.ActionListener; 11 | import java.awt.event.WindowAdapter; 12 | import java.awt.event.WindowEvent; 13 | 14 | /** 15 | * @author Peter Dragicevic 16 | */ 17 | public abstract class GUI_About extends JDialog { 18 | protected JImageLabel imagePanel; 19 | protected Component parent; 20 | protected JButton closeButton; 21 | 22 | /** 23 | * Creates a new, initially invisible Frame with the 24 | * specified title. 25 | *

26 | * This constructor sets the component's locale property to the value 27 | * returned by JComponent.getDefaultLocale. 28 | * 29 | * @param title the title for the frame 30 | * @param relativeTo relative to which parent component 31 | * @throws HeadlessException if GraphicsEnvironment.isHeadless() 32 | * returns true. 33 | * @see GraphicsEnvironment#isHeadless 34 | * @see Component#setSize 35 | * @see Component#setVisible 36 | * @see JComponent#getDefaultLocale 37 | */ 38 | public GUI_About(String title, JFrame relativeTo) throws HeadlessException { 39 | super(relativeTo, title, JDialog.DEFAULT_MODALITY_TYPE); 40 | this.parent = relativeTo; 41 | this.imagePanel = this.aboutIcon(); 42 | 43 | this.setVisible(false); 44 | this.createCloseButton(); 45 | this.constructAbout(); 46 | this.windowCloseOperation(); 47 | 48 | this.setLocationRelativeTo(this.parent); 49 | } 50 | 51 | /** 52 | * Construct the Content of the About-Window 53 | */ 54 | protected abstract void constructAbout(); 55 | 56 | /** 57 | * Returns the text of the Close-Button 58 | * 59 | * @return - Button-Text 60 | */ 61 | protected abstract String closeButtonText(); 62 | 63 | /** 64 | * Creates the About-Icon 65 | * 66 | * @return - JImageLabel or null if not set 67 | */ 68 | protected abstract JImageLabel aboutIcon(); 69 | 70 | /** 71 | * Window Close Operation 72 | */ 73 | protected void windowCloseOperation() { 74 | this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 75 | this.addWindowListener(new WindowAdapter() { 76 | @Override 77 | public void windowClosing(WindowEvent e) { 78 | hideWindow(); 79 | } 80 | }); 81 | } 82 | 83 | /** 84 | * Creates the close Button 85 | */ 86 | protected void createCloseButton() { 87 | this.closeButton = new JButton(this.closeButtonText()); 88 | this.closeButton.addActionListener(this.closeButtonAction()); 89 | } 90 | 91 | /** 92 | * Close Action for the Button 93 | * 94 | * @return - ActionListener 95 | */ 96 | protected ActionListener closeButtonAction() { 97 | return e -> this.hideWindow(); 98 | } 99 | 100 | /** 101 | * Show this Window 102 | */ 103 | public void showWindow() { 104 | this.setLocationRelativeTo(this.parent); 105 | this.setVisible(true); 106 | this.setAlwaysOnTop(true); 107 | } 108 | 109 | /** 110 | * Hides the Window 111 | */ 112 | protected void hideWindow() { 113 | this.setAlwaysOnTop(false); 114 | this.setVisible(false); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JDirectoryChooser.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import javax.swing.JFileChooser; 4 | import java.io.File; 5 | 6 | /** 7 | * @author Peter Dragicevic 8 | */ 9 | public class JDirectoryChooser extends JFileChooser{ 10 | /** 11 | * Constructs a JFileChooser using the given path. 12 | * Passing in a null 13 | * string causes the file chooser to point to the user's default directory. 14 | * This default depends on the operating system. It is 15 | * typically the "My Documents" folder on Windows, and the user's 16 | * home directory on Unix. 17 | * 18 | * @param currentDirectoryPath a String giving the path 19 | * to a file or directory 20 | */ 21 | public JDirectoryChooser(String currentDirectoryPath) { 22 | super(currentDirectoryPath); 23 | 24 | this.setupDirChooser(); 25 | } 26 | 27 | /** 28 | * Constructs a JFileChooser using the given File 29 | * as the path. Passing in a null file 30 | * causes the file chooser to point to the user's default directory. 31 | * This default depends on the operating system. It is 32 | * typically the "My Documents" folder on Windows, and the user's 33 | * home directory on Unix. 34 | * 35 | * @param currentDirectory a File object specifying 36 | * the path to a file or directory 37 | */ 38 | public JDirectoryChooser(File currentDirectory) { 39 | super(currentDirectory); 40 | 41 | this.setupDirChooser(); 42 | } 43 | 44 | /** 45 | * Setup the Parameter so that it look & works like a DirectoryChooser 46 | */ 47 | private void setupDirChooser() { 48 | this.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 49 | this.setAcceptAllFileFilterUsed(false); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JImageLabel.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import org.petschko.lib.Image; 4 | 5 | import javax.imageio.ImageIO; 6 | import javax.swing.ImageIcon; 7 | import javax.swing.JLabel; 8 | import java.awt.image.BufferedImage; 9 | import java.io.IOException; 10 | import java.net.URL; 11 | 12 | /** 13 | * @author Peter Dragicevic 14 | */ 15 | public class JImageLabel extends JLabel { 16 | private BufferedImage image = null; 17 | 18 | /** 19 | * Creates a new JPanel with a double buffer 20 | * and a flow layout. 21 | * 22 | * @param imagePath - Path of the Image 23 | */ 24 | public JImageLabel(String imagePath) { 25 | this.setImage(imagePath, false); 26 | } 27 | 28 | /** 29 | * Creates a new JPanel with a double buffer 30 | * and a flow layout. 31 | * 32 | * @param image - File Pointing to the Image 33 | */ 34 | public JImageLabel(java.io.File image) { 35 | this.setImage(image); 36 | } 37 | 38 | /** 39 | * Creates a new JPanel with a double buffer 40 | * and a flow layout. 41 | * 42 | * @param imagePath - Path or ClassPath to the Image 43 | * @param useURL - true if use class path else false 44 | */ 45 | public JImageLabel(String imagePath, boolean useURL) { 46 | this.setImage(imagePath, useURL); 47 | } 48 | 49 | /** 50 | * Returns the Image as BufferedImage 51 | * 52 | * @return - Buffered Image or null if not set 53 | */ 54 | public BufferedImage getImage() { 55 | return image; 56 | } 57 | 58 | /** 59 | * Set this Image direct as Buffered Image 60 | * 61 | * @param image - new BufferedImage 62 | */ 63 | public void setImage(BufferedImage image) { 64 | this.image = image; 65 | this.createImagePanel(); 66 | } 67 | 68 | /** 69 | * Set a new Image as File for the Panel 70 | * 71 | * @param file - File Pointing to the Image 72 | */ 73 | public void setImage(java.io.File file) { 74 | this.setBufferedImage(file); 75 | } 76 | 77 | /** 78 | * Set a new Image as String (Path or Class-Path) for the Panel 79 | * 80 | * @param imagePath - Path or Class-Path 81 | * @param useURL - true uses Class-Path instead of a Path 82 | */ 83 | public void setImage(String imagePath, boolean useURL) { 84 | if(imagePath == null) { 85 | Exception e = new Exception("Image Path can't be null"); 86 | e.printStackTrace(); 87 | return; 88 | } 89 | 90 | if(useURL) { 91 | this.setBufferedImage(getClass().getResource(imagePath)); 92 | } else { 93 | java.io.File imageFile; 94 | 95 | try { 96 | imageFile = new java.io.File(imagePath); 97 | } catch(Exception e) { 98 | e.printStackTrace(); 99 | this.image = null; 100 | 101 | return; 102 | } 103 | 104 | this.setBufferedImage(imageFile); 105 | } 106 | } 107 | 108 | /** 109 | * Reads the imageURL 110 | * 111 | * @param imageURL - URL of the Image 112 | */ 113 | private void setBufferedImage(URL imageURL) { 114 | if(imageURL == null) { 115 | this.image = null; 116 | 117 | return; 118 | } 119 | 120 | try { 121 | this.image = ImageIO.read(imageURL); 122 | } catch(IOException e) { 123 | e.printStackTrace(); 124 | this.image = null; 125 | 126 | return; 127 | } 128 | 129 | // Try to create the new Panel after reading 130 | this.createImagePanel(); 131 | } 132 | 133 | /** 134 | * Reads an Image-File 135 | * 136 | * @param imageFile - Image-File 137 | */ 138 | private void setBufferedImage(java.io.File imageFile) { 139 | try { 140 | this.image = ImageIO.read(imageFile); 141 | } catch(IOException e) { 142 | e.printStackTrace(); 143 | this.image = null; 144 | 145 | return; 146 | } 147 | 148 | // Try to create the new Panel after reading 149 | this.createImagePanel(); 150 | } 151 | 152 | /** 153 | * Assign the Buffered Image to the Panel 154 | */ 155 | private void createImagePanel() { 156 | if(this.image != null) 157 | this.setIcon(new ImageIcon(this.image)); 158 | } 159 | 160 | /** 161 | * Resize the Element 162 | * 163 | * @param width - New Width 164 | * @param height - New Height 165 | */ 166 | public void setImageSize(int width, int height) { 167 | Image img = new Image(this.image); 168 | 169 | try { 170 | img.resize(width, height); 171 | } catch(Exception e) { 172 | e.printStackTrace(); 173 | 174 | return; 175 | } 176 | 177 | this.setImage(img.getBufferedImage()); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JLabelExtra.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import javax.swing.JLabel; 4 | import java.awt.Color; 5 | import java.awt.Cursor; 6 | import java.awt.Desktop; 7 | import java.awt.event.MouseAdapter; 8 | import java.awt.event.MouseEvent; 9 | import java.awt.font.TextAttribute; 10 | import java.io.IOException; 11 | import java.net.URI; 12 | import java.net.URISyntaxException; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * @author Peter Dragicevic 18 | */ 19 | public class JLabelExtra extends JLabel { 20 | private String url = null; 21 | private MouseAdapter urlClickEvent = null; 22 | private boolean isBold = false; 23 | private boolean isUnderline = false; 24 | private boolean isItalic = false; 25 | 26 | /** 27 | * Creates a JLabel instance with the specified 28 | * text and horizontal alignment. 29 | * The label is centered vertically in its display area. 30 | * 31 | * @param text The text to be displayed by the label. 32 | * @param horizontalAlignment One of the following constants 33 | * defined in SwingConstants: 34 | * LEFT, 35 | * CENTER, 36 | * RIGHT, 37 | * LEADING or 38 | */ 39 | public JLabelExtra(String text, int horizontalAlignment) { 40 | super(text, horizontalAlignment); 41 | } 42 | 43 | /** 44 | * Creates a JLabel instance with the specified text. 45 | * The label is aligned against the leading edge of its display area, 46 | * and centered vertically. 47 | * 48 | * @param text The text to be displayed by the label. 49 | */ 50 | public JLabelExtra(String text) { 51 | super(text); 52 | } 53 | 54 | /** 55 | * Creates a JLabel instance with 56 | * no image and with an empty string for the title. 57 | * The label is centered vertically 58 | * in its display area. 59 | * The label's contents, once set, will be displayed on the leading edge 60 | * of the label's display area. 61 | */ 62 | public JLabelExtra() { 63 | // Void 64 | } 65 | 66 | /** 67 | * Sets the Text-Color of the JLabelExtra 68 | * 69 | * @param color - new Color for the Text or null for default 70 | */ 71 | public void setTextColor(Color color) { 72 | if(color == null) { 73 | this.setForeground(new JLabel().getForeground()); 74 | return; 75 | } 76 | 77 | this.setForeground(color); 78 | } 79 | 80 | /** 81 | * Sets if the Text should be Bold 82 | * 83 | * @param bold - true if the text should be bold else false 84 | */ 85 | public void setBold(boolean bold) { 86 | if(bold && ! this.isBold) { 87 | // Set it Bold 88 | this.changeStyleAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); 89 | this.isBold = true; 90 | } else if(! bold && this.isBold) { 91 | // Remove Bold 92 | this.changeStyleAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); 93 | this.isBold = false; 94 | } 95 | } 96 | 97 | /** 98 | * Sets if the Text should be Underlined 99 | * 100 | * @param underline - true if the text should be underlined else false 101 | */ 102 | public void setUnderline(boolean underline) { 103 | if(underline && ! this.isUnderline) { 104 | // Underline it 105 | this.changeStyleAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); 106 | this.isUnderline = true; 107 | } else if(! underline && this.isUnderline) { 108 | // Remove Underline 109 | this.changeStyleAttribute(TextAttribute.UNDERLINE, -1); 110 | this.isUnderline = false; 111 | } 112 | } 113 | 114 | /** 115 | * Sets if the Text should be Italic 116 | * 117 | * @param italic - true if the text should be italic else false 118 | */ 119 | public void setItalic(boolean italic) { 120 | if(italic && ! this.isItalic) { 121 | // Set Italic 122 | this.changeStyleAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); 123 | this.isItalic = true; 124 | } else if(! italic && this.isItalic) { 125 | // Remove Italic 126 | this.changeStyleAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); 127 | this.isItalic = false; 128 | } 129 | } 130 | 131 | /** 132 | * Sets the Font-Type of the Text 133 | * 134 | * @param fontType - Font-Type of the Text or null for default 135 | */ 136 | public void setFontType(String fontType) { 137 | if(fontType == null) { 138 | this.changeStyleAttribute(TextAttribute.FONT, new JLabel().getFont().getFontName()); 139 | return; 140 | } 141 | 142 | this.changeStyleAttribute(TextAttribute.FONT, fontType); 143 | } 144 | 145 | /** 146 | * Sets the size of the Text 147 | * 148 | * @param fontSize - Font-Size of the Text or <=0 for default 149 | */ 150 | public void setFontSize(int fontSize) { 151 | if(fontSize < 1) { 152 | this.changeStyleAttribute(TextAttribute.SIZE, new JLabel().getFont().getSize()); 153 | return; 154 | } 155 | 156 | this.changeStyleAttribute(TextAttribute.SIZE, fontSize); 157 | } 158 | 159 | /** 160 | * Set a URL and let the User click on this 161 | * 162 | * @param url - URL to set or null if you want remove the URL 163 | * @param defaultURLStyle - true Styles the URL for you Underlined-Blue else it don't style it for you 164 | */ 165 | public void setURL(String url, boolean defaultURLStyle) { 166 | if(url == null) { 167 | this.removeURL(defaultURLStyle); 168 | return; 169 | } 170 | 171 | if(this.url != null) { 172 | // Don't change anything if the url is the same 173 | if(this.url.equals(url)) 174 | return; 175 | 176 | // Remove old URL if url is different 177 | this.removeURL(defaultURLStyle); 178 | } 179 | 180 | // Styles 181 | if(defaultURLStyle) { 182 | this.setUnderline(true); 183 | this.setTextColor(Color.BLUE); 184 | } 185 | 186 | // Assign new URL 187 | this.url = url; 188 | this.setCursor(new Cursor(Cursor.HAND_CURSOR)); 189 | this.createMouseURLListener(); 190 | this.addMouseListener(this.urlClickEvent); 191 | } 192 | 193 | /** 194 | * Removes the URL Event and reset some styles back 195 | * 196 | * @param defaultURLStyle - true remove default URL-Styles else it don't remove styles 197 | */ 198 | private void removeURL(boolean defaultURLStyle) { 199 | this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 200 | 201 | // Remove Styles 202 | if(defaultURLStyle) { 203 | this.setUnderline(false); 204 | this.setTextColor(null); 205 | } 206 | 207 | if(this.urlClickEvent != null) { 208 | this.removeMouseListener(this.urlClickEvent); 209 | this.urlClickEvent = null; 210 | this.url = null; 211 | } 212 | } 213 | 214 | /** 215 | * Creates a MouseAdapter from the given URL 216 | */ 217 | private void createMouseURLListener() { 218 | if(this.url == null) 219 | return; 220 | 221 | this.urlClickEvent = new MouseAdapter() { 222 | /** 223 | * {@inheritDoc} 224 | * 225 | * @param e 226 | */ 227 | @Override 228 | public void mouseClicked(MouseEvent e) { 229 | try { 230 | Desktop.getDesktop().browse(new URI(url)); 231 | } catch (URISyntaxException | IOException ex) { 232 | ex.printStackTrace(); 233 | } 234 | } 235 | }; 236 | } 237 | 238 | /** 239 | * Changes an Attribute of the Font 240 | * 241 | * @param attributeKey - Key of the Attribute 242 | * @param value - New Value of the Attribute 243 | */ 244 | private void changeStyleAttribute(TextAttribute attributeKey, Object value) { 245 | Map attributes = new HashMap<>(this.getFont().getAttributes()); 246 | attributes.put(attributeKey, value); 247 | this.setFont(this.getFont().deriveFont(attributes)); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JLabelWrap.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import javax.swing.JTextArea; 4 | import javax.swing.UIManager; 5 | 6 | /** 7 | * @author Peter Dragicevic 8 | */ 9 | public class JLabelWrap extends JTextArea { 10 | /** 11 | * JLabelWrap Constructor 12 | */ 13 | public JLabelWrap() { 14 | this.styleItAsLabel(); 15 | } 16 | 17 | /** 18 | * JLabelWrap Constructor 19 | * 20 | * @param text - Label-Text 21 | */ 22 | public JLabelWrap(String text) { 23 | super(text); 24 | 25 | this.styleItAsLabel(); 26 | } 27 | 28 | /** 29 | * JLabelWrap Constructor 30 | * 31 | * @param rows - Rows of the Element 32 | * @param columns - Columns of the Element 33 | */ 34 | public JLabelWrap(int rows, int columns) { 35 | super(rows, columns); 36 | 37 | this.styleItAsLabel(); 38 | } 39 | 40 | /** 41 | * JLabelWrap Constructor 42 | * 43 | * @param text - Label-Text 44 | * @param rows - Rows of the Element 45 | * @param columns - Columns of the Element 46 | */ 47 | public JLabelWrap(String text, int rows, int columns) { 48 | super(text, rows, columns); 49 | 50 | this.styleItAsLabel(); 51 | } 52 | 53 | /** 54 | * Styles the Text-Area to look like a Label 55 | */ 56 | private void styleItAsLabel() { 57 | this.setFont(UIManager.getFont("Label.font")); 58 | this.setBackground(null); 59 | this.setBorder(null); 60 | this.setOpaque(false); 61 | this.setLineWrap(true); 62 | this.setWrapStyleWord(true); 63 | this.setEditable(false); 64 | this.setFocusable(false); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JOptionPane.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class JOptionPane extends javax.swing.JOptionPane { 7 | /** 8 | * Popups a yes/no question popup 9 | * 10 | * @param msg Message to display 11 | * @param title Title of the Popup Window 12 | * @param type Message type (Error, Warning etc) 13 | * @param defaultYes true/false true means that "yes" is preselected 14 | * @return JOptionPane dialog result 15 | */ 16 | public static int yesNoPopupQuestion(String msg, String title, int type, boolean defaultYes) { 17 | String def; 18 | if(defaultYes) 19 | def = "Yes"; 20 | else 21 | def = "No"; 22 | 23 | return JOptionPane.showOptionDialog(null, msg, title, JOptionPane.YES_NO_OPTION, type, null, new String[] {"Yes", "No"}, def); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/JPanelLine.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui; 2 | 3 | import javax.swing.Box; 4 | import javax.swing.BoxLayout; 5 | import javax.swing.JLabel; 6 | import javax.swing.JPanel; 7 | import java.awt.Component; 8 | import java.awt.Dimension; 9 | 10 | /** 11 | * @author Peter Dragicevic 12 | */ 13 | public class JPanelLine extends JPanel { 14 | /** 15 | * Creates a new JPanel with a double buffer 16 | * and a box layout. 17 | */ 18 | public JPanelLine() { 19 | this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); 20 | this.setAlignmentX(Component.LEFT_ALIGNMENT); 21 | } 22 | 23 | /** 24 | * Adds a Label with 1 empty space 25 | */ 26 | public void addSpaceLabel() { 27 | this.add(new JLabel(" ")); 28 | } 29 | 30 | /** 31 | * Adds a Space-Dimension 32 | * 33 | * @param len - Length of the Dimension 34 | */ 35 | public void addSpaceDimension(int len) { 36 | this.add(Box.createRigidArea(new Dimension(len, 0))); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/notification/ErrorWindow.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui.notification; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class ErrorWindow extends NotificationWindow { 7 | /** 8 | * NotificationWindow Constructor 9 | * 10 | * @param message - Message for this Notification 11 | * @param errorLevel - Error-Level of this Notification 12 | * @param stopProgram - Stop Program when Displaying this 13 | */ 14 | public ErrorWindow(String message, int errorLevel, boolean stopProgram) { 15 | super(message, null, errorLevel, stopProgram); 16 | } 17 | 18 | /** 19 | * NotificationWindow Constructor 20 | * 21 | * @param message - Message for this Notification 22 | * @param errorLevel - Error-Level of this Notification 23 | * @param stopProgram - Stop Program when Displaying this 24 | * @param e - Exception of this Notification 25 | */ 26 | public ErrorWindow(String message, int errorLevel, boolean stopProgram, Exception e) { 27 | super(message, null, errorLevel, stopProgram, e); 28 | } 29 | 30 | /** 31 | * NotificationWindow Constructor 32 | * 33 | * @param message - Message for this Notification 34 | * @param title - Title for this Notification 35 | * @param errorLevel - Error-Level of this Notification 36 | * @param stopProgram - Stop Program when Displaying this 37 | * @param e - Exception of this Notification 38 | */ 39 | public ErrorWindow(String message, String title, int errorLevel, boolean stopProgram, Exception e) { 40 | super(message, title, errorLevel, stopProgram, e); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/notification/InfoWindow.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui.notification; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class InfoWindow extends NotificationWindow { 7 | /** 8 | * NotificationWindow Constructor 9 | * 10 | * @param message - Message for this Notification 11 | */ 12 | public InfoWindow(String message) { 13 | super(message, null); 14 | } 15 | 16 | /** 17 | * NotificationWindow Constructor 18 | * 19 | * @param message - Message for this Notification 20 | * @param title - Title for this Notification 21 | */ 22 | public InfoWindow(String message, String title) { 23 | super(message, title); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/gui/notification/NotificationWindow.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.gui.notification; 2 | 3 | import javax.swing.JOptionPane; 4 | import java.awt.Component; 5 | import java.io.PrintWriter; 6 | import java.io.StringWriter; 7 | 8 | /** 9 | * @author Peter Dragicevic 10 | */ 11 | abstract class NotificationWindow { 12 | public static final int ERROR_LEVEL_FATAL = 4; 13 | public static final int ERROR_LEVEL_ERROR = 3; 14 | public static final int ERROR_LEVEL_WARNING = 2; 15 | public static final int ERROR_LEVEL_NOTICE = 1; 16 | public static final int ERROR_LEVEL_INFO = 0; 17 | 18 | private int errorLevel; 19 | private String title; 20 | private String message; 21 | private boolean stopProgram = false; 22 | private Exception e = null; 23 | 24 | /** 25 | * NotificationWindow Constructor 26 | * 27 | * @param message - Message for this Notification 28 | * @param title - Title for this Notification 29 | */ 30 | NotificationWindow(String message, String title) { 31 | this.errorLevel = ERROR_LEVEL_INFO; 32 | this.setTitle(title); 33 | this.message = message; 34 | } 35 | 36 | /** 37 | * NotificationWindow Constructor 38 | * 39 | * @param message - Message for this Notification 40 | * @param title - Title for this Notification 41 | * @param errorLevel - Error-Level of this Notification 42 | */ 43 | NotificationWindow(String message, String title, int errorLevel) { 44 | this.errorLevel = errorLevel; 45 | this.setTitle(title); 46 | this.message = message; 47 | } 48 | 49 | /** 50 | * NotificationWindow Constructor 51 | * 52 | * @param message - Message for this Notification 53 | * @param title - Title for this Notification 54 | * @param errorLevel - Error-Level of this Notification 55 | * @param stopProgram - Stop Program when Displaying this 56 | */ 57 | NotificationWindow(String message, String title, int errorLevel, boolean stopProgram) { 58 | this.errorLevel = errorLevel; 59 | this.setTitle(title); 60 | this.message = message; 61 | this.stopProgram = stopProgram; 62 | } 63 | 64 | /** 65 | * NotificationWindow Constructor 66 | * 67 | * @param message - Message for this Notification 68 | * @param title - Title for this Notification 69 | * @param errorLevel - Error-Level of this Notification 70 | * @param stopProgram - Stop Program when Displaying this 71 | * @param e - Exception of this Notification 72 | */ 73 | NotificationWindow(String message, String title, int errorLevel, boolean stopProgram, Exception e) { 74 | this.errorLevel = errorLevel; 75 | this.setTitle(title); 76 | this.message = message; 77 | this.stopProgram = stopProgram; 78 | this.e = e; 79 | } 80 | 81 | /** 82 | * Returns the Error-Level for this Notification 83 | * 84 | * @return - Error-Level for this Notification 85 | */ 86 | public int getErrorLevel() { 87 | return errorLevel; 88 | } 89 | 90 | /** 91 | * Set the Error-Level for this Notification 92 | * 93 | * @param errorLevel - Error-Level for this Notification 94 | */ 95 | protected void setErrorLevel(int errorLevel) { 96 | this.errorLevel = errorLevel; 97 | } 98 | 99 | /** 100 | * Returns the Title for this Notification 101 | * 102 | * @return - Title for this Notification 103 | */ 104 | public String getTitle() { 105 | return title; 106 | } 107 | 108 | /** 109 | * Sets the Title for this Notification 110 | * 111 | * @param title - Title for this Notification 112 | */ 113 | public void setTitle(String title) { 114 | if(title == null) 115 | this.setDefaultTitle(); 116 | else 117 | this.title = title; 118 | } 119 | 120 | /** 121 | * Returns the Message that will shown 122 | * 123 | * @return - Notification Message 124 | */ 125 | public String getMessage() { 126 | return message; 127 | } 128 | 129 | /** 130 | * Sets the Message for this Notification 131 | * 132 | * @param message - Message to display 133 | */ 134 | public void setMessage(String message) { 135 | this.message = message; 136 | } 137 | 138 | /** 139 | * Returns if the Program will stop when showing this Dialog 140 | * 141 | * @return - true if the Program will stop on showing else false 142 | */ 143 | public boolean isStopProgram() { 144 | return stopProgram; 145 | } 146 | 147 | /** 148 | * Set if the Program should stop if the Window is shown 149 | * 150 | * @param stopProgram - true if the Program should stop on showing else false 151 | */ 152 | public void setStopProgram(boolean stopProgram) { 153 | this.stopProgram = stopProgram; 154 | } 155 | 156 | /** 157 | * Returns the Exception of the Dialog 158 | * 159 | * @return - Exception or null 160 | */ 161 | public Exception getE() { 162 | return e; 163 | } 164 | 165 | /** 166 | * Sets the Exception for this Dialog 167 | * 168 | * @param e - Exception 169 | */ 170 | public void setE(Exception e) { 171 | this.e = e; 172 | } 173 | 174 | /** 175 | * Sets the Title depending on the Error-Level 176 | */ 177 | protected void setDefaultTitle() { 178 | switch(this.errorLevel) { 179 | case ERROR_LEVEL_NOTICE: 180 | this.title = "Notice"; 181 | break; 182 | case ERROR_LEVEL_WARNING: 183 | this.title = "Warning"; 184 | break; 185 | case ERROR_LEVEL_ERROR: 186 | this.title = "Error"; 187 | break; 188 | case ERROR_LEVEL_FATAL: 189 | this.title = "Fatal-Error"; 190 | break; 191 | case ERROR_LEVEL_INFO: 192 | default: 193 | this.title = "Info"; 194 | } 195 | } 196 | 197 | /** 198 | * Returns the JOptionPane Type depending on the Error-Level 199 | * 200 | * @return - JOptionPane Type 201 | */ 202 | protected int getJOptionType() { 203 | switch(this.errorLevel) { 204 | case ERROR_LEVEL_WARNING: 205 | return JOptionPane.WARNING_MESSAGE; 206 | case ERROR_LEVEL_ERROR: 207 | case ERROR_LEVEL_FATAL: 208 | return JOptionPane.ERROR_MESSAGE; 209 | case ERROR_LEVEL_NOTICE: 210 | case ERROR_LEVEL_INFO: 211 | default: 212 | return JOptionPane.INFORMATION_MESSAGE; 213 | } 214 | } 215 | 216 | /** 217 | * Returns the Message with Exception-Trace if there is an Exception set 218 | * 219 | * @return - Full-Message 220 | */ 221 | protected String getFullMessage() { 222 | if(this.e != null) { 223 | StringWriter stringWriter = new StringWriter(); 224 | this.e.printStackTrace(new PrintWriter(stringWriter)); 225 | 226 | return this.message + " | Exception-Trace: " + stringWriter.toString(); 227 | } 228 | 229 | return this.message; 230 | } 231 | 232 | /** 233 | * Shows this Notification-Window 234 | */ 235 | public void show() { 236 | this.show(null); 237 | } 238 | 239 | /** 240 | * Shows this Notification-Window 241 | * 242 | * @param parentComponent - Parent Component or null for none 243 | */ 244 | public void show(Component parentComponent) { 245 | JOptionPane.showConfirmDialog(parentComponent, this.getFullMessage(), this.getTitle(), JOptionPane.DEFAULT_OPTION, this.getJOptionType()); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/update/Update.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.update; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | 9 | /** 10 | * @author Peter Dragicevic 11 | */ 12 | public class Update { 13 | private UpdateCache updateCache; 14 | private URL checkVersionUrl; 15 | private URL whatsNewUrl = null; 16 | private URL downloadURL = null; 17 | private Version currentVersion; 18 | private Version newestVersion = null; 19 | private boolean hasNewVersion = false; 20 | private boolean ignoreCache = false; 21 | 22 | /** 23 | * Update Constructor 24 | * 25 | * @param checkVersionUrl - URL to get the newest Version-Number 26 | * @param currentVersion - Current Version 27 | * @throws IOException - IO-Exception 28 | */ 29 | public Update(String checkVersionUrl, String currentVersion) throws IOException { 30 | this.updateCache = new UpdateCache(); 31 | this.checkVersionUrl = new URL(checkVersionUrl); 32 | this.currentVersion = new Version(currentVersion); 33 | 34 | this.init(); 35 | } 36 | 37 | /** 38 | * Update Constructor 39 | * 40 | * @param checkVersionUrl - URL to get the newest Version-Number 41 | * @param currentVersion - Current Version 42 | * @param cacheTime - Cache-Time in Sec 43 | * @throws IOException - IO-Exception 44 | */ 45 | public Update(String checkVersionUrl, String currentVersion, long cacheTime) throws IOException { 46 | this.updateCache = new UpdateCache(cacheTime); 47 | this.checkVersionUrl = new URL(checkVersionUrl); 48 | this.currentVersion = new Version(currentVersion); 49 | 50 | this.init(); 51 | } 52 | 53 | /** 54 | * Update Constructor 55 | * 56 | * @param checkVersionUrl - URL to get the newest Version-Number 57 | * @param currentVersion - Current Version 58 | * @param ignoreCache - Should the Cache be ignored? 59 | * @throws IOException - IO-Exception 60 | */ 61 | public Update(String checkVersionUrl, String currentVersion, boolean ignoreCache) throws IOException { 62 | this.updateCache = new UpdateCache(); 63 | this.checkVersionUrl = new URL(checkVersionUrl); 64 | this.currentVersion = new Version(currentVersion); 65 | this.ignoreCache = ignoreCache; 66 | 67 | this.init(); 68 | } 69 | 70 | /** 71 | * Gets the Whats-New URL 72 | * 73 | * @return - Whats-New URL 74 | */ 75 | public URL getWhatsNewUrl() { 76 | return whatsNewUrl; 77 | } 78 | 79 | /** 80 | * Initiates this instance (may loads cache) 81 | */ 82 | private void init() throws IOException { 83 | if(this.ignoreCache) { 84 | this.getUpdateInfo(); 85 | } else { 86 | if(this.updateCache.loadCache()) { 87 | this.newestVersion = this.updateCache.newestVersionCache; 88 | this.downloadURL = this.updateCache.cachedDownloadUrl; 89 | this.whatsNewUrl = this.updateCache.cachedWhatsNewUrl; 90 | } else { 91 | this.getUpdateInfo(); 92 | } 93 | } 94 | 95 | this.checkVersion(); 96 | } 97 | 98 | /** 99 | * Get all information from the File for the Update process 100 | */ 101 | private void getUpdateInfo() throws IOException { 102 | // Read the Update-URL 103 | InputStream content = this.checkVersionUrl.openStream(); 104 | 105 | 106 | // Convert the read Content to Strings 107 | int c; 108 | int currentString = 0; 109 | StringBuilder version = new StringBuilder(); 110 | StringBuilder downloadUrl = new StringBuilder(); 111 | StringBuilder whatsNewUrl = new StringBuilder(); 112 | 113 | while(true) { 114 | try { 115 | c = content.read(); 116 | 117 | // Exit loop if file reaches end 118 | if(c == -1) 119 | break; 120 | 121 | if(c == (int) ';') 122 | currentString++; 123 | else { 124 | switch(currentString) { 125 | case 0: 126 | version.append((char) c); 127 | break; 128 | case 1: 129 | downloadUrl.append((char) c); 130 | break; 131 | case 2: 132 | whatsNewUrl.append((char) c); 133 | break; 134 | default: 135 | } 136 | } 137 | } catch(IOException e) { 138 | e.printStackTrace(); 139 | break; 140 | } 141 | } 142 | 143 | this.newestVersion = new Version(version.toString().trim()); 144 | 145 | try { 146 | this.downloadURL = new URL(downloadUrl.toString().trim()); 147 | this.whatsNewUrl = new URL(whatsNewUrl.toString().trim()); 148 | } catch(MalformedURLException e) { 149 | e.printStackTrace(); 150 | } 151 | 152 | this.savesCache(); 153 | } 154 | 155 | /** 156 | * Saves new Data to the Cache 157 | */ 158 | private void savesCache() { 159 | this.updateCache.newestVersionCache = this.newestVersion; 160 | this.updateCache.cachedDownloadUrl = this.downloadURL; 161 | this.updateCache.cachedWhatsNewUrl = this.whatsNewUrl; 162 | 163 | this.updateCache.saveCache(); 164 | } 165 | 166 | /** 167 | * Checks if the Version is the newest 168 | */ 169 | private void checkVersion() { 170 | if(this.newestVersion == null) 171 | return; 172 | 173 | if(! this.currentVersion.versionsEqual(this.newestVersion)) 174 | this.hasNewVersion = this.currentVersion.thisIsLowerThan(this.newestVersion); 175 | } 176 | 177 | /** 178 | * Shows if the current Version is the newest 179 | * 180 | * @return - Is newest Version 181 | */ 182 | public boolean isHasNewVersion() { 183 | return this.hasNewVersion; 184 | } 185 | 186 | /** 187 | * Get the newest Version-Number 188 | * 189 | * @return - Newest Version-Number or null if could not read Update-URL 190 | */ 191 | public String getNewestVersion() { 192 | return newestVersion.getVersion(); 193 | } 194 | 195 | /** 196 | * Get the current Version 197 | * 198 | * @return - Current Version 199 | */ 200 | public String getCurrentVersion() { 201 | return currentVersion.getVersion(); 202 | } 203 | 204 | /** 205 | * Starts the updater but not relaunch after update 206 | * 207 | * @param targetJar - Target jar which should be updated 208 | * @param gui - Should the Updater show a GUI window 209 | */ 210 | public void runUpdate(String targetJar, boolean gui) throws UpdateException { 211 | this.runUpdate(targetJar, gui, false, null); 212 | } 213 | 214 | 215 | /** 216 | * Starts the updater 217 | * 218 | * @param targetJar - Target jar which should be updated 219 | * @param gui - Should the Updater show a GUI window 220 | * @param relaunch - Relaunch this Program after Update 221 | * @param relaunchArgs - Args for relaunch, can be null if none 222 | */ 223 | public void runUpdate(String targetJar, boolean gui, boolean relaunch, String[] relaunchArgs) throws UpdateException { 224 | File updaterFile = new File("update.jar"); 225 | File targetJarFile = new File(targetJar); 226 | 227 | if(this.newestVersion == null) 228 | throw new UpdateException("Newest Version is not set!", this.currentVersion); 229 | 230 | if(this.newestVersion.versionsEqual(new Version(""))) 231 | throw new UpdateException("Newest Version is empty...", this.currentVersion); 232 | 233 | if(this.newestVersion.versionsEqual(this.currentVersion)) 234 | throw new UpdateException("This Program is already up to date!", this.currentVersion, this.newestVersion); 235 | 236 | if(! targetJarFile.exists() || targetJarFile.isDirectory()) 237 | throw new UpdateException("Can not find the Target-Jar", this.currentVersion); 238 | 239 | if(! updaterFile.exists() || updaterFile.isDirectory()) 240 | throw new UpdateException("Updater not found!", this.currentVersion); 241 | 242 | String[] run = { 243 | "java", 244 | "-jar", 245 | "update.jar", 246 | "\"" + targetJar + "\"", 247 | "\"" + this.downloadURL.toString() + "\"", 248 | gui ? "true" : "false", 249 | relaunch ? "true" : "false" 250 | }; 251 | 252 | // Add args 253 | if(relaunchArgs != null) { 254 | String[] tmp = new String[run.length + relaunchArgs.length]; 255 | int i; 256 | for(i = 0; i < run.length; i++) 257 | tmp[i] = run[i]; 258 | 259 | int n = i; 260 | for(; i < tmp.length; i++) 261 | tmp[i] = relaunchArgs[i - n]; 262 | 263 | run = tmp; 264 | } 265 | 266 | try { 267 | Runtime.getRuntime().exec(run); 268 | } catch (Exception e) { 269 | throw new UpdateException(e.getMessage(), this.currentVersion, e); 270 | } 271 | System.exit(0); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/update/UpdateCache.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.update; 2 | 3 | import java.io.*; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | import java.sql.Timestamp; 7 | import java.util.Properties; 8 | 9 | /** 10 | * @author Peter Dragicevic 11 | */ 12 | class UpdateCache { 13 | private static final String PROP_NEWEST_VERSION_CACHE = "newestVersionCache"; 14 | private static final String PROP_CACHED_DOWNLOAD_URL = "cachedDownloadUrl"; 15 | private static final String PROP_WHATS_NEW_URL = "cachedWhatsNewUrl"; 16 | private static final String PROP_LAST_CHECK = "lastCheck"; 17 | private static final String FILE_PATH = "updateCache.pref"; 18 | 19 | private File propertyFile = null; 20 | private Properties properties = null; 21 | private long currentTime; 22 | private long checkAgainAfterSec = 86400; // Default 1 Day 23 | private long lastCheck = 0; 24 | Version newestVersionCache = null; 25 | URL cachedDownloadUrl = null; 26 | URL cachedWhatsNewUrl = null; 27 | 28 | /** 29 | * UpdateCache constructor 30 | */ 31 | UpdateCache() { 32 | this.setTime(); 33 | } 34 | 35 | /** 36 | * UpdateCache constructor 37 | * 38 | * @param checkAgainAfterSec - Checks again after secs from last check, this overwrites default value 39 | */ 40 | UpdateCache(long checkAgainAfterSec) { 41 | this.setTime(); 42 | this.checkAgainAfterSec = checkAgainAfterSec; 43 | } 44 | 45 | /** 46 | * Sets current time 47 | */ 48 | private void setTime() { 49 | Timestamp timestamp = new Timestamp(System.currentTimeMillis()); 50 | 51 | this.currentTime = timestamp.getTime() / 1000; 52 | } 53 | 54 | /** 55 | * Loads the cache from a File 56 | * 57 | * @return - true if cache was loaded successfully else false if either not all data provided or need new check 58 | */ 59 | boolean loadCache() { 60 | this.propertyFile = new File(FILE_PATH); 61 | if(! this.propertyFile.exists() || this.propertyFile.isDirectory()) { 62 | this.propertyFile = null; 63 | return false; 64 | } 65 | 66 | this.properties = new Properties(); 67 | Reader reader; 68 | try { 69 | reader = new FileReader(this.propertyFile); 70 | this.properties.load(reader); 71 | } catch(Exception e) { 72 | return false; 73 | } 74 | 75 | // Set the values 76 | this.lastCheck = Long.parseLong(this.properties.getProperty(PROP_LAST_CHECK, "0")); 77 | String cachedVersion = this.properties.getProperty(PROP_NEWEST_VERSION_CACHE, ""); 78 | this.newestVersionCache = cachedVersion.equals("") ? null : new Version(cachedVersion); 79 | try { 80 | this.cachedDownloadUrl = new URL(this.properties.getProperty(PROP_CACHED_DOWNLOAD_URL, "")); 81 | } catch(MalformedURLException e) { 82 | this.cachedDownloadUrl = null; 83 | } 84 | try { 85 | this.cachedWhatsNewUrl = new URL(this.properties.getProperty(PROP_WHATS_NEW_URL, "")); 86 | } catch(MalformedURLException e) { 87 | this.cachedWhatsNewUrl = null; 88 | } 89 | 90 | if(this.cacheToOld()) 91 | return false; 92 | 93 | return this.newestVersionCache != null && this.cachedDownloadUrl != null && this.cachedWhatsNewUrl != null; 94 | } 95 | 96 | /** 97 | * Saves the cache to a File 98 | */ 99 | void saveCache() { 100 | this.lastCheck = this.currentTime; 101 | 102 | if(this.propertyFile == null) 103 | this.propertyFile = new File(FILE_PATH); 104 | 105 | // Create missing file 106 | if(! this.propertyFile.exists()) { 107 | try { 108 | new FileWriter(this.propertyFile).close(); 109 | } catch(IOException e) { 110 | e.printStackTrace(); 111 | 112 | return; 113 | } 114 | 115 | if(! this.propertyFile.exists()) 116 | return; 117 | } 118 | 119 | if(this.properties == null) 120 | this.properties = new Properties(); 121 | 122 | // Set the new values 123 | this.properties.setProperty(PROP_LAST_CHECK, String.valueOf(this.lastCheck)); 124 | this.properties.setProperty(PROP_NEWEST_VERSION_CACHE, this.newestVersionCache.getVersion()); 125 | this.properties.setProperty(PROP_CACHED_DOWNLOAD_URL, this.cachedDownloadUrl.toString()); 126 | this.properties.setProperty(PROP_WHATS_NEW_URL, this.cachedWhatsNewUrl.toString()); 127 | 128 | try { 129 | FileWriter fileWriter = new FileWriter(FILE_PATH); 130 | this.properties.store(fileWriter, "Update Cache File"); 131 | } catch(IOException e) { 132 | e.printStackTrace(); 133 | } 134 | } 135 | 136 | /** 137 | * Shows if the cache is to old 138 | * 139 | * @return - Cache is to Old 140 | */ 141 | private boolean cacheToOld() { 142 | return this.currentTime > this.lastCheck + this.checkAgainAfterSec; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/update/UpdateException.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.update; 2 | 3 | import java.security.PrivilegedActionException; 4 | 5 | /** 6 | * @author Peter Dragicevic 7 | */ 8 | public class UpdateException extends Exception { 9 | private Version currentVersion; 10 | private Version newestVersion = null; 11 | 12 | /** 13 | * Constructs a new exception with {@code null} as its detail message. 14 | * The cause is not initialized, and may subsequently be initialized by a 15 | * call to {@link #initCause}. 16 | * 17 | * @param currentVersion - Current Version 18 | */ 19 | public UpdateException(Version currentVersion) { 20 | super(); 21 | this.setCurrentVersion(currentVersion); 22 | } 23 | 24 | /** 25 | * Constructs a new exception with {@code null} as its detail message. 26 | * The cause is not initialized, and may subsequently be initialized by a 27 | * call to {@link #initCause}. 28 | * 29 | * @param currentVersion - Current Version 30 | * @param newestVersion - Newest Version or null for none 31 | */ 32 | public UpdateException(Version currentVersion, Version newestVersion) { 33 | super(); 34 | this.setCurrentVersion(currentVersion); 35 | this.setNewestVersion(newestVersion); 36 | } 37 | 38 | /** 39 | * Constructs a new exception with the specified detail message. The 40 | * cause is not initialized, and may subsequently be initialized by 41 | * a call to {@link #initCause}. 42 | * 43 | * @param message the detail message. The detail message is saved for 44 | * later retrieval by the {@link #getMessage()} method. 45 | * @param currentVersion - Current Version 46 | */ 47 | public UpdateException(String message, Version currentVersion) { 48 | super(message); 49 | this.setCurrentVersion(currentVersion); 50 | } 51 | 52 | /** 53 | * Constructs a new exception with the specified detail message. The 54 | * cause is not initialized, and may subsequently be initialized by 55 | * a call to {@link #initCause}. 56 | * 57 | * @param message the detail message. The detail message is saved for 58 | * later retrieval by the {@link #getMessage()} method. 59 | * @param currentVersion - Current Version 60 | * @param newestVersion - Newest Version or null for none 61 | */ 62 | public UpdateException(String message, Version currentVersion, Version newestVersion) { 63 | super(message); 64 | this.setCurrentVersion(currentVersion); 65 | this.setNewestVersion(newestVersion); 66 | } 67 | 68 | /** 69 | * Constructs a new exception with the specified detail message and 70 | * cause.

Note that the detail message associated with 71 | * {@code cause} is not automatically incorporated in 72 | * this exception's detail message. 73 | * 74 | * @param message the detail message (which is saved for later retrieval 75 | * by the {@link #getMessage()} method). 76 | * @param currentVersion - Current Version 77 | * @param cause the cause (which is saved for later retrieval by the 78 | * {@link #getCause()} method). (A null value is 79 | * permitted, and indicates that the cause is nonexistent or 80 | * unknown.) 81 | */ 82 | public UpdateException(String message, Version currentVersion, Throwable cause) { 83 | super(message, cause); 84 | this.setCurrentVersion(currentVersion); 85 | } 86 | 87 | /** 88 | * Constructs a new exception with the specified detail message and 89 | * cause.

Note that the detail message associated with 90 | * {@code cause} is not automatically incorporated in 91 | * this exception's detail message. 92 | * 93 | * @param message the detail message (which is saved for later retrieval 94 | * by the {@link #getMessage()} method). 95 | * @param currentVersion - Current Version 96 | * @param newestVersion - Newest Version or null for none 97 | * @param cause the cause (which is saved for later retrieval by the 98 | * {@link #getCause()} method). (A null value is 99 | * permitted, and indicates that the cause is nonexistent or 100 | * unknown.) 101 | */ 102 | public UpdateException(String message, Version currentVersion, Version newestVersion, Throwable cause) { 103 | super(message, cause); 104 | this.setCurrentVersion(currentVersion); 105 | this.setNewestVersion(newestVersion); 106 | } 107 | 108 | /** 109 | * Constructs a new exception with the specified cause and a detail 110 | * message of (cause==null ? null : cause.toString()) (which 111 | * typically contains the class and detail message of cause). 112 | * This constructor is useful for exceptions that are little more than 113 | * wrappers for other throwables (for example, {@link 114 | * PrivilegedActionException}). 115 | * 116 | * @param currentVersion - Current Version 117 | * @param cause the cause (which is saved for later retrieval by the 118 | * {@link #getCause()} method). (A null value is 119 | * permitted, and indicates that the cause is nonexistent or 120 | * unknown.) 121 | */ 122 | public UpdateException(Version currentVersion, Throwable cause) { 123 | super(cause); 124 | this.setCurrentVersion(currentVersion); 125 | } 126 | 127 | /** 128 | * Constructs a new exception with the specified cause and a detail 129 | * message of (cause==null ? null : cause.toString()) (which 130 | * typically contains the class and detail message of cause). 131 | * This constructor is useful for exceptions that are little more than 132 | * wrappers for other throwables (for example, {@link 133 | * PrivilegedActionException}). 134 | * 135 | * @param currentVersion - Current Version 136 | * @param newestVersion - Newest Version or null for none 137 | * @param cause the cause (which is saved for later retrieval by the 138 | * {@link #getCause()} method). (A null value is 139 | * permitted, and indicates that the cause is nonexistent or 140 | * unknown.) 141 | */ 142 | public UpdateException(Version currentVersion, Version newestVersion, Throwable cause) { 143 | super(cause); 144 | this.setCurrentVersion(currentVersion); 145 | this.setNewestVersion(newestVersion); 146 | } 147 | 148 | /** 149 | * Constructs a new exception with the specified detail message, 150 | * cause, suppression enabled or disabled, and writable stack 151 | * trace enabled or disabled. 152 | * 153 | * @param message the detail message. 154 | * @param currentVersion - Current Version 155 | * @param cause the cause. (A {@code null} value is permitted, 156 | * and indicates that the cause is nonexistent or unknown.) 157 | * @param enableSuppression whether or not suppression is enabled 158 | * or disabled 159 | * @param writableStackTrace whether or not the stack trace should 160 | * be writable 161 | */ 162 | protected UpdateException(String message, Version currentVersion, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 163 | super(message, cause, enableSuppression, writableStackTrace); 164 | this.setCurrentVersion(currentVersion); 165 | } 166 | 167 | /** 168 | * Constructs a new exception with the specified detail message, 169 | * cause, suppression enabled or disabled, and writable stack 170 | * trace enabled or disabled. 171 | * 172 | * @param message the detail message. 173 | * @param currentVersion - Current Version 174 | * @param newestVersion - Newest Version or null for none 175 | * @param cause the cause. (A {@code null} value is permitted, 176 | * and indicates that the cause is nonexistent or unknown.) 177 | * @param enableSuppression whether or not suppression is enabled 178 | * or disabled 179 | * @param writableStackTrace whether or not the stack trace should 180 | * be writable 181 | */ 182 | protected UpdateException(String message, Version currentVersion, Version newestVersion, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 183 | super(message, cause, enableSuppression, writableStackTrace); 184 | this.setCurrentVersion(currentVersion); 185 | this.setNewestVersion(newestVersion); 186 | } 187 | 188 | /** 189 | * Get the current Version 190 | * 191 | * @return - Current Version 192 | */ 193 | public Version getCurrentVersion() { 194 | return currentVersion; 195 | } 196 | 197 | /** 198 | * Get the current Version as String 199 | * 200 | * @return - Current Version as String 201 | */ 202 | public String getCurrentVersionAsString() { 203 | return currentVersion.getVersion(); 204 | } 205 | 206 | /** 207 | * Set the current Version 208 | * 209 | * @param currentVersion - Current Version 210 | */ 211 | private void setCurrentVersion(Version currentVersion) { 212 | this.currentVersion = currentVersion; 213 | } 214 | 215 | /** 216 | * Get the newest Version 217 | * 218 | * @return - Newest Version or null 219 | */ 220 | public Version getNewestVersion() { 221 | return newestVersion; 222 | } 223 | 224 | /** 225 | * Get the newest Version as String 226 | * 227 | * @return - Newest Version as String 228 | */ 229 | public String getNewestVersionAsString() { 230 | if(this.newestVersion == null) 231 | return ""; 232 | 233 | return newestVersion.getVersion(); 234 | } 235 | 236 | /** 237 | * Set the newest Version 238 | * 239 | * @param newestVersion - Newest Version or null 240 | */ 241 | private void setNewestVersion(Version newestVersion) { 242 | this.newestVersion = newestVersion; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/lib/update/Version.java: -------------------------------------------------------------------------------- 1 | package org.petschko.lib.update; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class Version { 7 | private String version; 8 | 9 | /** 10 | * Version constructor 11 | * 12 | * @param version - Version 13 | */ 14 | public Version(String version) { 15 | this.version = version; 16 | } 17 | 18 | /** 19 | * Get the Version 20 | * 21 | * @return - Version 22 | */ 23 | public String getVersion() { 24 | return version; 25 | } 26 | 27 | /** 28 | * Compares 2 Versions 29 | * 30 | * @param version - Version to compare 31 | * @return - Versions are equal 32 | */ 33 | public boolean versionsEqual(Version version) { 34 | return this.version.equals(version.getVersion()); 35 | } 36 | 37 | /** 38 | * Checks if this Version is lower than the other Version 39 | * 40 | * @param version - Version to compare 41 | * @return - This Version is lower than the other 42 | */ 43 | public boolean thisIsLowerThan(Version version) { 44 | String[] thisVersion = this.version.split("\\."); 45 | String[] otherVersion = version.version.split("\\."); 46 | 47 | // Ensure same length arrays 48 | if(thisVersion.length > otherVersion.length) { 49 | String[] tmp = new String[thisVersion.length]; 50 | 51 | for(int i = 0; i < tmp.length; i++) { 52 | if(i < otherVersion.length) 53 | tmp[i] = otherVersion[i]; 54 | else 55 | tmp[i] = "0"; 56 | } 57 | 58 | otherVersion = tmp; 59 | } else if(otherVersion.length > thisVersion.length) { 60 | String[] tmp = new String[otherVersion.length]; 61 | 62 | for(int i = 0; i < tmp.length; i++) { 63 | if(i < thisVersion.length) 64 | tmp[i] = thisVersion[i]; 65 | else 66 | tmp[i] = "0"; 67 | } 68 | 69 | thisVersion = tmp; 70 | } 71 | 72 | // Compare Versions 73 | for(int n = 0; n < thisVersion.length; n++) { 74 | int thisNumber = Integer.parseInt(thisVersion[n]); 75 | int otherNumber = Integer.parseInt(otherVersion[n]); 76 | 77 | if(thisNumber < otherNumber) 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/App.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.lib.File; 5 | import org.petschko.lib.gui.notification.ErrorWindow; 6 | import org.petschko.rpgmakermv.decrypt.cmd.CMD; 7 | import org.petschko.rpgmakermv.decrypt.gui.GUI; 8 | 9 | import java.io.IOException; 10 | import java.util.jar.Attributes; 11 | import java.util.jar.Manifest; 12 | 13 | /** 14 | * @author Peter Dragicevic 15 | */ 16 | public class App { 17 | private static Boolean useGUI = true; 18 | private static GUI gui; 19 | private static CMD cmd; 20 | public static String outputDir; 21 | public static Preferences preferences; 22 | 23 | /** 24 | * Main-Class 25 | * 26 | * @param args - Optional Arguments from Command-Line 27 | */ 28 | public static void main(String[] args) { 29 | // Dynamically read the Versions number into the CFG 30 | Config.setVersion(readMfVersion()); 31 | 32 | // Ensure System output dir always exists 33 | if(! File.existsDir(Config.DEFAULT_OUTPUT_DIR)) 34 | File.createDirectory(Config.DEFAULT_OUTPUT_DIR); 35 | 36 | // Check whats given from CMD 37 | if(args.length > 0) { 38 | useGUI = false; 39 | cmd = new CMD(args); 40 | } 41 | 42 | if(useGUI) { 43 | // Show something when its started via .bat or shell file 44 | System.out.println(Config.PROGRAM_NAME + " - " + Config.VERSION + " by " + Const.CREATOR); 45 | 46 | // Use GUI 47 | preferences = new Preferences(Config.PREFERENCES_FILE); 48 | outputDir = App.preferences.getConfig(Preferences.LAST_OUTPUT_DIR, Config.DEFAULT_OUTPUT_DIR); 49 | gui = new GUI(); 50 | } else { 51 | // Use Command-Line Version 52 | cmd.runCMD(); 53 | } 54 | } 55 | 56 | /** 57 | * Shows the given message if no GUI is enabled 58 | * 59 | * @param msg - Message to display 60 | * @param messageStatus - Status of the Message 61 | */ 62 | public static void showMessage(String msg, int messageStatus) { 63 | String status; 64 | 65 | switch(messageStatus) { 66 | case CMD.STATUS_ERROR: 67 | status = "[ERROR]: "; 68 | break; 69 | case CMD.STATUS_WARNING: 70 | status = "[WARN]: "; 71 | break; 72 | case CMD.STATUS_OK: 73 | status = "[SUCCESS]: "; 74 | break; 75 | default: 76 | status = "[INFO]: "; 77 | } 78 | 79 | if(! App.useGUI) 80 | System.out.println(status + msg); 81 | } 82 | 83 | /** 84 | * Shows the given message if no GUI is enabled 85 | * 86 | * @param msg - Message to display 87 | */ 88 | public static void showMessage(String msg) { 89 | showMessage(msg, CMD.STATUS_INFO); 90 | } 91 | 92 | /** 93 | * Saves the settings, close the GUI and quit the Program 94 | */ 95 | public static void closeGUI() { 96 | if(! App.preferences.save()) { 97 | ErrorWindow errorWindow = new ErrorWindow("Can't save Settings...", ErrorWindow.ERROR_LEVEL_ERROR, false); 98 | errorWindow.show(); 99 | } 100 | 101 | App.gui.dispose(); 102 | System.exit(0); 103 | } 104 | 105 | /** 106 | * Returns the Version-Number from the Manifest-File 107 | * 108 | * @return - Version number from the Manifest File or null for debug 109 | */ 110 | public static String readMfVersion() { 111 | Manifest mf = new Manifest(); 112 | try { 113 | mf.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/MANIFEST.MF")); 114 | } catch (IOException e) { 115 | throw new RuntimeException(e); 116 | } 117 | 118 | Attributes attributes = mf.getMainAttributes(); 119 | return attributes.getValue("Version"); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/Config.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | public class Config { 7 | // Program Info 8 | public static String VERSION_NUMBER; 9 | public static String VERSION = "v%s Alpha"; 10 | public static final String PROGRAM_NAME = "RPG-Maker MV/MZ Decrypter"; 11 | public static final String PROJECT_PAGE_URL = "https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter"; 12 | public static final String PROJECT_BUG_REPORT_URL = "https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter/-/issues"; 13 | public static final String PROJECT_LICENCE_URL = "https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter/-/blob/master/LICENCE"; 14 | public static final String AUTHOR_IMAGE = "/icons/petschko_icon.png"; 15 | public static final String UPDATE_URL = "https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter/-/raw/master/version.txt?ref_type=heads"; 16 | 17 | // File-Path-Settings 18 | public static final String DEFAULT_OUTPUT_DIR = "output"; 19 | public static final String PREFERENCES_FILE = "config.pref"; 20 | 21 | // Misc Settings 22 | public static boolean UPDATE_CHECK = true; 23 | public static final long UPDATE_CHECK_EVERY_SECS = 172800; 24 | public static final String THIS_JAR_FILE_NAME = "RPG Maker MV Decrypter.jar"; 25 | 26 | /** 27 | * Constructor 28 | */ 29 | private Config() { 30 | // VOID - This is a Static-Class 31 | } 32 | 33 | /** 34 | * Set the Version-Number to the Config 35 | * 36 | * @param version - Versions Number-String or NULL 37 | */ 38 | public static void setVersion(String version) { 39 | VERSION_NUMBER = version; 40 | VERSION = String.format(VERSION, VERSION_NUMBER == null ? "NULL" : VERSION_NUMBER); 41 | 42 | if(VERSION_NUMBER == null) 43 | UPDATE_CHECK = false; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/Finder.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.lib.File; 5 | 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * @author Peter Dragicevic 10 | */ 11 | class Finder { 12 | /** 13 | * Constructor 14 | */ 15 | private Finder() { 16 | // VOID - This is a Static-Class 17 | } 18 | 19 | /** 20 | * Search all know places for the System-File 21 | * 22 | * @param projectDir - Directory of the Project 23 | * @return - System-File-Object if found else null 24 | */ 25 | static File findSystemFile(String projectDir) { 26 | String[] filePaths = new String[] { 27 | "data" + Const.DS + "System.json", 28 | "www" + Const.DS + "data" + Const.DS + "System.json" 29 | }; 30 | 31 | return findFromArray(filePaths, projectDir); 32 | } 33 | 34 | /** 35 | * Finds the Project-File 36 | * 37 | * @param projectDir - Directory were to search 38 | * @return - Project File or null if not found 39 | */ 40 | static File findProjectFile(String projectDir) { 41 | String[] potentialPaths = new String[] { 42 | "Game.rpgproject", 43 | "game.rmmzproject" 44 | }; 45 | 46 | return findFromArray(potentialPaths, projectDir); 47 | } 48 | 49 | /** 50 | * Check if Encryption-Key name is may different from given - Tests all know Encryption-Key Names 51 | * 52 | * @param systemFile - System.json File 53 | * @return - Key-Name or null if not found 54 | */ 55 | static String testEncryptionKeyNames(File systemFile) { 56 | String[] keyNames = new String[]{"encryptionKey"}; 57 | Decrypter d = new Decrypter(); 58 | String result = null; 59 | 60 | for(String keyName : keyNames) { 61 | try { 62 | d.detectEncryptionKeyFromJson(systemFile, keyName); 63 | 64 | if(d.getDecryptCode() != null) { 65 | result = keyName; 66 | break; 67 | } 68 | } catch(Exception e) { 69 | // Void 70 | } 71 | } 72 | 73 | return result; 74 | } 75 | 76 | /** 77 | * Checks if there is a RPG-Maker file within the Directory 78 | * 79 | * @param dir - Path to the Directory 80 | * @return - true if a File was found else false 81 | */ 82 | static boolean verifyRPGDir(String dir) { 83 | if(dir == null) { 84 | Exception e = new Exception("Dir can't be null!"); 85 | e.printStackTrace(); 86 | return false; 87 | } 88 | 89 | ArrayList mainDirFiles = File.readDirFiles(new java.io.File(dir), false); 90 | String[] rpgGameCommonFiles = new String[] { 91 | "Game.exe", // Mostly with an other name... 92 | "Game.rpgproject", // Mostly not in the Directory 93 | "d3dcompiler_47.dll", 94 | "ffmpegsumo.dll", 95 | "icudtl.dat", 96 | "libEGL.dll", 97 | "libGLESv2.dll", 98 | "nw.pak", 99 | "package.json", 100 | "pdf.dll", 101 | "resources.pak" 102 | }; 103 | 104 | // Check if a File is in there 105 | for(java.io.File currentFile : mainDirFiles) { 106 | for(String rpgFile : rpgGameCommonFiles) { 107 | if(rpgFile.equals(currentFile.getName())) 108 | return true; 109 | else if(rpgFile.toLowerCase().equals(currentFile.getName().toLowerCase())) 110 | return true; 111 | } 112 | } 113 | 114 | return false; 115 | } 116 | 117 | /** 118 | * Finds a File from the given Array 119 | * 120 | * @param filePathArray - The array with potential hits 121 | * @param mainPath - Main path which is added in front of all files (aka search in this dir) 122 | * @return - Target File or null if not found 123 | */ 124 | private static File findFromArray(String[] filePathArray, String mainPath) { 125 | File targetFile = null; 126 | 127 | for(String filePath : filePathArray) { 128 | java.io.File fileIo = new java.io.File(mainPath + filePath); 129 | 130 | if(fileIo.exists() && ! fileIo.isDirectory()) { 131 | try { 132 | targetFile = new File(mainPath + filePath); 133 | } catch(Exception e) { 134 | e.printStackTrace(); 135 | } 136 | 137 | return targetFile; 138 | } 139 | } 140 | 141 | return null; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/Preferences.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt; 2 | 3 | import org.petschko.lib.UserPref; 4 | 5 | import java.util.Properties; 6 | 7 | /** 8 | * @author Peter Dragicevic 9 | */ 10 | public class Preferences extends UserPref { 11 | public static final String IGNORE_FAKE_HEADER = "ignoreFakeHeader"; 12 | public static final String LOAD_INVALID_RPG_DIRS = "loadInvalidRPGDirs"; 13 | public static final String OVERWRITE_FILES = "overwriteFiles"; 14 | public static final String CLEAR_OUTPUT_DIR_BEFORE_DECRYPT = "clearOutputDirBeforeDecrypt"; 15 | public static final String LAST_OUTPUT_DIR = "lastOutputDir"; 16 | public static final String LAST_OUTPUT_PARENT_DIR = "lastOutputParentDir"; 17 | public static final String LAST_RPG_DIR = "lastRPGParentDir"; 18 | public static final String DECRYPTER_VERSION = "decrypterVersion"; 19 | public static final String DECRYPTER_REMAIN = "decrypterRemain"; 20 | public static final String DECRYPTER_SIGNATURE = "decrypterSignature"; 21 | public static final String DECRYPTER_HEADER_LEN = "decrypterHeaderLen"; 22 | public static final String AUTO_CHECK_FOR_UPDATES = "autoCheckForUpdates"; 23 | 24 | /** 25 | * UserPrefs Constructor 26 | * 27 | * @param filePath - File-Path to UserPref-File 28 | */ 29 | public Preferences(String filePath) { 30 | super(filePath); 31 | } 32 | 33 | /** 34 | * Load the default-values for Preferences 35 | * 36 | * @return - true on success else false 37 | */ 38 | @Override 39 | public boolean loadDefaults() { 40 | Properties p = new Properties(); 41 | 42 | p.setProperty(Preferences.IGNORE_FAKE_HEADER, "true"); 43 | p.setProperty(Preferences.OVERWRITE_FILES, "false"); 44 | p.setProperty(Preferences.LOAD_INVALID_RPG_DIRS, "false"); 45 | p.setProperty(Preferences.CLEAR_OUTPUT_DIR_BEFORE_DECRYPT, "false"); 46 | p.setProperty(Preferences.LAST_OUTPUT_DIR, Config.DEFAULT_OUTPUT_DIR); 47 | p.setProperty(Preferences.LAST_OUTPUT_PARENT_DIR, "."); 48 | p.setProperty(Preferences.LAST_RPG_DIR, "."); 49 | p.setProperty(Preferences.DECRYPTER_VERSION, Decrypter.DEFAULT_VERSION); 50 | p.setProperty(Preferences.DECRYPTER_REMAIN, Decrypter.DEFAULT_REMAIN); 51 | p.setProperty(Preferences.DECRYPTER_SIGNATURE, Decrypter.DEFAULT_SIGNATURE); 52 | p.setProperty(Preferences.DECRYPTER_HEADER_LEN, Integer.toString(Decrypter.DEFAULT_HEADER_LEN)); 53 | p.setProperty(Preferences.AUTO_CHECK_FOR_UPDATES, "true"); 54 | 55 | this.setProperties(p); 56 | 57 | return true; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/CMD.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.rpgmakermv.decrypt.App; 5 | import org.petschko.rpgmakermv.decrypt.Config; 6 | 7 | /** 8 | * @author Peter Dragicevic 9 | */ 10 | public class CMD { 11 | public static final int STATUS_OK = 0; 12 | public static final int STATUS_INFO = 2; 13 | public static final int STATUS_WARNING = 1; 14 | public static final int STATUS_ERROR = -1; 15 | public static final String HELP_INDENT = " "; 16 | public static final String LINE_CMD = "------------------------------------------------------------------------------"; 17 | private static final String CMD_HELP = "help"; 18 | private static final String CMD_HELP_2 = "-help"; 19 | private static final String CMD_HELP_3 = "--help"; 20 | private static final String CMD_HELP_4 = "/?"; 21 | private static final String CMD_OPEN_IMG = "open"; 22 | private static final String CMD_DECRYPT = "decrypt"; 23 | private static final String CMD_ENCRYPT = "encrypt"; 24 | private static final String CMD_RESTORE = "restore"; 25 | private static final String CMD_RESTORE_PROJECT = "restoreproject"; 26 | private static final String CMD_GET_KEY = "key"; 27 | private static final String CMD_GET_KEY_2 = "detect"; 28 | private static final String CMD_GET_KEY_3 = "getkey"; 29 | private static final String CMD_GET_KEY_4 = "detectkey"; 30 | private static final String CMD_GET_KEY_5 = "keydetect"; 31 | private static final String UPDATE = "update"; 32 | 33 | private final String[] args; 34 | 35 | /** 36 | * CMD Constructor 37 | * 38 | * @param args - CMD Args 39 | */ 40 | public CMD(String[] args) { 41 | this.args = args; 42 | } 43 | 44 | /** 45 | * Runs the Command 46 | */ 47 | public void runCMD() { 48 | // Show Welcome-Message 49 | System.out.println(LINE_CMD); 50 | System.out.println(Config.PROGRAM_NAME + " - " + Config.VERSION + " by " + Const.CREATOR + " | Command-Line Version"); 51 | System.out.println(LINE_CMD); 52 | 53 | if(Config.UPDATE_CHECK) 54 | Update.checkForUpdates(); 55 | 56 | sanitizeArgs(); 57 | processArgs(); 58 | 59 | exitCMD(0); 60 | } 61 | 62 | /** 63 | * Sanitize the first args 64 | */ 65 | private void sanitizeArgs() { 66 | args[0] = args[0].toLowerCase().trim(); 67 | args[0] = args[0].replaceAll("-", ""); 68 | args[0] = args[0].replaceAll("/", ""); 69 | 70 | if(args.length >= 2) { 71 | // Lowercase everything for help & update 72 | if(isHelpCmd(args[0].toLowerCase().trim()) || isHelpCmd(args[1].toLowerCase().trim()) || args[0].toLowerCase().equals(UPDATE)) 73 | args[1] = args[1].toLowerCase().trim(); 74 | } 75 | } 76 | 77 | /** 78 | * Process Command-Line Arguments 79 | */ 80 | private void processArgs() { 81 | // Get the Sub command 82 | String subCommand; 83 | I_CMD cmdHandler; 84 | try { 85 | subCommand = args[1].toLowerCase(); 86 | } catch(ArrayIndexOutOfBoundsException arEx) { 87 | subCommand = null; 88 | } 89 | 90 | 91 | switch(args[0]) { 92 | case CMD_OPEN_IMG: 93 | cmdHandler = new Open(); 94 | break; 95 | case CMD_DECRYPT: 96 | cmdHandler = new Decrypt(); 97 | break; 98 | case CMD_ENCRYPT: 99 | cmdHandler = new Encrypt(); 100 | break; 101 | case CMD_RESTORE: 102 | cmdHandler = new Restore(); 103 | break; 104 | case CMD_RESTORE_PROJECT: 105 | cmdHandler = new RestoreProject(); 106 | break; 107 | case CMD_GET_KEY: 108 | case CMD_GET_KEY_2: 109 | case CMD_GET_KEY_3: 110 | case CMD_GET_KEY_4: 111 | case CMD_GET_KEY_5: 112 | cmdHandler = new DetectKey(); 113 | break; 114 | case UPDATE: 115 | cmdHandler = new Update(); 116 | break; 117 | default: 118 | boolean invalidCommand = false; 119 | if(! isHelpCmd(args[0])) 120 | invalidCommand = true; 121 | 122 | cmdHandler = new Help(); 123 | 124 | // Help is handles a bit different 125 | if(invalidCommand) 126 | cmdHandler.run(args); 127 | else { 128 | // Check if 2nd param is command so make this an alias too 129 | if(subCommand != null) { 130 | printHelpForCmd(subCommand); 131 | } else 132 | cmdHandler.printHelp(); 133 | } 134 | 135 | exitCMD(invalidCommand ? STATUS_WARNING : STATUS_OK); 136 | return; 137 | } 138 | 139 | if(isHelpCmd(subCommand)) 140 | cmdHandler.printHelp(); 141 | else 142 | cmdHandler.run(args); 143 | } 144 | 145 | /** 146 | * Shows if the current command is a help command 147 | * 148 | * @return - Is the command a help command 149 | */ 150 | private boolean isHelpCmd(String command) { 151 | if(command == null) 152 | return false; 153 | 154 | return command.equals(CMD_HELP) || command.equals(CMD_HELP_2) || command.equals(CMD_HELP_3) || command.equals(CMD_HELP_4); 155 | } 156 | 157 | /** 158 | * Prints out the help for a specific command 159 | * 160 | * @param command - Command to print help of 161 | */ 162 | private void printHelpForCmd(String command) { 163 | I_CMD cmdCommand = new Help(); 164 | 165 | switch(command) { 166 | case CMD_OPEN_IMG: 167 | cmdCommand = new Open(); 168 | break; 169 | case CMD_DECRYPT: 170 | cmdCommand = new Decrypt(); 171 | break; 172 | case CMD_ENCRYPT: 173 | cmdCommand = new Encrypt(); 174 | break; 175 | case CMD_RESTORE: 176 | cmdCommand = new Restore(); 177 | break; 178 | case CMD_RESTORE_PROJECT: 179 | cmdCommand = new RestoreProject(); 180 | break; 181 | case CMD_GET_KEY: 182 | case CMD_GET_KEY_2: 183 | case CMD_GET_KEY_3: 184 | case CMD_GET_KEY_4: 185 | case CMD_GET_KEY_5: 186 | cmdCommand = new DetectKey(); 187 | break; 188 | default: 189 | // Void 190 | } 191 | 192 | cmdCommand.printHelp(); 193 | } 194 | 195 | /** 196 | * Exit the Program with a Message 197 | * 198 | * @param status - Exit-Status-Code 199 | */ 200 | static void exitCMD(int status) { 201 | App.showMessage("Done."); 202 | System.exit(status); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Decrypt.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | import org.petschko.rpgmakermv.decrypt.Decrypter; 6 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 7 | 8 | /** 9 | * @author Peter Dragicevic 10 | */ 11 | class Decrypt implements I_CMD { 12 | private String pathToProject; 13 | private String outputDir; 14 | 15 | // Decrypter options 16 | private String key = null; 17 | private boolean verifyDir = false; 18 | private boolean ignoreFakeHeader = true; 19 | private int headerLen = Decrypter.DEFAULT_HEADER_LEN; 20 | private String signature = Decrypter.DEFAULT_SIGNATURE; 21 | private String version = Decrypter.DEFAULT_VERSION; 22 | private String remain = Decrypter.DEFAULT_REMAIN; 23 | 24 | /** 25 | * Runs the Command 26 | * 27 | * @param args - Command-Line commands 28 | */ 29 | @Override 30 | public void run(String[] args) { 31 | if(args.length < 2) { 32 | App.showMessage("To less arguments, see help", CMD.STATUS_WARNING); 33 | App.showMessage(""); 34 | this.printHelp(); 35 | CMD.exitCMD(CMD.STATUS_WARNING); 36 | return; 37 | } 38 | 39 | // Set Path to Project 40 | pathToProject = args[1]; 41 | App.showMessage("Set Project-Dir to: \"" + pathToProject + "\""); 42 | 43 | // Set Output-Dir 44 | try { 45 | outputDir = args[2]; 46 | } catch(ArrayIndexOutOfBoundsException arEx) { 47 | outputDir = Config.DEFAULT_OUTPUT_DIR; 48 | } 49 | 50 | App.showMessage("Set Output-Dir to: \"" + outputDir + "\""); 51 | 52 | if(args.length >= 4) 53 | verifyDir = Boolean.parseBoolean(args[3]); 54 | if(args.length >= 5) 55 | ignoreFakeHeader = Boolean.parseBoolean(args[4]); 56 | if(args.length >= 6) { 57 | if(! args[5].equalsIgnoreCase("auto")) { 58 | key = args[5].toLowerCase(); 59 | } 60 | } 61 | if(args.length >= 7) { 62 | headerLen = Integer.parseInt(args[6]); 63 | 64 | // Ensure headerLen is at least 1 else default 65 | if(headerLen < 1) 66 | headerLen = Decrypter.DEFAULT_HEADER_LEN; 67 | } 68 | if(args.length >= 8) 69 | signature = args[7].trim().toLowerCase(); 70 | if(args.length >= 9) 71 | version = args[8].trim().toLowerCase(); 72 | if(args.length >= 10) 73 | remain = args[9].trim().toLowerCase(); 74 | 75 | handleFiles(); 76 | } 77 | 78 | /** 79 | * Handles Files to decrypt 80 | */ 81 | private void handleFiles() { 82 | try { 83 | RPG_Project rpgProject = new RPG_Project(pathToProject, verifyDir); 84 | Decrypter decrypter; 85 | 86 | if(key == null) 87 | decrypter = new Decrypter(); 88 | else 89 | decrypter = new Decrypter(key); 90 | 91 | rpgProject.setOutputPath(outputDir); 92 | decrypter.setIgnoreFakeHeader(ignoreFakeHeader); 93 | decrypter.setHeaderLen(headerLen); 94 | decrypter.setSignature(signature); 95 | decrypter.setVersion(version); 96 | decrypter.setRemain(remain); 97 | rpgProject.decryptFilesCmd(decrypter); 98 | } catch(Exception e) { 99 | e.printStackTrace(); 100 | CMD.exitCMD(CMD.STATUS_ERROR); 101 | } 102 | } 103 | 104 | /** 105 | * Prints help for the command 106 | */ 107 | @Override 108 | public void printHelp() { 109 | App.showMessage("Decrypt Files"); 110 | App.showMessage(""); 111 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" decrypt [path to decrypt project] [(optional) output path] [(optional) verifyRpgDir - false|true] [(optional) ignoreFakeHeader - true|false] [(optional) key - auto|keyValue] [(optional) headerLen] [(optional) hsignature] [(optional) hversion] [(optional) hremain]"); 112 | App.showMessage(""); 113 | App.showMessage(CMD.HELP_INDENT + "Params: (Separate each param by a space, for paths use \"\" around the path)"); 114 | App.showMessage(CMD.HELP_INDENT + " [path to decrypt project] - Path to the RPG-MV/MZ Project you want to decrypt"); 115 | App.showMessage(CMD.HELP_INDENT + " (optional) [output path] - Path where the decrypted files go"); 116 | App.showMessage(CMD.HELP_INDENT + " Default: \"output\" (out dir in program dir)"); 117 | App.showMessage(CMD.HELP_INDENT + " (optional) [verifyRpgDir (false|true)]"); 118 | App.showMessage(CMD.HELP_INDENT + " - Verifies if its a RPG-MV/MZ dir | Default: false"); 119 | App.showMessage(CMD.HELP_INDENT + " (optional) [ignoreFakeHeader (true|false)] - Ignored the Files MV/MZ-Header | Default: true"); 120 | App.showMessage(CMD.HELP_INDENT + " (optional) [key (auto|keyValue)] - Decryption key or auto detection | Default: auto"); 121 | App.showMessage(""); 122 | App.showMessage(CMD.HELP_INDENT + "Header-Values: (usually REALLY not needed)"); 123 | App.showMessage(CMD.HELP_INDENT + " (very optional) [headerLen] - Byte length of the Header | Default: " + this.headerLen); 124 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hsignature] - Signature of the Header | Default: " + this.signature); 125 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hversion] - Version of the Header | Default: " + this.version); 126 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hremain] - Remain of the Header | Default: " + this.remain); 127 | App.showMessage(""); 128 | App.showMessage(CMD.HELP_INDENT + "Examples of full commands with all params:"); 129 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" decrypt \"C:\\my rpg mv game\\\" \"output\" false true auto"); 130 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" decrypt \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true false d41d8cd98f00b204e9800998ecf8427e"); 131 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" decrypt \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true false d41d8cd98f00b204e9800998ecf8427e 14 5250474d56000000 000301 00000000"); 132 | App.showMessage(""); 133 | App.showMessage(CMD.HELP_INDENT + "- The first command extracts all files inside this programs output dir, dont check if its a RPG-MV/MZ dir,"); 134 | App.showMessage(CMD.HELP_INDENT + " ignored if the header of the files is the RPG-MV/MZ header and auto-detects the key"); 135 | App.showMessage(CMD.HELP_INDENT + "- The second command extract all files inside the game directory, checks if RPG-MV/MZ dir and Header is"); 136 | App.showMessage(CMD.HELP_INDENT + " valid with the key d41d8cd98f00b204e9800998ecf8427e"); 137 | App.showMessage(CMD.HELP_INDENT + "- The third command does the same as the 2nd, just shows how you can modify the values of the header"); 138 | App.showMessage(""); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/DetectKey.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | import org.petschko.rpgmakermv.decrypt.Decrypter; 6 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.InputStreamReader; 10 | 11 | /** 12 | * @author Peter Dragicevic 13 | */ 14 | class DetectKey implements I_CMD { 15 | private String pathToProject; 16 | private boolean skipImageQuestion = false; 17 | 18 | // Decoder options 19 | private int headerLen = Decrypter.DEFAULT_HEADER_LEN; 20 | 21 | /** 22 | * Runs the Command 23 | * 24 | * @param args - Command-Line commands 25 | */ 26 | @Override 27 | public void run(String[] args) { 28 | if(args.length < 2) { 29 | App.showMessage("To less arguments, see help", CMD.STATUS_WARNING); 30 | App.showMessage(""); 31 | this.printHelp(); 32 | CMD.exitCMD(CMD.STATUS_WARNING); 33 | return; 34 | } 35 | 36 | // Set Path to Project 37 | pathToProject = args[1]; 38 | App.showMessage("Set Project-Dir to: \"" + pathToProject + "\""); 39 | 40 | if(args.length >= 3) 41 | skipImageQuestion = Boolean.parseBoolean(args[2]); 42 | if(args.length >= 4) { 43 | headerLen = Integer.parseInt(args[3]); 44 | 45 | // Ensure headerLen is at least 1 else default 46 | if(headerLen < 1) 47 | headerLen = Decrypter.DEFAULT_HEADER_LEN; 48 | } 49 | 50 | detectsKey(); 51 | } 52 | 53 | /** 54 | * Detects the Key 55 | */ 56 | private void detectsKey() { 57 | try { 58 | RPG_Project rpgProject = new RPG_Project(pathToProject, false); 59 | Decrypter decrypter = new Decrypter(); 60 | decrypter.setHeaderLen(headerLen); 61 | 62 | // Ensure we may have an encrypted image 63 | rpgProject.findEncryptedImg(); 64 | 65 | // Try the detection from JSON-File if found 66 | if(rpgProject.getSystem() != null) { 67 | decrypter.detectEncryptionKeyFromJson(rpgProject.getSystem(), rpgProject.getEncryptionKeyName()); 68 | 69 | if(decrypter.getDecryptCode() != null) { 70 | showKey(decrypter.getDecryptCode()); 71 | return; 72 | } 73 | } 74 | 75 | // Try the detection from image but ask before 76 | if(rpgProject.getEncryptedImgFile() != null) { 77 | boolean doImgSearch = true; 78 | if(! skipImageQuestion) { 79 | BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 80 | App.showMessage(""); 81 | App.showMessage("Key not found so far (System.json)... Should I generate the Key from encrypted images?"); 82 | App.showMessage("WARNING: Key from images may not work. Continue? (Y/n)"); 83 | String s = reader.readLine().toLowerCase(); 84 | 85 | if(! (s.equals("") || s.equals("y") || s.equals("yes") || s.equals("true") || s.equals("1"))) 86 | doImgSearch = false; 87 | 88 | App.showMessage("Ok!"); 89 | } 90 | 91 | if(doImgSearch) { 92 | App.showMessage("Searches for Key in Image..."); 93 | decrypter.detectEncryptionKeyFromImage(rpgProject.getEncryptedImgFile()); 94 | } else 95 | App.showMessage("Skips searching for Key in Image..."); 96 | 97 | if(decrypter.getDecryptCode() != null) { 98 | showKey(decrypter.getDecryptCode()); 99 | return; 100 | } 101 | } 102 | 103 | App.showMessage("Key not found..."); 104 | CMD.exitCMD(CMD.STATUS_OK); 105 | } catch(Exception e) { 106 | e.printStackTrace(); 107 | CMD.exitCMD(CMD.STATUS_ERROR); 108 | } 109 | } 110 | 111 | /** 112 | * Shows the Key 113 | * 114 | * @param key - Key 115 | */ 116 | private void showKey(String key) { 117 | App.showMessage("---------------------------------------------------------", CMD.STATUS_OK); 118 | App.showMessage("> The Key is: " + key, CMD.STATUS_OK); 119 | App.showMessage("---------------------------------------------------------", CMD.STATUS_OK); 120 | CMD.exitCMD(CMD.STATUS_OK); 121 | } 122 | 123 | /** 124 | * Prints help for the command 125 | */ 126 | @Override 127 | public void printHelp() { 128 | App.showMessage("Detects the En-/Decryption-Key"); 129 | App.showMessage(""); 130 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" key [path to project] [(optional) ask before image keysearch (true|false)] [(optional) headerLen]"); 131 | App.showMessage(""); 132 | App.showMessage(CMD.HELP_INDENT + "Params: (Separate each param by a space, for paths use \"\" around the path)"); 133 | App.showMessage(CMD.HELP_INDENT + " [path to project] - Path to the RPG-MV/MZ Project were you want to get the key from"); 134 | App.showMessage(CMD.HELP_INDENT + " (optional) [ask before image keysearch (true|false)] - Ask before search key in images | Default: true"); 135 | App.showMessage(""); 136 | App.showMessage(CMD.HELP_INDENT + "Header-Values: (usually REALLY not needed)"); 137 | App.showMessage(CMD.HELP_INDENT + " (very optional) [headerLen] - Byte length of the Header | Default: " + this.headerLen); 138 | App.showMessage(""); 139 | App.showMessage(CMD.HELP_INDENT + "Examples of the full commands with all params:"); 140 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" key \"C:\\my rpg mv game\\\" true"); 141 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" key \"C:\\my rpg mv game\\\" false"); 142 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" key \"C:\\my rpg mv game\\\" false 14"); 143 | App.showMessage(""); 144 | App.showMessage(CMD.HELP_INDENT + "- The first command returns the key of the Project if found also asks before searching in images"); 145 | App.showMessage(CMD.HELP_INDENT + "- The second command returns the key of the Project if found but skips the image question"); 146 | App.showMessage(CMD.HELP_INDENT + "- The third command does the same as the 2nd, just shows how you can modify the header length"); 147 | App.showMessage(""); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Encrypt.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | import org.petschko.rpgmakermv.decrypt.Decrypter; 6 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 7 | 8 | /** 9 | * @author Peter Dragicevic 10 | */ 11 | class Encrypt implements I_CMD { 12 | private String pathToProject; 13 | private String outputDir; 14 | 15 | // Encrypter options 16 | private boolean toMV = true; 17 | private String key = null; 18 | private int headerLen = Decrypter.DEFAULT_HEADER_LEN; 19 | private String signature = Decrypter.DEFAULT_SIGNATURE; 20 | private String version = Decrypter.DEFAULT_VERSION; 21 | private String remain = Decrypter.DEFAULT_REMAIN; 22 | 23 | /** 24 | * Runs the Command 25 | * 26 | * @param args - Command-Line commands 27 | */ 28 | @Override 29 | public void run(String[] args) { 30 | if(args.length < 2) { 31 | App.showMessage("To less arguments, see help", CMD.STATUS_WARNING); 32 | App.showMessage(""); 33 | this.printHelp(); 34 | CMD.exitCMD(CMD.STATUS_WARNING); 35 | return; 36 | } 37 | 38 | // Set Path to Project 39 | pathToProject = args[1]; 40 | App.showMessage("Set Project-Dir to: \"" + pathToProject + "\""); 41 | 42 | // Set Output-Dir 43 | try { 44 | outputDir = args[2]; 45 | } catch(ArrayIndexOutOfBoundsException arEx) { 46 | outputDir = Config.DEFAULT_OUTPUT_DIR; 47 | } 48 | 49 | App.showMessage("Set Output-Dir to: \"" + outputDir + "\""); 50 | 51 | if(args.length >= 4) 52 | toMV = Boolean.parseBoolean(args[3]); 53 | if(args.length >= 5) { 54 | if(! args[4].toLowerCase().equals("auto")) { 55 | key = args[4].toLowerCase(); 56 | } 57 | } 58 | if(args.length >= 6) { 59 | headerLen = Integer.parseInt(args[5]); 60 | 61 | // Ensure headerLen is at least 1 else default 62 | if(headerLen < 1) 63 | headerLen = Decrypter.DEFAULT_HEADER_LEN; 64 | } 65 | if(args.length >= 7) 66 | signature = args[6].trim().toLowerCase(); 67 | if(args.length >= 8) 68 | version = args[7].trim().toLowerCase(); 69 | if(args.length >= 9) 70 | remain = args[8].trim().toLowerCase(); 71 | 72 | handleFiles(); 73 | } 74 | 75 | /** 76 | * Handles Files to encrypt 77 | */ 78 | private void handleFiles() { 79 | try { 80 | RPG_Project rpgProject = new RPG_Project(pathToProject, false); 81 | Decrypter encrypter; 82 | 83 | if(key == null) 84 | encrypter = new Decrypter(); 85 | else 86 | encrypter = new Decrypter(key); 87 | 88 | rpgProject.setOutputPath(outputDir); 89 | rpgProject.setMV(toMV); 90 | encrypter.setHeaderLen(headerLen); 91 | encrypter.setSignature(signature); 92 | encrypter.setVersion(version); 93 | encrypter.setRemain(remain); 94 | rpgProject.encryptFilesCmd(encrypter); 95 | } catch(Exception e) { 96 | e.printStackTrace(); 97 | CMD.exitCMD(CMD.STATUS_ERROR); 98 | } 99 | } 100 | 101 | /** 102 | * Prints help for the command 103 | */ 104 | @Override 105 | public void printHelp() { 106 | App.showMessage("Encrypts files back to MV/MZ"); 107 | App.showMessage(""); 108 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" encrypt [path to encrypt files dir] [(optional) output path] [(optional) to MV - true|false] [(optional) key - auto|keyValue] [(optional) headerLen] [(optional) hsignature] [(optional) hversion] [(optional) hremain]"); 109 | App.showMessage(""); 110 | App.showMessage(CMD.HELP_INDENT + "Params: (Separate each param by a space, for paths use \"\" around the path)"); 111 | App.showMessage(CMD.HELP_INDENT + " [path to encrypt files dir] - Path to the File-Dir/Project you want to encrypt"); 112 | App.showMessage(CMD.HELP_INDENT + " (optional) [output path] - Path where the encrypted files go"); 113 | App.showMessage(CMD.HELP_INDENT + " Default: \"output\" (out dir in program dir)"); 114 | App.showMessage(CMD.HELP_INDENT + " (optional) [to MV (true|false)] - Encrypts files for MV (MZ on false) | Default: true"); 115 | App.showMessage(CMD.HELP_INDENT + " (optional) [key (auto|keyValue)] - Encryption key or auto detection | Default: auto"); 116 | App.showMessage(""); 117 | App.showMessage(CMD.HELP_INDENT + "Header-Values: (usually REALLY not needed)"); 118 | App.showMessage(CMD.HELP_INDENT + " (very optional) [headerLen] - Byte length of the Header | Default: " + this.headerLen); 119 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hsignature] - Signature of the Header | Default: " + this.signature); 120 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hversion] - Version of the Header | Default: " + this.version); 121 | App.showMessage(CMD.HELP_INDENT + " (very optional) [hremain] - Remain of the Header | Default: " + this.remain); 122 | App.showMessage(""); 123 | App.showMessage(CMD.HELP_INDENT + "Examples of full commands with all params:"); 124 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" encrypt \"C:\\my rpg mv game\\\" \"output\" true auto"); 125 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" encrypt \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true d41d8cd98f00b204e9800998ecf8427e"); 126 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" encrypt \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true d41d8cd98f00b204e9800998ecf8427e 14 5250474d56000000 000301 00000000"); 127 | App.showMessage(""); 128 | App.showMessage(CMD.HELP_INDENT + "- The first command encrypts all files to this programs output dir, as a MV-Files and auto-detects the key"); 129 | App.showMessage(CMD.HELP_INDENT + "- The second command encrypts all files inside the game directory, as MV-Files"); 130 | App.showMessage(CMD.HELP_INDENT + " with the key d41d8cd98f00b204e9800998ecf8427e"); 131 | App.showMessage(CMD.HELP_INDENT + "- The third command does the same as the 2nd, just shows how you can modify the values of the header"); 132 | App.showMessage(""); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Help.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | 6 | /** 7 | * @author Peter Dragicevic 8 | */ 9 | class Help implements I_CMD { 10 | /** 11 | * Runs the Command 12 | * 13 | * @param args - Command-Line commands 14 | */ 15 | @Override 16 | public void run(String[] args) { 17 | App.showMessage("Invalid Command \"" + args[1] + "\"!", CMD.STATUS_WARNING); 18 | App.showMessage(""); 19 | printHelp(); 20 | } 21 | 22 | /** 23 | * Prints help for the command 24 | */ 25 | @Override 26 | public void printHelp() { 27 | App.showMessage("Help:"); 28 | App.showMessage(""); 29 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" [command] [help|args...]"); 30 | App.showMessage(""); 31 | App.showMessage(CMD.HELP_INDENT + "Commands:"); 32 | App.showMessage(CMD.HELP_INDENT + " help - Shows this message"); 33 | App.showMessage(CMD.HELP_INDENT + " decrypt - Decrypts Files of a Game-Directory"); 34 | App.showMessage(CMD.HELP_INDENT + " encrypt - (Re-)Encrypts resource Files"); 35 | App.showMessage(CMD.HELP_INDENT + " restore - Restores images of a Game-Directory"); 36 | //App.showMessage(CMD.HELP_INDENT + " restoreproject - Restores a RPG-MV/MZ Project (Makes it editable again)"); 37 | App.showMessage(CMD.HELP_INDENT + " key - Detects the Key and Displays it"); 38 | //App.showMessage(CMD.HELP_INDENT + " open - Opens an encrypted Image"); 39 | App.showMessage(CMD.HELP_INDENT + " update - Updates this Program"); 40 | App.showMessage(""); 41 | App.showMessage(CMD.HELP_INDENT + "Display detailed help for each command:"); 42 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" [command] help"); 43 | App.showMessage(""); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/I_CMD.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | /** 4 | * @author Peter Dragicevic 5 | */ 6 | interface I_CMD { 7 | /** 8 | * Runs the Command 9 | * 10 | * @param args - Command-Line commands 11 | */ 12 | void run(String[] args); 13 | 14 | /** 15 | * Prints help for the command 16 | */ 17 | void printHelp(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Open.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | import org.petschko.rpgmakermv.decrypt.Decrypter; 6 | 7 | import java.awt.Desktop; 8 | import java.io.File; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | 13 | /** 14 | * @author Peter Dragicevic 15 | */ 16 | class Open implements I_CMD { 17 | private String pathToFile; 18 | 19 | /** 20 | * Runs the Command 21 | * 22 | * @param args - Command-Line commands 23 | */ 24 | @Override 25 | public void run(String[] args) { 26 | /*if(args.length < 2) { 27 | App.showMessage("To less arguments, see help", CMD.STATUS_WARNING); 28 | App.showMessage(""); 29 | this.printHelp(); 30 | CMD.exitCMD(CMD.STATUS_WARNING); 31 | return; 32 | } 33 | 34 | // Set Path to Project 35 | pathToFile = args[1]; 36 | App.showMessage("Open file: \"" + pathToFile + "\"..."); 37 | 38 | openFile();*/ 39 | printHelp(); 40 | CMD.exitCMD(CMD.STATUS_WARNING); 41 | } 42 | 43 | /** 44 | * Opens a RPG-MV/MZ Image-File 45 | */ 46 | private void openFile() { 47 | try { 48 | // todo fix issue file is deleted before shown 49 | 50 | // Restore image 51 | org.petschko.lib.File file = new org.petschko.lib.File(pathToFile); 52 | Decrypter decrypter = new Decrypter(); 53 | decrypter.decryptFile(file, true); 54 | 55 | // Write to tmp file 56 | File tmpFile = File.createTempFile("temp", ".png"); 57 | Path tmpFilePath = Paths.get(tmpFile.getAbsolutePath()); 58 | Files.write(tmpFilePath, file.getContent()); 59 | 60 | // Open and set delete delete tmp file 61 | Desktop.getDesktop().open(tmpFile); 62 | tmpFile.deleteOnExit(); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | CMD.exitCMD(CMD.STATUS_ERROR); 66 | } 67 | 68 | CMD.exitCMD(CMD.STATUS_OK); 69 | } 70 | 71 | /** 72 | * Prints help for the command 73 | */ 74 | @Override 75 | public void printHelp() { 76 | App.showMessage("open -> !! NOT IMPLEMENTED YET !!", CMD.STATUS_WARNING); 77 | App.showMessage(""); 78 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" open [path to rpgmvp|png_ file]"); 79 | App.showMessage(""); 80 | App.showMessage(CMD.HELP_INDENT + "Params: (Separate each param by a space, for paths use \"\" around the path)"); 81 | App.showMessage(CMD.HELP_INDENT + " [path to rpgmvp|png_ file] - Path to the rpgmvp/png_ file you want to open"); 82 | App.showMessage(""); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Restore.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | import org.petschko.rpgmakermv.decrypt.Decrypter; 6 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 7 | 8 | /** 9 | * @author Peter Dragicevic 10 | */ 11 | class Restore implements I_CMD { 12 | private String pathToProject; 13 | private String outputDir; 14 | 15 | // Decoder options 16 | private boolean verifyDir = false; 17 | private boolean ignoreFakeHeader = true; 18 | private int headerLen = Decrypter.DEFAULT_HEADER_LEN; 19 | 20 | /** 21 | * Runs the Command 22 | * 23 | * @param args - Command-Line commands 24 | */ 25 | @Override 26 | public void run(String[] args) { 27 | if(args.length < 2) { 28 | App.showMessage("To less arguments, see help", CMD.STATUS_WARNING); 29 | App.showMessage(""); 30 | this.printHelp(); 31 | CMD.exitCMD(CMD.STATUS_WARNING); 32 | return; 33 | } 34 | 35 | // Set Path to Project 36 | pathToProject = args[1]; 37 | App.showMessage("Set Project-Dir to: \"" + pathToProject + "\""); 38 | 39 | // Set Output-Dir 40 | try { 41 | outputDir = args[2]; 42 | } catch(ArrayIndexOutOfBoundsException arEx) { 43 | outputDir = Config.DEFAULT_OUTPUT_DIR; 44 | } 45 | 46 | App.showMessage("Set Output-Dir to: \"" + outputDir + "\""); 47 | 48 | if(args.length >= 4) 49 | verifyDir = Boolean.parseBoolean(args[3]); 50 | if(args.length >= 5) 51 | ignoreFakeHeader = Boolean.parseBoolean(args[4]); 52 | if(args.length >= 6) { 53 | headerLen = Integer.parseInt(args[5]); 54 | 55 | // Ensure headerLen is at least 1 else default 56 | if(headerLen < 1) 57 | headerLen = Decrypter.DEFAULT_HEADER_LEN; 58 | } 59 | 60 | handleFiles(); 61 | } 62 | 63 | /** 64 | * Handles Files to restore 65 | */ 66 | private void handleFiles() { 67 | try { 68 | RPG_Project rpgProject = new RPG_Project(pathToProject, verifyDir); 69 | Decrypter decrypter = new Decrypter(); 70 | 71 | rpgProject.setOutputPath(outputDir); 72 | decrypter.setIgnoreFakeHeader(ignoreFakeHeader); 73 | decrypter.setHeaderLen(headerLen); 74 | rpgProject.decryptFilesCmd(decrypter, true); 75 | } catch(Exception e) { 76 | e.printStackTrace(); 77 | CMD.exitCMD(CMD.STATUS_ERROR); 78 | } 79 | } 80 | 81 | /** 82 | * Prints help for the command 83 | */ 84 | @Override 85 | public void printHelp() { 86 | App.showMessage("Restores images without needing the Key"); 87 | App.showMessage(""); 88 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" restore [path to project] [(optional) output path] [(optional) verifyRpgDir - false|true] [(optional) ignoreFakeHeader - true|false] [(optional) headerLen]"); 89 | App.showMessage(""); 90 | App.showMessage(CMD.HELP_INDENT + "Params: (Separate each param by a space, for paths use \"\" around the path)"); 91 | App.showMessage(CMD.HELP_INDENT + " [path to project] - Path to the RPG-MV/MZ Project were you want to restore images"); 92 | App.showMessage(CMD.HELP_INDENT + " (optional) [output path] - Path where the restored files go | Default: \"output\" (out dir in program dir)"); 93 | App.showMessage(CMD.HELP_INDENT + " (optional) [verifyRpgDir (false|true)] - Verifies if its a RPG-MV/MZ dir | Default: false"); 94 | App.showMessage(CMD.HELP_INDENT + " (optional) [ignoreFakeHeader (true|false)] - Ignored the Files MV/MZ-Header | Default: true"); 95 | App.showMessage(""); 96 | App.showMessage(CMD.HELP_INDENT + "Header-Values: (usually REALLY not needed)"); 97 | App.showMessage(CMD.HELP_INDENT + " (very optional) [headerLen] - Byte length of the Header | Default: " + this.headerLen); 98 | App.showMessage(""); 99 | App.showMessage(CMD.HELP_INDENT + "Examples of full commands with all params:"); 100 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" restore \"C:\\my rpg mv game\\\" \"output\" false true"); 101 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" restore \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true false"); 102 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" restore \"C:\\my rpg mv game\\\" \"C:\\my rpg mv game\\\" true false 14"); 103 | App.showMessage(""); 104 | App.showMessage(CMD.HELP_INDENT + "- The first command restores all files inside this programs output dir, dont check if its a"); 105 | App.showMessage(CMD.HELP_INDENT + " RPG-MV/MZ dir and ignores if the header of the files is the RPG-MV/MZ header"); 106 | App.showMessage(CMD.HELP_INDENT + "- The second command restores all files inside the game directory, it checks if RPG-MV/MZ dir and"); 107 | App.showMessage(CMD.HELP_INDENT + " if Header is valid"); 108 | App.showMessage(CMD.HELP_INDENT + "- The third command does the same as the 2nd, just shows how you can modify the header length"); 109 | App.showMessage(""); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/RestoreProject.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.rpgmakermv.decrypt.App; 4 | import org.petschko.rpgmakermv.decrypt.Config; 5 | 6 | /** 7 | * @author Peter Dragicevic 8 | */ 9 | class RestoreProject implements I_CMD { 10 | /** 11 | * Runs the Command 12 | * 13 | * @param args - Command-Line commands 14 | */ 15 | @Override 16 | public void run(String[] args) { 17 | printHelp(); 18 | CMD.exitCMD(CMD.STATUS_WARNING); 19 | } 20 | 21 | /** 22 | * Prints help for the command 23 | */ 24 | @Override 25 | public void printHelp() { 26 | App.showMessage("restoreproject -> !! NOT IMPLEMENTED YET !!", CMD.STATUS_WARNING); 27 | App.showMessage(""); 28 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" restoreproject"); 29 | App.showMessage(""); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/cmd/Update.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.cmd; 2 | 3 | import org.petschko.lib.update.UpdateException; 4 | import org.petschko.rpgmakermv.decrypt.App; 5 | import org.petschko.rpgmakermv.decrypt.Config; 6 | 7 | import java.awt.Desktop; 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URISyntaxException; 11 | 12 | /** 13 | * @author Peter Dragicevic 14 | */ 15 | class Update implements I_CMD { 16 | private static final String SUB_CMD_WHATS_NEW = "whatsnew"; 17 | 18 | private org.petschko.lib.update.Update update = null; 19 | 20 | /** 21 | * Runs the Command 22 | * 23 | * @param args - Command-Line commands 24 | */ 25 | @Override 26 | public void run(String[] args) { 27 | if(! Config.UPDATE_CHECK) { 28 | App.showMessage("Updates are disabled!", CMD.STATUS_WARNING); 29 | CMD.exitCMD(CMD.STATUS_WARNING); 30 | return; 31 | } 32 | 33 | this.update = checkForUpdates(false, true); 34 | 35 | if(this.update != null) { 36 | if(args.length >= 2) { 37 | String subCmd = args[1]; 38 | 39 | // Handle sub CMDs 40 | if(subCmd.equals(SUB_CMD_WHATS_NEW)) { 41 | this.showWhatsNew(); 42 | } else { 43 | App.showMessage("Sub-Command \"" + subCmd + "\" doesnt exists! See help", CMD.STATUS_WARNING); 44 | App.showMessage(""); 45 | this.printHelp(); 46 | CMD.exitCMD(CMD.STATUS_WARNING); 47 | } 48 | return; 49 | } 50 | 51 | this.runUpdate(); 52 | } 53 | } 54 | 55 | /** 56 | * Runs the Update 57 | */ 58 | private void runUpdate() { 59 | if(! this.update.isHasNewVersion()) { 60 | System.out.println("You are already using the newest Version!"); 61 | System.out.println(CMD.LINE_CMD); 62 | return; 63 | } 64 | 65 | App.showMessage("Starting update..."); 66 | try { 67 | update.runUpdate(Config.THIS_JAR_FILE_NAME, false); 68 | } catch(UpdateException e) { 69 | App.showMessage("Update Failed... Cause: " + e.getMessage()); 70 | } 71 | } 72 | 73 | /** 74 | * Opens the Link in whats new 75 | */ 76 | private void showWhatsNew() { 77 | if(! this.update.isHasNewVersion()) { 78 | System.out.println("You are already using the newest Version!"); 79 | System.out.println(CMD.LINE_CMD); 80 | } else if(Desktop.isDesktopSupported()) { 81 | Desktop desktop = Desktop.getDesktop(); 82 | 83 | if(desktop.isSupported(Desktop.Action.BROWSE)) { 84 | try { 85 | URI uri = new URI(this.update.getWhatsNewUrl().toString()); 86 | desktop.browse(uri); 87 | } catch(IOException | URISyntaxException e) { 88 | App.showMessage("Can't open \"What's new...\"", CMD.STATUS_ERROR); 89 | CMD.exitCMD(CMD.STATUS_ERROR); 90 | return; 91 | } 92 | } 93 | } else { 94 | App.showMessage("Can't open \"What's new...\"...", CMD.STATUS_ERROR); 95 | App.showMessage("This operation isnt supported by your OS!", CMD.STATUS_ERROR); 96 | CMD.exitCMD(CMD.STATUS_ERROR); 97 | return; 98 | } 99 | 100 | CMD.exitCMD(CMD.STATUS_OK); 101 | } 102 | 103 | /** 104 | * Prints help for the command 105 | */ 106 | @Override 107 | public void printHelp() { 108 | App.showMessage("Usage: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" update [(optional) Sub Command]"); 109 | App.showMessage(""); 110 | App.showMessage(CMD.HELP_INDENT + "Sub-Commands:"); 111 | App.showMessage(CMD.HELP_INDENT + " " + SUB_CMD_WHATS_NEW + " - Opens \"Whats new\" in your Browser"); 112 | App.showMessage(""); 113 | App.showMessage(CMD.HELP_INDENT + "Updates the Program:"); 114 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" update"); 115 | App.showMessage(""); 116 | App.showMessage(CMD.HELP_INDENT + "Show whats new in your Browser:"); 117 | App.showMessage(CMD.HELP_INDENT + " java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" update " + SUB_CMD_WHATS_NEW); 118 | App.showMessage(""); 119 | } 120 | 121 | /** 122 | * Check if there is an update and displays it 123 | */ 124 | static void checkForUpdates() { 125 | checkForUpdates(true, false); 126 | } 127 | 128 | /** 129 | * Check if there is an update and may displays it 130 | * 131 | * @param output - Shows console output 132 | * @param ignoreUpdateCache - Ignored the Update-Cache 133 | * @return - Update Object 134 | */ 135 | private static org.petschko.lib.update.Update checkForUpdates(boolean output, boolean ignoreUpdateCache) { 136 | org.petschko.lib.update.Update update = null; 137 | 138 | try { 139 | if(ignoreUpdateCache) 140 | update = new org.petschko.lib.update.Update(Config.UPDATE_URL, Config.VERSION_NUMBER, true); 141 | else 142 | update = new org.petschko.lib.update.Update(Config.UPDATE_URL, Config.VERSION_NUMBER, Config.UPDATE_CHECK_EVERY_SECS); 143 | } catch(IOException e) { 144 | System.out.println("Update: Can't check for Updates..."); 145 | System.out.println(CMD.LINE_CMD); 146 | } 147 | 148 | if(update != null) { 149 | if(update.isHasNewVersion() && output) { 150 | System.out.println("Update: There is a new Version available! New Version: " + update.getNewestVersion()); 151 | System.out.println(); 152 | System.out.println("For update run: java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" update"); 153 | System.out.println("To see whats new (Opens Browser): java -jar \"" + Config.THIS_JAR_FILE_NAME + "\" update "+ SUB_CMD_WHATS_NEW); 154 | System.out.println(CMD.LINE_CMD); 155 | } 156 | } 157 | 158 | return update; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/About.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.lib.gui.JImageLabel; 5 | import org.petschko.lib.gui.JLabelExtra; 6 | import org.petschko.lib.gui.JPanelLine; 7 | import org.petschko.rpgmakermv.decrypt.Config; 8 | 9 | import javax.swing.BorderFactory; 10 | import javax.swing.Box; 11 | import javax.swing.BoxLayout; 12 | import javax.swing.JComponent; 13 | import javax.swing.JFrame; 14 | import javax.swing.JLabel; 15 | import javax.swing.JPanel; 16 | import java.awt.BorderLayout; 17 | import java.awt.Component; 18 | import java.awt.Dimension; 19 | import java.awt.GraphicsEnvironment; 20 | import java.awt.HeadlessException; 21 | 22 | /** 23 | * @author Peter Dragicevic 24 | */ 25 | class About extends org.petschko.lib.gui.GUI_About { 26 | /** 27 | * Creates a new, initially invisible Frame with the 28 | * specified title. 29 | *

30 | * This constructor sets the component's locale property to the value 31 | * returned by JComponent.getDefaultLocale. 32 | * 33 | * @param title the title for the frame 34 | * @param relativeTo relative to which parent component 35 | * @throws HeadlessException if GraphicsEnvironment.isHeadless() 36 | * returns true. 37 | * @see GraphicsEnvironment#isHeadless 38 | * @see Component#setSize 39 | * @see Component#setVisible 40 | * @see JComponent#getDefaultLocale 41 | */ 42 | About(String title, JFrame relativeTo) throws HeadlessException { 43 | super(title, relativeTo); 44 | } 45 | 46 | /** 47 | * Construct the Content of the About-Window 48 | */ 49 | @Override 50 | protected void constructAbout() { 51 | int lineSpace = 4; 52 | 53 | // Initial Comps - Panels 54 | JPanel borderFrame = new JPanel(); 55 | JPanel descriptionContainer = new JPanel(); 56 | JPanel logoPanel = new JPanel(); 57 | JPanel okButton = new JPanel(); 58 | 59 | // Initial Comps - Labels 60 | JPanelLine versionLine = new JPanelLine(); 61 | JLabelExtra versionHeading = new JLabelExtra("Version:"); 62 | JLabel version = new JLabel(Config.VERSION); 63 | 64 | JPanelLine licenceLine = new JPanelLine(); 65 | JLabelExtra licenceHeading = new JLabelExtra("Licence:"); 66 | JLabelExtra licence = new JLabelExtra("MIT-Licence"); 67 | licence.setURL(Config.PROJECT_LICENCE_URL, true); 68 | 69 | JPanelLine projectLine = new JPanelLine(); 70 | JLabelExtra projectHpHeading = new JLabelExtra("Project-HP:"); 71 | JLabelExtra projectHp = new JLabelExtra("Visit the Project-Page on GitLab"); 72 | projectHp.setURL(Config.PROJECT_PAGE_URL, true); 73 | 74 | JPanelLine creditLine = new JPanelLine(); 75 | JLabelExtra creditHeading = new JLabelExtra("Credits:"); 76 | JPanelLine creatorLine = new JPanelLine(); 77 | JLabel programmedBy = new JLabel(Const.CREATOR + " (Programmer) - "); 78 | JLabelExtra programmedByURL = new JLabelExtra("Website"); 79 | programmedByURL.setURL(Const.CREATOR_URL, true); 80 | JLabelExtra programmedByDonate = new JLabelExtra("Donate"); 81 | programmedByDonate.setURL(Const.CREATOR_DONATION_URL, true); 82 | 83 | // Set Layouts 84 | borderFrame.setLayout(new BorderLayout()); 85 | descriptionContainer.setLayout(new BoxLayout(descriptionContainer, BoxLayout.Y_AXIS)); 86 | 87 | // Style 88 | versionHeading.setUnderline(true); 89 | licenceHeading.setUnderline(true); 90 | projectHpHeading.setUnderline(true); 91 | creditHeading.setUnderline(true); 92 | borderFrame.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); 93 | descriptionContainer.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0)); 94 | 95 | // Add stuff 96 | logoPanel.add(this.imagePanel); 97 | okButton.add(this.closeButton); 98 | 99 | versionLine.add(versionHeading); 100 | versionLine.addSpaceDimension(10); 101 | versionLine.add(version); 102 | licenceLine.add(licenceHeading); 103 | licenceLine.addSpaceDimension(10); 104 | licenceLine.add(licence); 105 | projectLine.add(projectHpHeading); 106 | projectLine.addSpaceDimension(10); 107 | projectLine.add(projectHp); 108 | creditLine.add(creditHeading); 109 | creatorLine.add(programmedBy); 110 | creatorLine.add(programmedByURL); 111 | creatorLine.add(new JLabel(" | ")); 112 | creatorLine.add(programmedByDonate); 113 | 114 | descriptionContainer.add(versionLine); 115 | descriptionContainer.add(Box.createRigidArea(new Dimension(0, lineSpace))); 116 | descriptionContainer.add(licenceLine); 117 | descriptionContainer.add(Box.createRigidArea(new Dimension(0, lineSpace))); 118 | descriptionContainer.add(projectLine); 119 | descriptionContainer.add(Box.createRigidArea(new Dimension(0, lineSpace))); 120 | descriptionContainer.add(creditLine); 121 | descriptionContainer.add(creatorLine); 122 | 123 | borderFrame.add(logoPanel, BorderLayout.NORTH); 124 | borderFrame.add(descriptionContainer, BorderLayout.CENTER); 125 | borderFrame.add(okButton, BorderLayout.SOUTH); 126 | 127 | this.add(borderFrame); 128 | this.setResizable(false); 129 | this.pack(); 130 | } 131 | 132 | /** 133 | * Returns the text of the Close-Button 134 | * 135 | * @return - Button-Text 136 | */ 137 | @Override 138 | protected String closeButtonText() { 139 | return "Ok"; 140 | } 141 | 142 | /** 143 | * Creates the About-Icon 144 | * 145 | * @return - JImageLabel or null if not set 146 | */ 147 | @Override 148 | protected JImageLabel aboutIcon() { 149 | JImageLabel imagePanel = new JImageLabel(Config.AUTHOR_IMAGE, true); 150 | 151 | // Ensure this size 152 | imagePanel.setImageSize(200, 200); 153 | 154 | return imagePanel; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/ActionListener.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.File; 4 | import org.petschko.lib.Functions; 5 | import org.petschko.lib.gui.JDirectoryChooser; 6 | import org.petschko.lib.gui.notification.ErrorWindow; 7 | import org.petschko.lib.gui.notification.InfoWindow; 8 | import org.petschko.rpgmakermv.decrypt.App; 9 | import org.petschko.rpgmakermv.decrypt.Preferences; 10 | 11 | import javax.swing.JFileChooser; 12 | import javax.swing.JOptionPane; 13 | import javax.swing.UIManager; 14 | import javax.swing.filechooser.FileNameExtensionFilter; 15 | import java.awt.Desktop; 16 | import java.awt.event.WindowAdapter; 17 | import java.awt.event.WindowEvent; 18 | 19 | /** 20 | * @author Peter Dragicevic 21 | */ 22 | class ActionListener { 23 | 24 | /** 25 | * Close via Menu ActionListener 26 | * 27 | * @return - Close ActionListener 28 | */ 29 | static java.awt.event.ActionListener closeMenu() { 30 | return e -> App.closeGUI(); 31 | } 32 | 33 | /** 34 | * Close-Action 35 | * 36 | * @return - Close WindowAdapter 37 | */ 38 | static WindowAdapter closeButton() { 39 | return new WindowAdapter() { 40 | @Override 41 | public void windowClosing(WindowEvent e) { 42 | App.closeGUI(); 43 | } 44 | }; 45 | } 46 | 47 | /** 48 | * Switches a Config-Value with the given name 49 | * 50 | * @param configName - Config-Name 51 | * @return - Switch-Setting ActionListener 52 | */ 53 | static java.awt.event.ActionListener switchSetting(String configName) { 54 | if(configName == null) { 55 | Exception e = new Exception("configName can't be null!"); 56 | e.printStackTrace(); 57 | } 58 | 59 | return e -> App.preferences.switchBoolConfig(configName); 60 | } 61 | 62 | /** 63 | * Open-Website ActionListener 64 | * 65 | * @param url - Target URL 66 | * @return - Open-Website ActionListener 67 | */ 68 | static java.awt.event.ActionListener openWebsite(String url) { 69 | return e -> Functions.openWebsite(url); 70 | } 71 | 72 | /** 73 | * Open an Explorer with the given Path 74 | * 75 | * @param directoryPath - Path to open 76 | * @return Open-Explorer ActionListener 77 | */ 78 | static java.awt.event.ActionListener openExplorer(String directoryPath) { 79 | return e -> { 80 | Desktop desktop = Desktop.getDesktop(); 81 | String path = File.ensureDSonEndOfPath(directoryPath); 82 | 83 | if(path == null) { 84 | ErrorWindow errorWindow = new ErrorWindow( 85 | "File-Explorer can't be opened due to: Directory can't be null!", 86 | ErrorWindow.ERROR_LEVEL_ERROR, 87 | false 88 | ); 89 | 90 | errorWindow.show(); 91 | return; 92 | } 93 | 94 | try { 95 | desktop.open(new java.io.File(path).getAbsoluteFile()); 96 | } catch(Exception ex) { 97 | ex.printStackTrace(); 98 | ErrorWindow errorWindow = new ErrorWindow( 99 | "Unable to open the File-Explorer with the Directory: " + directoryPath, 100 | ErrorWindow.ERROR_LEVEL_ERROR, 101 | false 102 | ); 103 | 104 | errorWindow.show(); 105 | } 106 | }; 107 | } 108 | 109 | /** 110 | * Opens the File-Dialog and selects the RPG-Maker MV/MZ Project directory 111 | * 112 | * @param gui - Main GUI Object 113 | * @return - Select RPG-Maker Project-Dir ActionListener 114 | */ 115 | static java.awt.event.ActionListener selectRPGMDir(GUI gui) { 116 | return e -> { 117 | String openDir = App.preferences.getConfig(Preferences.LAST_RPG_DIR, "."); 118 | 119 | if(! File.existsDir(openDir)) 120 | openDir = "."; 121 | 122 | UIManager.put("FileChooser.readOnly", Boolean.TRUE); 123 | JDirectoryChooser dirChooser = new JDirectoryChooser(openDir); 124 | int choose = dirChooser.showDialog(gui.getMainWindow(), null); 125 | 126 | if(dirChooser.getSelectedFile() != null && choose == JDirectoryChooser.APPROVE_OPTION) { 127 | App.preferences.setConfig(Preferences.LAST_RPG_DIR, dirChooser.getCurrentDirectory().getPath()); 128 | 129 | gui.openRPGProject(dirChooser.getSelectedFile().getPath(), true); 130 | } 131 | }; 132 | } 133 | 134 | /** 135 | * Changes the Output dir with a Directory Chooser 136 | * 137 | * @param gui - Main GUI Object 138 | * @return - Change output dir ActionListener 139 | */ 140 | static java.awt.event.ActionListener changeOutputDirectory(GUI gui) { 141 | return e -> { 142 | // Warn the user that the selected directory will be cleared 143 | if(Boolean.parseBoolean(App.preferences.getConfig(Preferences.CLEAR_OUTPUT_DIR_BEFORE_DECRYPT, "true"))) 144 | new InfoWindow("You have chosen, that the selected Directory will be cleared.\nBeware that this Program clear the selected Directory (Deletes all Files within)! Don't select directories where you have important Files or Sub-Directories in!\n\n(Or turn off the clearing under Options)", "Important Info about your Files").show(gui.getMainWindow()); 145 | 146 | String openDir = App.preferences.getConfig(Preferences.LAST_OUTPUT_PARENT_DIR, "."); 147 | 148 | if(! File.existsDir(openDir)) 149 | openDir = "."; 150 | 151 | UIManager.put("FileChooser.readOnly", Boolean.TRUE); 152 | JDirectoryChooser dirChooser = new JDirectoryChooser(openDir); 153 | int choose = dirChooser.showDialog(gui.getMainMenu(), null); 154 | 155 | if(dirChooser.getSelectedFile() != null && choose == JDirectoryChooser.APPROVE_OPTION) { 156 | App.preferences.setConfig(Preferences.LAST_OUTPUT_PARENT_DIR, dirChooser.getCurrentDirectory().getPath()); 157 | App.preferences.setConfig(Preferences.LAST_OUTPUT_DIR, dirChooser.getSelectedFile().getPath()); 158 | gui.setNewOutputDir(dirChooser.getSelectedFile().getPath()); 159 | gui.getMainMenu().doClearOutputDir.setEnabled(true); 160 | } 161 | }; 162 | } 163 | 164 | /** 165 | * Changes the current output directory path to the executable directory path 166 | * 167 | * @param gui - Main GUI Object 168 | * @return - Change output dir to current dir ActionListener 169 | */ 170 | static java.awt.event.ActionListener changeOutputDirToCurrentDir(GUI gui) { 171 | return e -> { 172 | // Warn the user that the selected directory will be cleared 173 | if(Boolean.parseBoolean(App.preferences.getConfig(Preferences.CLEAR_OUTPUT_DIR_BEFORE_DECRYPT, "true"))) 174 | new InfoWindow("You have chosen, that the selected Directory will be cleared.\nBeware that this Program clear the selected Directory (Deletes all Files within)! Don't select directories where you have important Files or Sub-Directories in!\n\n(Or turn off the clearing under Options)", "Important Info about your Files").show(gui.getMainWindow()); 175 | 176 | int answer = JOptionPane.showOptionDialog( 177 | gui.getMainWindow(), 178 | "Do you really want to change the output directory to the Directory of this Program?", 179 | "Change Directory", 180 | JOptionPane.YES_NO_OPTION, 181 | JOptionPane.QUESTION_MESSAGE, 182 | null, 183 | null, 184 | 1 185 | ); 186 | 187 | if(answer == 1) 188 | return; 189 | 190 | final String newDir = "."; 191 | 192 | App.preferences.setConfig(Preferences.LAST_OUTPUT_PARENT_DIR, newDir); 193 | App.preferences.setConfig(Preferences.LAST_OUTPUT_DIR, newDir); 194 | gui.setNewOutputDir(newDir); 195 | gui.getMainMenu().doClearOutputDir.setEnabled(false); 196 | }; 197 | } 198 | 199 | /** 200 | * Opens a File-Chooser and detects the Key from an Encrypted Image 201 | * 202 | * @param gui - Main GUI Object 203 | * @return - File-Chooser and detection from Image 204 | */ 205 | static java.awt.event.ActionListener detectKeyFromImage(GUI gui) { 206 | return e -> { 207 | String openDir = gui.getRpgProject().getPath(); 208 | 209 | if(! File.existsDir(openDir)) 210 | openDir = "."; 211 | 212 | // Add settings to File-Chooser 213 | UIManager.put("FileChooser.readOnly", Boolean.TRUE); 214 | FileNameExtensionFilter filter = new FileNameExtensionFilter("Encrypted RPG Pictures", "rpgmvp", "png_"); 215 | JFileChooser fileChooser = new JFileChooser(openDir); 216 | fileChooser.setFileFilter(filter); 217 | 218 | int choose = fileChooser.showDialog(gui.getMainWindow(), null); 219 | 220 | if(fileChooser.getSelectedFile() != null && choose == JFileChooser.APPROVE_OPTION) { 221 | File file; 222 | try { 223 | file = new File(fileChooser.getSelectedFile().getPath()); 224 | } catch (Exception ex) { 225 | ErrorWindow errorWindow = new ErrorWindow( 226 | "Could not load the selected File...", 227 | ErrorWindow.ERROR_LEVEL_ERROR, 228 | false, 229 | ex 230 | ); 231 | errorWindow.show(gui.getMainWindow()); 232 | 233 | return; 234 | } 235 | 236 | try { 237 | gui.getDecrypter().detectEncryptionKeyFromImage(file); 238 | } catch (Exception ex) { 239 | ErrorWindow errorWindow = new ErrorWindow( 240 | "Could not find the Key from the selected File...", 241 | ErrorWindow.ERROR_LEVEL_ERROR, 242 | false, 243 | ex 244 | ); 245 | errorWindow.show(gui.getMainWindow()); 246 | return; 247 | } 248 | 249 | // If found update the values and show it to the user 250 | gui.setExtractedKey(); 251 | } 252 | }; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/FileInfo.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.File; 4 | 5 | import javax.swing.BorderFactory; 6 | import javax.swing.JPanel; 7 | import javax.swing.JTextField; 8 | 9 | /** 10 | * @author Peter Dragicevic 11 | */ 12 | class FileInfo extends JPanel { 13 | private File file = null; 14 | private JTextField filePath = new JTextField(); 15 | private JTextField fileExt = new JTextField(); 16 | private JPanel realExt = new JPanel(); 17 | private JTextField realFileExt = new JTextField(); 18 | 19 | 20 | /** 21 | * FileInfo Constructor 22 | */ 23 | FileInfo() { 24 | this.setBorder(BorderFactory.createTitledBorder("File-Info")); 25 | // todo add comps together 26 | } 27 | 28 | void setFile(File file) { 29 | this.file = file; 30 | this.loadFileData(); 31 | } 32 | 33 | private void loadFileData() { 34 | //todo load and set this element 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/GUI.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.lib.File; 5 | import org.petschko.lib.Functions; 6 | import org.petschko.lib.exceptions.PathException; 7 | import org.petschko.lib.gui.*; 8 | import org.petschko.lib.gui.notification.ErrorWindow; 9 | import org.petschko.lib.gui.notification.InfoWindow; 10 | import org.petschko.rpgmakermv.decrypt.*; 11 | 12 | import javax.swing.*; 13 | import javax.swing.JOptionPane; 14 | import java.awt.BorderLayout; 15 | import java.awt.Color; 16 | import java.awt.Dimension; 17 | import java.awt.GridLayout; 18 | import java.util.ArrayList; 19 | 20 | /** 21 | * @author Peter Dragicevic 22 | */ 23 | public class GUI { 24 | private JFrame mainWindow; 25 | private Menu mainMenu; 26 | private JPanel windowPanel = new JPanel(new BorderLayout()); 27 | JPanel projectFilesPanel = new JPanel(); 28 | JList fileList = new JList<>(); 29 | private About guiAbout; 30 | private FileInfo fileInfo = new FileInfo(); 31 | ProjectInfo projectInfo = new ProjectInfo(); 32 | private RPG_Project rpgProject = null; 33 | private Decrypter decrypter = null; 34 | 35 | /** 36 | * GUI Constructor 37 | */ 38 | public GUI() { 39 | // Create and Setup components 40 | this.createMainWindow(); 41 | this.createMainMenu(); 42 | this.guiAbout = new About("About " + Config.PROGRAM_NAME, this.mainWindow); 43 | this.createWindowGUI(); 44 | 45 | // Center Window and Display it 46 | this.mainWindow.setLocationRelativeTo(null); 47 | this.mainWindow.setVisible(true); 48 | this.mainWindow.pack(); 49 | 50 | // Assign Listener 51 | this.mainMenu.assignActionListeners(this); 52 | this.setNewOutputDir(App.outputDir); 53 | 54 | // Add Update-Check 55 | if(Config.UPDATE_CHECK) { 56 | if(Functions.strToBool(App.preferences.getConfig(Preferences.AUTO_CHECK_FOR_UPDATES, "true"))) 57 | new Update(this, true); 58 | } 59 | } 60 | 61 | /** 62 | * Returns the Main-Window 63 | * 64 | * @return - Main-Window 65 | */ 66 | JFrame getMainWindow() { 67 | return mainWindow; 68 | } 69 | 70 | /** 71 | * Returns the Main-Menu 72 | * 73 | * @return - Main-Menu 74 | */ 75 | Menu getMainMenu() { 76 | return mainMenu; 77 | } 78 | 79 | /** 80 | * Returns the RPG-Project 81 | * 82 | * @return - RPG-Project 83 | */ 84 | RPG_Project getRpgProject() { 85 | return rpgProject; 86 | } 87 | 88 | /** 89 | * Sets the RPG-Project 90 | * 91 | * @param rpgProject - RPG-Project 92 | */ 93 | void setRpgProject(RPG_Project rpgProject) { 94 | this.rpgProject = rpgProject; 95 | } 96 | 97 | /** 98 | * Returns the Decrypter Object 99 | * 100 | * @return - Decrypter-Object 101 | */ 102 | Decrypter getDecrypter() { 103 | return decrypter; 104 | } 105 | 106 | /** 107 | * Sets the Decrypter Object 108 | * 109 | * @param decrypter - Decrypter Object 110 | */ 111 | void setDecrypter(Decrypter decrypter) { 112 | this.decrypter = decrypter; 113 | } 114 | 115 | /** 116 | * Returns the GUI-About Object 117 | * 118 | * @return - GUI-About Object 119 | */ 120 | About getGuiAbout() { 121 | return guiAbout; 122 | } 123 | 124 | /** 125 | * Dispose the GUI 126 | */ 127 | public void dispose() { 128 | this.guiAbout.dispose(); 129 | this.mainWindow.dispose(); 130 | } 131 | 132 | /** 133 | * Creates and assign the MainFrame 134 | */ 135 | private void createMainWindow() { 136 | this.mainWindow = new JFrame(Config.PROGRAM_NAME + " by " + Const.CREATOR + " " + Config.VERSION); 137 | this.mainWindow.setPreferredSize(new Dimension(1000, 900)); 138 | 139 | // Center the Window 140 | this.mainWindow.setLocationRelativeTo(null); 141 | this.mainWindow.pack(); 142 | 143 | // Change close Action 144 | this.mainWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); 145 | this.mainWindow.addWindowListener(ActionListener.closeButton()); 146 | } 147 | 148 | /** 149 | * Creates and assign the Main-Menu 150 | */ 151 | private void createMainMenu() { 152 | this.mainMenu = new Menu(); 153 | this.mainWindow.add(this.mainMenu, BorderLayout.NORTH); 154 | 155 | // Set Menu-Settings 156 | this.mainMenu.loadSettings(); 157 | } 158 | 159 | /** 160 | * Creates all Components for the Window 161 | */ 162 | private void createWindowGUI() { 163 | JPanel middleStuffWrapper = new JPanel(new BorderLayout()); 164 | JPanel middleFileContainer = new JPanel(new GridLayout(1, 2)); 165 | 166 | // Design stuff 167 | this.projectFilesPanel.setLayout(new BorderLayout()); 168 | this.projectFilesPanel.setBorder(BorderFactory.createTitledBorder("Project-Files")); 169 | this.windowPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 170 | 171 | // Assign to the main comps 172 | middleFileContainer.add(this.projectFilesPanel); 173 | middleFileContainer.add(this.fileInfo); 174 | 175 | this.projectInfo.reset(); 176 | middleStuffWrapper.add(this.projectInfo, BorderLayout.NORTH); 177 | middleStuffWrapper.add(middleFileContainer, BorderLayout.CENTER); 178 | 179 | this.windowPanel.add(middleStuffWrapper, BorderLayout.CENTER); 180 | this.resetFileList(); 181 | this.mainWindow.add(this.windowPanel, BorderLayout.CENTER); 182 | } 183 | 184 | /** 185 | * Resets the File-List Panel 186 | */ 187 | void resetFileList() { 188 | JLabelWrap filesListText = new JLabelWrap("Please open a RPG-Maker MV Project (\"File\" -> \"Select RPG MV/MZ Project\")"); 189 | filesListText.setColumns(20); 190 | filesListText.setForeground(Color.GRAY); 191 | filesListText.setBorder(BorderFactory.createEmptyBorder(5, 7, 5, 7)); 192 | 193 | this.projectFilesPanel.removeAll(); 194 | this.projectFilesPanel.add(filesListText, BorderLayout.NORTH); 195 | this.projectFilesPanel.validate(); 196 | } 197 | 198 | /** 199 | * Opens the RPG-MV-Project 200 | * 201 | * @param currentDirectory - Current RPG-Maker Directory 202 | * @param showInfoWindow - Show Info-Window if done 203 | */ 204 | void openRPGProject(String currentDirectory, boolean showInfoWindow) { 205 | if(currentDirectory == null) { 206 | PathException pe = new PathException("currentDirectory can't be null!", (String) null); 207 | pe.printStackTrace(); 208 | return; 209 | } 210 | 211 | WorkerOpenRPGDir openRPG = new WorkerOpenRPGDir(this, currentDirectory, showInfoWindow); 212 | openRPG.execute(); 213 | } 214 | 215 | /** 216 | * Opens the RPG-MV-Project & Decrypts it 217 | * 218 | * @param currentDirectory - Current RPG-Maker Directory 219 | */ 220 | void openRPGProjectDecrypt(String currentDirectory) { 221 | WorkerOpenRPGDir openRPG = new WorkerOpenRPGDir(this, currentDirectory, false); 222 | openRPG.showImportantMessages = true; 223 | openRPG.decryptWhenDone = true; 224 | openRPG.closeProjectWhenDone = true; 225 | openRPG.execute(); 226 | } 227 | 228 | /** 229 | * Opens the RPG-MV-Project & Encrypts it 230 | * 231 | * @param currentDirectory - Current RPG-Maker Directory 232 | */ 233 | void openRPGProjectEncrypt(String currentDirectory) { 234 | WorkerOpenRPGDir openRPG = new WorkerOpenRPGDir(this, currentDirectory, false); 235 | openRPG.showImportantMessages = true; 236 | openRPG.encryptWhenDone = true; 237 | openRPG.closeProjectWhenDone = true; 238 | openRPG.execute(); 239 | } 240 | 241 | /** 242 | * Set the new Output dir & assign new ActionListeners 243 | * 244 | * @param newOutputDir - New Output-Directory 245 | */ 246 | void setNewOutputDir(String newOutputDir) { 247 | App.outputDir = File.ensureDSonEndOfPath(newOutputDir); 248 | 249 | // Remove old ActionListener 250 | Functions.buttonRemoveAllActionListeners(this.mainMenu.openOutputDirExplorer); 251 | Functions.buttonRemoveAllActionListeners(this.mainMenu.doClearOutputDir); 252 | 253 | // New ActionListener 254 | this.mainMenu.openOutputDirExplorer.addActionListener(ActionListener.openExplorer(App.outputDir)); 255 | this.mainMenu.doClearOutputDir.addActionListener(new WorkerDirectoryClearing(this, App.outputDir)); 256 | } 257 | 258 | /** 259 | * Removes everything from the open RPG-Project also removes UI-Changes 260 | */ 261 | void closeRPGProject() { 262 | setRpgProject(null); 263 | setDecrypter(null); 264 | 265 | mainMenu.enableOnRPGProject(false, this); 266 | mainMenu.deAssignRPGActionListener(); 267 | 268 | resetFileList(); 269 | projectInfo.reset(); 270 | } 271 | 272 | /** 273 | * Assigns the Decryption Code 274 | */ 275 | void assignDecryptKey() { 276 | String defaultValue = getDecrypter().getDecryptCode() == null ? "" : getDecrypter().getDecryptCode(); 277 | String value = JOptionPane.showInputDialog(getMainWindow(), "Enter Decryption-Code:", defaultValue); 278 | 279 | if(value != null) { 280 | value = value.toLowerCase().trim(); 281 | 282 | if(value.matches("[0-9a-f]+")) { 283 | getDecrypter().setDecryptCode(value); 284 | projectInfo.setEncryptionKey(value); 285 | projectInfo.refresh(); 286 | } else { 287 | ErrorWindow ew = new ErrorWindow("Only 0-9 and A-F are allowed for the Code!", ErrorWindow.ERROR_LEVEL_WARNING, false); 288 | ew.show(); 289 | } 290 | } 291 | } 292 | 293 | /** 294 | * Changes the Header-Signature 295 | */ 296 | void changeHeaderSignature() { 297 | JTextField headerLen = new JTextField(); 298 | headerLen.setText(String.valueOf(getDecrypter().getHeaderLen())); 299 | JTextField signature = new JTextField(); 300 | signature.setText(getDecrypter().getSignature()); 301 | JTextField version = new JTextField(); 302 | version.setText(getDecrypter().getVersion()); 303 | JTextField remain = new JTextField(); 304 | remain.setText(getDecrypter().getRemain()); 305 | 306 | Object[] fields = { 307 | "Header-Length:", headerLen, 308 | "Header-Signature:", signature, 309 | "Header-Version:", version, 310 | "Header-Remain:", remain 311 | }; 312 | 313 | int option = JOptionPane.showConfirmDialog(getMainWindow(), fields, "Change-Header Values", JOptionPane.OK_CANCEL_OPTION); 314 | 315 | if(option == JOptionPane.OK_OPTION) { 316 | headerLen.setText(headerLen.getText().trim()); 317 | signature.setText(signature.getText().toLowerCase().trim()); 318 | version.setText(version.getText().toLowerCase().trim()); 319 | remain.setText(remain.getText().toLowerCase().trim()); 320 | ArrayList errors = new ArrayList<>(); 321 | boolean changes = false; 322 | 323 | if(headerLen.getText().matches("[0-9]+")) { 324 | int headerLength = Integer.parseInt(headerLen.getText()); 325 | getDecrypter().setHeaderLen(headerLength); 326 | projectInfo.setHeaderLen(headerLength); 327 | changes = true; 328 | } else 329 | errors.add("Header Length can be only numbers!"); 330 | 331 | if(signature.getText().matches("[0-9a-f]+")) { 332 | getDecrypter().setSignature(signature.getText()); 333 | projectInfo.setSignature(signature.getText()); 334 | changes = true; 335 | } else 336 | errors.add("Only 0-9 and A-F are allowed for the Signature!"); 337 | 338 | if(version.getText().matches("[0-9a-f]+")) { 339 | getDecrypter().setVersion(version.getText()); 340 | projectInfo.setVersion(version.getText()); 341 | changes = true; 342 | } else 343 | errors.add("Only 0-9 and A-F are allowed for the Version!"); 344 | 345 | if(remain.getText().matches("[0-9a-f]+")) { 346 | getDecrypter().setRemain(remain.getText()); 347 | projectInfo.setRemain(remain.getText()); 348 | changes = true; 349 | } else 350 | errors.add("Only 0-9 and A-F are allowed for the Remain!"); 351 | 352 | if(errors.size() > 0) { 353 | StringBuilder errorText = new StringBuilder(); 354 | for(String e : errors) 355 | errorText.append(e).append(Const.NEW_LINE); 356 | 357 | ErrorWindow ew = new ErrorWindow( 358 | "There were some Errors in your inputs, these were are ignored:" + Const.NEW_LINE + Const.NEW_LINE + errorText, 359 | ErrorWindow.ERROR_LEVEL_WARNING, 360 | false 361 | ); 362 | ew.show(getMainWindow()); 363 | } 364 | 365 | if(changes) { 366 | projectInfo.refresh(); 367 | 368 | mainMenu.resetHeaderToDefault.setEnabled(true); 369 | mainMenu.resetHeaderToDefaultE.setEnabled(true); 370 | } 371 | } 372 | } 373 | 374 | /** 375 | * Resets header values to the default 376 | */ 377 | void resetHeaderValues() { 378 | getDecrypter().setHeaderLen(Decrypter.DEFAULT_HEADER_LEN); 379 | getDecrypter().setSignature(Decrypter.DEFAULT_SIGNATURE); 380 | getDecrypter().setVersion(Decrypter.DEFAULT_VERSION); 381 | getDecrypter().setRemain(Decrypter.DEFAULT_REMAIN); 382 | 383 | projectInfo.setValuesFromDecrypter(getDecrypter()); 384 | projectInfo.refresh(); 385 | 386 | mainMenu.resetHeaderToDefault.setEnabled(false); 387 | mainMenu.resetHeaderToDefaultE.setEnabled(false); 388 | } 389 | 390 | /** 391 | * Sets the Extracted key, refreshes the displayed value and enables certain features 392 | */ 393 | void setExtractedKey() { 394 | if(this.getDecrypter().getDecryptCode() == null) { 395 | ErrorWindow errorWindow = new ErrorWindow( 396 | "No Key found!...", 397 | ErrorWindow.ERROR_LEVEL_ERROR, 398 | false 399 | ); 400 | errorWindow.show(this.getMainWindow()); 401 | 402 | return; 403 | } 404 | 405 | this.projectInfo.setEncryptionKey(this.getDecrypter().getDecryptCode()); 406 | this.projectInfo.refresh(); 407 | this.getMainMenu().disableOnNoKey(true, this); 408 | 409 | InfoWindow infoWindow = new InfoWindow( 410 | "Key extracted! It may results in wrong en/decryption..." 411 | ); 412 | 413 | infoWindow.show(this.getMainWindow()); 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/ProjectInfo.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.gui.JPanelLine; 4 | import org.petschko.rpgmakermv.decrypt.Decrypter; 5 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 6 | 7 | import javax.swing.*; 8 | import java.awt.Color; 9 | import java.awt.GridLayout; 10 | 11 | /** 12 | * @author Peter Dragicevic 13 | */ 14 | class ProjectInfo extends JPanel { 15 | private JPanel mainInfo = new JPanel(new GridLayout(2, 2)); 16 | private JPanel keyInfo = new JPanel(); 17 | private JPanel encryptedFiles = new JPanel(new GridLayout(1, 2)); 18 | private JPanel resourceFiles = new JPanel(new GridLayout(1, 2)); 19 | private JPanel projectFile = new JPanel(new GridLayout(1, 2)); 20 | private JPanel systemFile = new JPanel(new GridLayout(1, 2)); 21 | private JPanel jEncryptionKey = new JPanelLine(); 22 | private JPanel jHeaderLen = new JPanelLine(); 23 | private JPanel jSignature = new JPanelLine(); 24 | private JPanel jVersion = new JPanelLine(); 25 | private JPanel jRemain = new JPanelLine(); 26 | 27 | // Info values 28 | private int encryptedFilesCount = 0; 29 | private int resourceFilesCount = 0; 30 | private boolean hasProjectFile = false; 31 | private boolean hasSystemFile = false; 32 | private String encryptionKey = null; 33 | private int headerLen = 0; 34 | private String signature = null; 35 | private String version = null; 36 | private String remain = null; 37 | 38 | /** 39 | * Creates a new JPanel with a double buffer 40 | * and a flow layout. 41 | */ 42 | ProjectInfo() { 43 | this.setBorder(BorderFactory.createTitledBorder("Project-Info")); 44 | this.setLayout(new GridLayout(2, 1)); 45 | 46 | mainInfo.setBorder(BorderFactory.createEmptyBorder(5,7, 5, 7)); 47 | keyInfo.setBorder(BorderFactory.createEmptyBorder(5,7, 5, 7)); 48 | 49 | this.add(mainInfo); 50 | this.add(keyInfo); 51 | } 52 | 53 | /** 54 | *Sets the Encrypted Files count 55 | * 56 | * @param encryptedFilesCount - Encrypted Files count 57 | */ 58 | void setEncryptedFilesCount(int encryptedFilesCount) { 59 | this.encryptedFilesCount = encryptedFilesCount; 60 | } 61 | 62 | /** 63 | * Sets the Resource Files count 64 | * 65 | * @param resourceFilesCount - Resource Files count 66 | */ 67 | void setResourceFilesCount(int resourceFilesCount) { 68 | this.resourceFilesCount = resourceFilesCount; 69 | } 70 | 71 | /** 72 | * Sets if it has the Project-File 73 | * 74 | * @param hasProjectFile - has it the Project-File 75 | */ 76 | void setHasProjectFile(boolean hasProjectFile) { 77 | this.hasProjectFile = hasProjectFile; 78 | } 79 | 80 | /** 81 | * Sets if it has the System.json 82 | * 83 | * @param hasSystemFile - has it the System.json 84 | */ 85 | void setHasSystemFile(boolean hasSystemFile) { 86 | this.hasSystemFile = hasSystemFile; 87 | } 88 | 89 | /** 90 | * Sets the Encryption-Key 91 | * 92 | * @param encryptionKey - Encryption-Key 93 | */ 94 | void setEncryptionKey(String encryptionKey) { 95 | this.encryptionKey = encryptionKey; 96 | } 97 | 98 | /** 99 | * Sets the Header-Len 100 | * 101 | * @param headerLen - Header-Len 102 | */ 103 | public void setHeaderLen(int headerLen) { 104 | this.headerLen = headerLen; 105 | } 106 | 107 | /** 108 | * Sets the Header-Signature 109 | * 110 | * @param signature - Header-Signature 111 | */ 112 | void setSignature(String signature) { 113 | this.signature = signature; 114 | } 115 | 116 | /** 117 | * Sets the Header-Version 118 | * 119 | * @param version - Header-Version 120 | */ 121 | void setVersion(String version) { 122 | this.version = version; 123 | } 124 | 125 | /** 126 | * Sets the Header-Remain 127 | * 128 | * @param remain - Header-Remain 129 | */ 130 | void setRemain(String remain) { 131 | this.remain = remain; 132 | } 133 | 134 | /** 135 | * Sets the Values from a RPG-Project 136 | * 137 | * @param rpgProject - RPG-Project 138 | */ 139 | void setValuesFromRPGProject(RPG_Project rpgProject) { 140 | if(rpgProject == null) 141 | return; 142 | 143 | this.encryptedFilesCount = rpgProject.getEncryptedFiles().size(); 144 | this.resourceFilesCount = rpgProject.getResourceFiles().size(); 145 | this.hasProjectFile = rpgProject.getProjectFile() != null; 146 | this.hasSystemFile = rpgProject.getSystem() != null; 147 | } 148 | 149 | /** 150 | * Sets the Values from the Decrypter 151 | * 152 | * @param decrypter - Decrypter 153 | */ 154 | void setValuesFromDecrypter(Decrypter decrypter) { 155 | if(decrypter == null) 156 | return; 157 | 158 | this.encryptionKey = decrypter.getDecryptCode(); 159 | this.headerLen = decrypter.getHeaderLen(); 160 | this.signature = decrypter.getSignature(); 161 | this.version = decrypter.getVersion(); 162 | this.remain = decrypter.getRemain(); 163 | } 164 | 165 | /** 166 | * Removes all internal Layouts 167 | */ 168 | private void removeAllLayouts() { 169 | mainInfo.removeAll(); 170 | keyInfo.removeAll(); 171 | encryptedFiles.removeAll(); 172 | resourceFiles.removeAll(); 173 | projectFile.removeAll(); 174 | systemFile.removeAll(); 175 | jEncryptionKey.removeAll(); 176 | jHeaderLen.removeAll(); 177 | jSignature.removeAll(); 178 | jVersion.removeAll(); 179 | jRemain.removeAll(); 180 | } 181 | 182 | /** 183 | * Creates the No-Project Layout 184 | */ 185 | private void noProjectLayout() { 186 | removeAllLayouts(); 187 | 188 | JLabel jLabel = new JLabel("No Project"); 189 | jLabel.setForeground(Color.GRAY); 190 | mainInfo.add(jLabel); 191 | } 192 | 193 | /** 194 | * Builds the content with all Info-Values 195 | */ 196 | private void buildContent() { 197 | removeAllLayouts(); 198 | this.keyInfo.setLayout(new BoxLayout(this.keyInfo, BoxLayout.Y_AXIS)); 199 | 200 | this.encryptedFiles.add(new JLabel("Encrypted Files:")); 201 | JLabel encryptedFilesCountLabel = new JLabel(String.valueOf(this.encryptedFilesCount)); 202 | if(this.encryptedFilesCount == 0) 203 | encryptedFilesCountLabel.setForeground(Color.RED); 204 | this.encryptedFiles.add(encryptedFilesCountLabel); 205 | 206 | this.resourceFiles.add(new JLabel("Resource-Files:")); 207 | JLabel resourceFilesCountLabel = new JLabel(String.valueOf(this.resourceFilesCount)); 208 | if(this.resourceFilesCount == 0) 209 | resourceFilesCountLabel.setForeground(Color.RED); 210 | this.resourceFiles.add(resourceFilesCountLabel); 211 | 212 | this.systemFile.add(new JLabel("System.json:")); 213 | JLabel hasSystemJsonLabel = new JLabel(this.hasSystemFile ? "Found" : "Not Found"); 214 | hasSystemJsonLabel.setForeground(this.hasSystemFile ? new Color(6, 125, 23) : Color.RED); 215 | this.systemFile.add(hasSystemJsonLabel); 216 | 217 | this.projectFile.add(new JLabel("Project-File:")); 218 | JLabel hasProjectFile = new JLabel(this.hasProjectFile ? "Found" : "Not Found"); 219 | hasProjectFile.setForeground(this.hasProjectFile ? new Color(6, 125, 23) : Color.RED); 220 | this.projectFile.add(hasProjectFile); 221 | 222 | this.jEncryptionKey.add(new JLabel("Key: ")); 223 | JLabel keyLabel = new JLabel(this.encryptionKey == null ? "Not Found!" : this.encryptionKey); 224 | if(this.encryptionKey == null) 225 | keyLabel.setForeground(Color.RED); 226 | this.jEncryptionKey.add(keyLabel); 227 | 228 | this.jHeaderLen.add(new JLabel("Header-Length: ")); 229 | JLabel headerLabel = new JLabel(String.valueOf(this.headerLen)); 230 | if(this.headerLen != Decrypter.DEFAULT_HEADER_LEN && this.headerLen != 0) { 231 | headerLabel.setForeground(Color.BLUE); 232 | headerLabel.setText(headerLabel.getText() + " (Custom)"); 233 | } 234 | if(this.headerLen == 0) 235 | headerLabel.setForeground(Color.RED); 236 | this.jHeaderLen.add(headerLabel); 237 | 238 | this.jSignature.add(new JLabel("Signature: ")); 239 | JLabel signatureLabel = new JLabel(this.signature == null ? "-" : this.signature); 240 | if(this.signature == null) 241 | signatureLabel.setForeground(Color.RED); 242 | else if(! this.signature.equals(Decrypter.DEFAULT_SIGNATURE)) { 243 | signatureLabel.setForeground(Color.BLUE); 244 | signatureLabel.setText(signatureLabel.getText() + " (Custom)"); 245 | } 246 | this.jSignature.add(signatureLabel); 247 | 248 | this.jVersion.add(new JLabel("Version: ")); 249 | JLabel versionLabel = new JLabel(this.version == null ? "-" : this.version); 250 | if(this.version == null) 251 | versionLabel.setForeground(Color.RED); 252 | else if(! this.version.equals(Decrypter.DEFAULT_VERSION)) { 253 | versionLabel.setForeground(Color.BLUE); 254 | versionLabel.setText(versionLabel.getText() + " (Custom)"); 255 | } 256 | this.jVersion.add(versionLabel); 257 | 258 | this.jRemain.add(new JLabel("Remain: ")); 259 | JLabel remainLabel = new JLabel(this.remain == null ? "-" : this.remain); 260 | if(this.remain == null) 261 | remainLabel.setForeground(Color.RED); 262 | else if(! this.remain.equals(Decrypter.DEFAULT_REMAIN)) { 263 | remainLabel.setForeground(Color.BLUE); 264 | remainLabel.setText(remainLabel.getText() + " (Custom)"); 265 | } 266 | this.jRemain.add(remainLabel); 267 | 268 | this.mainInfo.add(this.encryptedFiles); 269 | this.mainInfo.add(this.resourceFiles); 270 | this.mainInfo.add(this.systemFile); 271 | this.mainInfo.add(this.projectFile); 272 | this.mainInfo.validate(); 273 | 274 | this.keyInfo.add(this.jEncryptionKey); 275 | this.keyInfo.add(this.jHeaderLen); 276 | this.keyInfo.add(this.jSignature); 277 | this.keyInfo.add(this.jVersion); 278 | this.keyInfo.add(this.jRemain); 279 | this.keyInfo.validate(); 280 | } 281 | 282 | /** 283 | * Refreshes the Layout & Shown Values 284 | */ 285 | void refresh() { 286 | buildContent(); 287 | validate(); 288 | } 289 | 290 | /** 291 | * Resets the Layout to No-Project 292 | */ 293 | void reset() { 294 | encryptedFilesCount = 0; 295 | resourceFilesCount = 0; 296 | hasProjectFile = false; 297 | hasSystemFile = false; 298 | encryptionKey = null; 299 | headerLen = 0; 300 | signature = null; 301 | version = null; 302 | remain = null; 303 | 304 | noProjectLayout(); 305 | validate(); 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/Update.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.Const; 4 | import org.petschko.lib.gui.JOptionPane; 5 | import org.petschko.lib.gui.notification.ErrorWindow; 6 | import org.petschko.lib.gui.notification.InfoWindow; 7 | import org.petschko.lib.update.UpdateException; 8 | import org.petschko.rpgmakermv.decrypt.App; 9 | import org.petschko.rpgmakermv.decrypt.Config; 10 | import org.petschko.rpgmakermv.decrypt.Preferences; 11 | 12 | import java.awt.*; 13 | import java.io.IOException; 14 | import java.net.URI; 15 | import java.net.URISyntaxException; 16 | 17 | /** 18 | * @author Peter Dragicevic 19 | */ 20 | class Update { 21 | private GUI gui; 22 | private org.petschko.lib.update.Update update = null; 23 | private String[] options; 24 | private boolean autoOptionExists = false; 25 | private boolean ranAutomatically = false; 26 | 27 | /** 28 | * Update constructor 29 | * 30 | * @param gui - Main GUI-Object 31 | */ 32 | Update(GUI gui) { 33 | this.gui = gui; 34 | this.options = new String[] {"Update", "Show whats new", "Cancel"}; 35 | 36 | this.init(); 37 | } 38 | 39 | /** 40 | * Update constructor 41 | * 42 | * @param gui - Main GUI-Object 43 | * @param auto - This ran automatically 44 | */ 45 | Update(GUI gui, boolean auto) { 46 | this.gui = gui; 47 | this.options = new String[] {"Update", "Show whats new", "Disable update check", "Cancel"}; 48 | this.autoOptionExists = true; 49 | this.ranAutomatically = auto; 50 | 51 | this.init(); 52 | } 53 | 54 | /** 55 | * Inits the Object 56 | */ 57 | private void init() { 58 | try { 59 | if(this.ranAutomatically) 60 | update = new org.petschko.lib.update.Update(Config.UPDATE_URL, Config.VERSION_NUMBER, Config.UPDATE_CHECK_EVERY_SECS); 61 | else 62 | update = new org.petschko.lib.update.Update(Config.UPDATE_URL, Config.VERSION_NUMBER, true); 63 | } catch (IOException e) { 64 | if(! this.ranAutomatically) { 65 | ErrorWindow ew = new ErrorWindow("Can't check for Updates...", ErrorWindow.ERROR_LEVEL_WARNING, false); 66 | ew.show(this.gui.getMainWindow()); 67 | } 68 | } 69 | 70 | this.checkIfUpdate(); 71 | } 72 | 73 | /** 74 | * Checks if an update exists 75 | */ 76 | private void checkIfUpdate() { 77 | if(update != null) { 78 | if(update.isHasNewVersion()) { 79 | // Ask the user what to do 80 | int response = JOptionPane.showOptionDialog( 81 | this.gui.getMainWindow(), 82 | "Update found!" + Const.NEW_LINE + 83 | "Your Version: " + Config.VERSION_NUMBER + Const.NEW_LINE + 84 | "New Version: " + update.getNewestVersion() + Const.NEW_LINE + Const.NEW_LINE + 85 | "What do you want to do?", 86 | "Update found", 87 | JOptionPane.DEFAULT_OPTION, 88 | JOptionPane.QUESTION_MESSAGE, 89 | null, 90 | this.options, 91 | this.options[0] 92 | ); 93 | 94 | if(response == 0) 95 | this.runUpdate(); 96 | else if(response == 1) 97 | this.showWhatsNew(); 98 | else if(this.autoOptionExists && response == 2) { 99 | App.preferences.switchBoolConfig(Preferences.AUTO_CHECK_FOR_UPDATES); 100 | gui.getMainMenu().checkForUpdates.setState(false); 101 | } 102 | } else if(! this.ranAutomatically) { 103 | InfoWindow infoWindow = new InfoWindow("You're using the newest Version!", "No update found"); 104 | infoWindow.show(this.gui.getMainWindow()); 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * Runs the update 111 | */ 112 | private void runUpdate() { 113 | try { 114 | update.runUpdate(Config.THIS_JAR_FILE_NAME, true, true, null); 115 | } catch(UpdateException e) { 116 | ErrorWindow errorWindow = new ErrorWindow("Update Failed!", ErrorWindow.ERROR_LEVEL_ERROR, false, e); 117 | errorWindow.show(this.gui.getMainWindow()); 118 | 119 | e.printStackTrace(); 120 | } 121 | } 122 | 123 | /** 124 | * Brings the user to the whats new url 125 | */ 126 | private void showWhatsNew() { 127 | if(Desktop.isDesktopSupported()) { 128 | Desktop desktop = Desktop.getDesktop(); 129 | 130 | if(desktop.isSupported(Desktop.Action.BROWSE)) { 131 | try { 132 | URI uri = new URI(update.getWhatsNewUrl().toString()); 133 | desktop.browse(uri); 134 | } catch(IOException | URISyntaxException e) { 135 | ErrorWindow errorWindow = new ErrorWindow("Can't open \"What's new...\"", ErrorWindow.ERROR_LEVEL_ERROR, false, e); 136 | errorWindow.show(this.gui.getMainWindow()); 137 | 138 | e.printStackTrace(); 139 | } 140 | } 141 | } else { 142 | ErrorWindow errorWindow = new ErrorWindow("Can't open \"What's new...\"..." + Const.NEW_LINE + "This operation isnt supported by your OS!", ErrorWindow.ERROR_LEVEL_ERROR, false); 143 | errorWindow.show(this.gui.getMainWindow()); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/WorkerDecryption.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.File; 4 | import org.petschko.lib.Functions; 5 | import org.petschko.lib.gui.notification.InfoWindow; 6 | import org.petschko.rpgmakermv.decrypt.App; 7 | import org.petschko.rpgmakermv.decrypt.Preferences; 8 | 9 | import javax.swing.ProgressMonitor; 10 | import java.awt.event.ActionEvent; 11 | import java.awt.event.ActionListener; 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * @author Peter Dragicevic 16 | */ 17 | class WorkerDecryption extends WorkerEncryption implements ActionListener { 18 | private boolean restoreImages = false; 19 | 20 | /** 21 | * WorkerDecryption constructor 22 | * 23 | * @param gui - GUI-Object 24 | * @param files - Files to Decrypt 25 | */ 26 | WorkerDecryption(GUI gui, ArrayList files) { 27 | super(gui, files); 28 | } 29 | 30 | /** 31 | * WorkerDecryption constructor 32 | * 33 | * @param gui - GUI-Object 34 | * @param files - Files to Decrypt 35 | * @param restoreImages - Restores Images without key 36 | */ 37 | WorkerDecryption(GUI gui, ArrayList files, boolean restoreImages) { 38 | super(gui, files, false); 39 | this.restoreImages = restoreImages; 40 | this.init(); 41 | } 42 | 43 | /** 44 | * Inits 45 | */ 46 | @Override 47 | protected void init() { 48 | this.progressMonitor = new ProgressMonitor(gui.getMainWindow(), this.restoreImages ? "Restoring..." : "Decrypting...", "Preparing...", 0, this.files.size()); 49 | this.progressMonitor.setProgress(0); 50 | } 51 | 52 | /** 53 | * Decrypts all Files as long it's not canceled 54 | */ 55 | protected void decryptFiles() { 56 | int i = 0; 57 | for(File file : this.files) { 58 | // Check if cancel button was pressed 59 | if(this.progressMonitor.isCanceled()) { 60 | this.cancel(true); 61 | return; 62 | } 63 | 64 | this.progressMonitor.setNote("File: " + file.getFilePath()); 65 | 66 | try { 67 | System.out.println("Decrypt: " + file.getFilePath()); 68 | gui.getDecrypter().decryptFile(file, this.restoreImages); 69 | } catch(Exception e1) { 70 | e1.printStackTrace(); 71 | } finally { 72 | if(! this.restoreImages || file.isImage()) { 73 | gui.getRpgProject().saveFile( 74 | file, 75 | Functions.strToBool(App.preferences.getConfig(Preferences.OVERWRITE_FILES, "false")) 76 | ); 77 | } 78 | } 79 | 80 | // Add Progress to Progress-Monitor 81 | i++; 82 | this.progressMonitor.setProgress(i); 83 | } 84 | } 85 | 86 | /** 87 | * Computes a result, or throws an exception if unable to do so. 88 | * 89 | * Note that this method is executed only once. 90 | * 91 | * Note: this method is executed in a background thread. 92 | * 93 | * @return the computed result 94 | */ 95 | @Override 96 | protected Void doInBackground() { 97 | if(! this.initChecksOk()) 98 | return null; 99 | 100 | this.prepareOutputDir(); 101 | this.prepareDecrypter(); 102 | 103 | // Check if Decrypter already has a Key 104 | if(! this.checkForKey(false)) 105 | return null; 106 | 107 | // Decrypt and Save Files 108 | this.decryptFiles(); 109 | 110 | return null; 111 | } 112 | 113 | /** 114 | * Executed on the Event Dispatch Thread after the {@code doInBackground} 115 | * method is finished. The default 116 | * implementation does nothing. Subclasses may override this method to 117 | * perform completion actions on the Event Dispatch Thread. Note 118 | * that you can query status inside the implementation of this method to 119 | * determine the result of this task or whether this task has been cancelled. 120 | * 121 | * @see #doInBackground 122 | * @see #isCancelled() 123 | * @see #get 124 | */ 125 | @Override 126 | protected void done() { 127 | this.progressMonitor.close(); 128 | 129 | // Reset Files/ActionListener 130 | if(this.closeProjectWhenDone) { 131 | gui.closeRPGProject(); 132 | } else { 133 | gui.openRPGProject(gui.getRpgProject().getPath(), false); 134 | } 135 | 136 | if(this.isCancelled()) { 137 | System.out.println("Cancelled..."); 138 | 139 | InfoWindow infoWindow; 140 | if(this.restoreImages) 141 | infoWindow = new InfoWindow("Restoring canceled!"); 142 | else 143 | infoWindow = new InfoWindow("Decryption canceled!"); 144 | 145 | infoWindow.show(gui.getMainWindow()); 146 | } else { 147 | System.out.println("Done."); 148 | 149 | InfoWindow infoWindow; 150 | if(this.restoreImages) 151 | infoWindow = new InfoWindow("Images are restored! ^-^"); 152 | else 153 | infoWindow = new InfoWindow("Decryption complete! =)"); 154 | 155 | infoWindow.show(gui.getMainWindow()); 156 | } 157 | } 158 | 159 | /** 160 | * Invoked when an action occurs. 161 | * 162 | * @param e - ActionEvent 163 | */ 164 | @Override 165 | public void actionPerformed(ActionEvent e) { 166 | this.execute(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/WorkerDirectoryClearing.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.File; 4 | import org.petschko.lib.exceptions.PathException; 5 | import org.petschko.lib.gui.notification.ErrorWindow; 6 | import org.petschko.lib.gui.notification.InfoWindow; 7 | 8 | import javax.swing.BorderFactory; 9 | import javax.swing.JDialog; 10 | import javax.swing.JLabel; 11 | import javax.swing.SwingWorker; 12 | import java.awt.event.ActionEvent; 13 | import java.awt.event.ActionListener; 14 | 15 | /** 16 | * @author Peter Dragicevic 17 | */ 18 | class WorkerDirectoryClearing extends SwingWorker implements ActionListener { 19 | private GUI gui; 20 | private String directoryPath = null; 21 | private JDialog jDialog; 22 | 23 | /** 24 | * WorkerDirectoryClearing constructor 25 | * 26 | * @param gui - GUI-Object 27 | * @param directoryPath - Path to clear 28 | */ 29 | WorkerDirectoryClearing(GUI gui, String directoryPath) { 30 | if(directoryPath == null) { 31 | PathException pe = new PathException("directoryPath can't be null!", (String) null); 32 | pe.printStackTrace(); 33 | return; 34 | } 35 | 36 | this.gui = gui; 37 | this.directoryPath = File.ensureDSonEndOfPath(directoryPath); 38 | } 39 | 40 | /** 41 | * Computes a result, or throws an exception if unable to do so. 42 | * 43 | * Note that this method is executed only once. 44 | * 45 | * Note: this method is executed in a background thread. 46 | * 47 | * @return the computed result 48 | */ 49 | @Override 50 | protected Void doInBackground() { 51 | if(this.directoryPath == null) 52 | return null; 53 | 54 | if(File.clearDirectory(this.directoryPath)) { 55 | InfoWindow infoWindow = new InfoWindow("Output-Directory cleared!"); 56 | infoWindow.show(gui.getMainWindow()); 57 | } else { 58 | ErrorWindow errorWindow = new ErrorWindow( 59 | "Can't clear Directory... May an other Program has still Files open in there?", 60 | ErrorWindow.ERROR_LEVEL_WARNING, 61 | false 62 | ); 63 | errorWindow.show(gui.getMainWindow()); 64 | } 65 | 66 | return null; 67 | } 68 | 69 | /** 70 | * Executed on the Event Dispatch Thread after the {@code doInBackground} 71 | * method is finished. The default 72 | * implementation does nothing. Subclasses may override this method to 73 | * perform completion actions on the Event Dispatch Thread. Note 74 | * that you can query status inside the implementation of this method to 75 | * determine the result of this task or whether this task has been cancelled. 76 | * 77 | * @see #doInBackground 78 | * @see #isCancelled() 79 | * @see #get 80 | */ 81 | @Override 82 | protected void done() { 83 | this.jDialog.dispose(); 84 | 85 | // Reset this ActionListener 86 | if(directoryPath != null) 87 | gui.setNewOutputDir(this.directoryPath); 88 | } 89 | 90 | /** 91 | * Invoked when an action occurs. 92 | * 93 | * @param e - ActionEvent 94 | */ 95 | @Override 96 | public void actionPerformed(ActionEvent e) { 97 | if(this.directoryPath == null) 98 | return; 99 | 100 | this.jDialog = new JDialog(); 101 | JLabel text = new JLabel("Please wait while clearing the Directory: " + this.directoryPath); 102 | text.setBorder(BorderFactory.createEmptyBorder(15, 20, 15, 20)); 103 | this.jDialog.setTitle("Please wait..."); 104 | this.jDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); 105 | this.jDialog.add(text); 106 | this.jDialog.pack(); 107 | this.jDialog.setLocationRelativeTo(gui.getMainMenu()); 108 | this.jDialog.setVisible(true); 109 | 110 | this.execute(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/WorkerEncryption.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.json.JSONException; 4 | import org.petschko.lib.Const; 5 | import org.petschko.lib.File; 6 | import org.petschko.lib.Functions; 7 | import org.petschko.lib.gui.notification.ErrorWindow; 8 | import org.petschko.lib.gui.notification.InfoWindow; 9 | import org.petschko.rpgmakermv.decrypt.App; 10 | import org.petschko.rpgmakermv.decrypt.Decrypter; 11 | import org.petschko.rpgmakermv.decrypt.Preferences; 12 | 13 | import javax.swing.SwingWorker; 14 | import javax.swing.ProgressMonitor; 15 | import java.awt.event.ActionEvent; 16 | import java.awt.event.ActionListener; 17 | import java.util.ArrayList; 18 | 19 | public class WorkerEncryption extends SwingWorker implements ActionListener { 20 | protected GUI gui; 21 | protected ArrayList files; 22 | protected ProgressMonitor progressMonitor; 23 | public boolean closeProjectWhenDone = false; 24 | public boolean ignoreClearing = false; 25 | public String alternateOutPutDir = null; 26 | 27 | public boolean toMv = true; 28 | 29 | /** 30 | * WorkerEncryption constructor 31 | * 32 | * @param gui - GUI-Object 33 | * @param files - Files to Encrypt 34 | */ 35 | WorkerEncryption(GUI gui, ArrayList files) { 36 | this(gui, files, true); 37 | } 38 | 39 | /** 40 | * WorkerEncryption constructor 41 | * 42 | * @param gui - GUI-Object 43 | * @param files - Files to Encrypt 44 | * @param init - Call init method 45 | */ 46 | WorkerEncryption(GUI gui, ArrayList files, boolean init) { 47 | this.gui = gui; 48 | this.files = files; 49 | 50 | if(init) 51 | this.init(); 52 | } 53 | 54 | /** 55 | * Inits 56 | */ 57 | protected void init() { 58 | this.progressMonitor = new ProgressMonitor(gui.getMainWindow(), "Encrypting...", "Preparing...", 0, this.files.size()); 59 | this.progressMonitor.setProgress(0); 60 | } 61 | 62 | /** 63 | * Performs Pre-Checks before decrypting 64 | * 65 | * @return - Pre-Checks are okay 66 | */ 67 | protected boolean initChecksOk() { 68 | if(gui.getRpgProject() == null) { 69 | ErrorWindow errorWindow = new ErrorWindow( 70 | "RPG-Project can't be null!", 71 | ErrorWindow.ERROR_LEVEL_WARNING, 72 | false 73 | ); 74 | errorWindow.show(gui.getMainWindow()); 75 | 76 | this.cancel(true); 77 | return false; 78 | } 79 | 80 | if(gui.getDecrypter() == null) { 81 | ErrorWindow errorWindow = new ErrorWindow( 82 | "Decrypter can't be null!", 83 | ErrorWindow.ERROR_LEVEL_WARNING, 84 | false 85 | ); 86 | errorWindow.show(gui.getMainWindow()); 87 | 88 | this.cancel(true); 89 | return false; 90 | } 91 | 92 | return true; 93 | } 94 | 95 | /** 96 | * Prepares the Output Dir by either setting the alternative dir or clearing it, if it's so desired by the User 97 | */ 98 | protected void prepareOutputDir() { 99 | // Set Alternative output dir 100 | if(this.alternateOutPutDir != null) 101 | gui.getRpgProject().setOutputPath(this.alternateOutPutDir); 102 | 103 | // Clear Output-Dir if checked but only if not alternate output dir or current dir 104 | if(!App.outputDir.equals(".") && this.alternateOutPutDir == null) { 105 | if( 106 | Functions.strToBool( 107 | App.preferences.getConfig(Preferences.CLEAR_OUTPUT_DIR_BEFORE_DECRYPT, "true") 108 | ) && ! this.ignoreClearing 109 | ) { 110 | this.progressMonitor.setNote("Clearing Output-Directory..."); 111 | File.clearDirectory(App.outputDir); 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * Prepares the Decrypter Object 118 | */ 119 | protected void prepareDecrypter() { 120 | gui.getDecrypter().setIgnoreFakeHeader( 121 | Functions.strToBool(App.preferences.getConfig(Preferences.IGNORE_FAKE_HEADER, "true")) 122 | ); 123 | gui.getDecrypter().setRemain(App.preferences.getConfig(Preferences.DECRYPTER_REMAIN, Decrypter.DEFAULT_REMAIN)); 124 | gui.getDecrypter().setSignature(App.preferences.getConfig(Preferences.DECRYPTER_SIGNATURE, Decrypter.DEFAULT_SIGNATURE)); 125 | gui.getDecrypter().setVersion(App.preferences.getConfig(Preferences.DECRYPTER_VERSION, Decrypter.DEFAULT_VERSION)); 126 | int headerLen = Decrypter.DEFAULT_HEADER_LEN; 127 | 128 | try { 129 | headerLen = Integer.parseInt(App.preferences.getConfig(Preferences.DECRYPTER_HEADER_LEN)); 130 | } catch(NumberFormatException ex) { 131 | ErrorWindow errorWindow = new ErrorWindow( 132 | "Header-Length was not an Valid Number - Using Default-Length!", 133 | ErrorWindow.ERROR_LEVEL_WARNING, 134 | false 135 | ); 136 | errorWindow.show(gui.getMainWindow()); 137 | 138 | // Set default as new Len 139 | App.preferences.setConfig(Preferences.DECRYPTER_HEADER_LEN, Integer.toString(Decrypter.DEFAULT_HEADER_LEN)); 140 | } 141 | gui.getDecrypter().setHeaderLen(headerLen); 142 | } 143 | 144 | /** 145 | * Checks for the Decryption-Key 146 | * 147 | * @return - Has the Key 148 | */ 149 | protected boolean checkForKey(boolean encrypt) { 150 | if(gui.getDecrypter().getDecryptCode() == null) { 151 | this.progressMonitor.setNote("Try to detect " + (encrypt ? "Encrypt" : "Decrypt") + "ion-Key..."); 152 | 153 | try { 154 | gui.getDecrypter().detectEncryptionKeyFromJson( 155 | gui.getRpgProject().getSystem(), 156 | gui.getRpgProject().getEncryptionKeyName() 157 | ); 158 | } catch(NullPointerException decryNullEx) { 159 | // File-Null-Pointer 160 | ErrorWindow errorWindow = new ErrorWindow( 161 | "Can't find " + (encrypt ? "Encrypt" : "Decrypt") + "ion-Key-File!" + Const.NEW_LINE + 162 | "Make sure that the File is in the RPG-Directory..." + Const.NEW_LINE + 163 | "Or set the Key by yourself (" + (encrypt ? "Encrypt" : "Decrypt") + " -> Set Encryption-Key)", 164 | ErrorWindow.ERROR_LEVEL_WARNING, 165 | false 166 | ); 167 | errorWindow.show(gui.getMainWindow()); 168 | 169 | // Halt task 170 | this.cancel(true); 171 | return false; 172 | } catch(JSONException e1) { 173 | // JSON-NotFound 174 | ErrorWindow errorWindow = new ErrorWindow( 175 | "Can't find " + (encrypt ? "Encrypt" : "Decrypt") + "ion-Key in File!", 176 | ErrorWindow.ERROR_LEVEL_WARNING, 177 | false 178 | ); 179 | errorWindow.show(gui.getMainWindow()); 180 | 181 | // Halt task 182 | this.cancel(true); 183 | return false; 184 | } 185 | } 186 | 187 | return true; 188 | } 189 | 190 | /** 191 | * Decrypts all Files as long it's not canceled 192 | */ 193 | protected void encryptFiles() { 194 | int i = 0; 195 | for(File file : this.files) { 196 | // Check if cancel button was pressed 197 | if(this.progressMonitor.isCanceled()) { 198 | this.cancel(true); 199 | return; 200 | } 201 | 202 | this.progressMonitor.setNote("File: " + file.getFilePath()); 203 | boolean encrypted = false; 204 | 205 | try { 206 | System.out.println("Encrypt: " + file.getFilePath()); 207 | encrypted = gui.getDecrypter().encryptFile(file, gui.getRpgProject().getPath(), toMv); 208 | } catch(Exception e1) { 209 | e1.printStackTrace(); 210 | } finally { 211 | if(encrypted) { 212 | gui.getRpgProject().saveFile( 213 | file, 214 | Functions.strToBool(App.preferences.getConfig(Preferences.OVERWRITE_FILES, "false")) 215 | ); 216 | } 217 | } 218 | 219 | // Add Progress to Progress-Monitor 220 | i++; 221 | this.progressMonitor.setProgress(i); 222 | } 223 | } 224 | 225 | /** 226 | * Computes a result, or throws an exception if unable to do so. 227 | * 228 | * Note that this method is executed only once. 229 | * 230 | * Note: this method is executed in a background thread. 231 | * 232 | * @return the computed result 233 | */ 234 | @Override 235 | protected Void doInBackground() { 236 | if(! this.initChecksOk()) 237 | return null; 238 | 239 | this.prepareOutputDir(); 240 | this.progressMonitor.setNote("Configuring Encrypter..."); 241 | this.prepareDecrypter(); 242 | 243 | // Check if Decrypter already has a Key 244 | if(! this.checkForKey(true)) 245 | return null; 246 | 247 | // Encrypt and Save Files 248 | this.encryptFiles(); 249 | 250 | return null; 251 | } 252 | 253 | /** 254 | * Executed on the Event Dispatch Thread after the {@code doInBackground} 255 | * method is finished. The default 256 | * implementation does nothing. Subclasses may override this method to 257 | * perform completion actions on the Event Dispatch Thread. Note 258 | * that you can query status inside the implementation of this method to 259 | * determine the result of this task or whether this task has been cancelled. 260 | * 261 | * @see #doInBackground 262 | * @see #isCancelled() 263 | * @see #get 264 | */ 265 | @Override 266 | protected void done() { 267 | this.progressMonitor.close(); 268 | 269 | // Reset Files/ActionListener 270 | if(this.closeProjectWhenDone) { 271 | gui.closeRPGProject(); 272 | } else { 273 | gui.openRPGProject(gui.getRpgProject().getPath(), false); 274 | } 275 | 276 | if(this.isCancelled()) { 277 | System.out.println("Cancelled..."); 278 | 279 | InfoWindow infoWindow = new InfoWindow("Encryption canceled!"); 280 | infoWindow.show(gui.getMainWindow()); 281 | } else { 282 | System.out.println("Done."); 283 | 284 | InfoWindow infoWindow = new InfoWindow("Encryption complete!"); 285 | infoWindow.show(gui.getMainWindow()); 286 | } 287 | } 288 | 289 | /** 290 | * Invoked when an action occurs. 291 | * 292 | * @param e - ActionEvent 293 | */ 294 | @Override 295 | public void actionPerformed(ActionEvent e) { 296 | this.execute(); 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /src/main/java/org/petschko/rpgmakermv/decrypt/gui/WorkerOpenRPGDir.java: -------------------------------------------------------------------------------- 1 | package org.petschko.rpgmakermv.decrypt.gui; 2 | 3 | import org.petschko.lib.CellRenderer; 4 | import org.petschko.lib.Const; 5 | import org.petschko.lib.File; 6 | import org.petschko.lib.Functions; 7 | import org.petschko.lib.exceptions.PathException; 8 | import org.petschko.lib.gui.notification.ErrorWindow; 9 | import org.petschko.lib.gui.notification.InfoWindow; 10 | import org.petschko.rpgmakermv.decrypt.App; 11 | import org.petschko.rpgmakermv.decrypt.Decrypter; 12 | import org.petschko.rpgmakermv.decrypt.Preferences; 13 | import org.petschko.rpgmakermv.decrypt.RPG_Project; 14 | 15 | import javax.swing.*; 16 | import java.awt.BorderLayout; 17 | import java.io.IOException; 18 | 19 | /** 20 | * @author Peter Dragicevic 21 | */ 22 | class WorkerOpenRPGDir extends SwingWorker { 23 | private static final int TO_MZ = 0; 24 | private static final int TO_MV = 1; 25 | 26 | private GUI gui; 27 | private String directoryPath; 28 | private boolean showInfoWindow = false; 29 | public boolean showImportantMessages = false; 30 | public boolean decryptWhenDone = false; 31 | public boolean encryptWhenDone = false; 32 | public boolean closeProjectWhenDone = false; 33 | 34 | /** 35 | * WorkerOpenRPGDir constructor 36 | * 37 | * @param gui - GUI-Object 38 | * @param directoryPath - Path of the Directory 39 | */ 40 | WorkerOpenRPGDir(GUI gui, String directoryPath) { 41 | this.gui = gui; 42 | this.directoryPath = directoryPath; 43 | } 44 | 45 | /** 46 | * WorkerOpenRPGDir constructor 47 | * 48 | * @param gui - GUI-Object 49 | * @param directoryPath - Path of the Directory 50 | * @param showInfoWindow - Show success Window after the Action 51 | */ 52 | WorkerOpenRPGDir(GUI gui, String directoryPath, boolean showInfoWindow) { 53 | this.gui = gui; 54 | this.directoryPath = directoryPath; 55 | this.showInfoWindow = showInfoWindow; 56 | } 57 | 58 | /** 59 | * Computes a result, or throws an exception if unable to do so. 60 | * 61 | * Note that this method is executed only once. 62 | * 63 | * Note: this method is executed in a background thread. 64 | * 65 | * @return the computed result 66 | */ 67 | @Override 68 | protected Void doInBackground() { 69 | try { 70 | this.directoryPath = File.convertRelativePathToAbsolute(this.directoryPath); 71 | 72 | gui.setRpgProject( 73 | new RPG_Project( 74 | File.ensureDSonEndOfPath(this.directoryPath), 75 | ! Functions.strToBool(App.preferences.getConfig(Preferences.LOAD_INVALID_RPG_DIRS, "false")) 76 | ) 77 | ); 78 | } catch(PathException e) { 79 | ErrorWindow errorWindow = new ErrorWindow( 80 | e.getMessage() + Const.NEW_LINE + 81 | "You can turn on the Option \"Load invalid RPG-Dirs anyway\" if your Directory is a RPG-Dir but it not detect it correctly." + Const.NEW_LINE + 82 | "Warning: Turning on the Option may cause incorrect results.", 83 | ErrorWindow.ERROR_LEVEL_WARNING, 84 | false 85 | ); 86 | errorWindow.show(gui.getMainWindow()); 87 | 88 | this.cancel(true); 89 | return null; 90 | } catch(Exception e) { 91 | e.printStackTrace(System.out); 92 | ErrorWindow errorWindow = new ErrorWindow(e.getMessage(), ErrorWindow.ERROR_LEVEL_ERROR, false); 93 | errorWindow.show(gui.getMainWindow()); 94 | 95 | this.cancel(true); 96 | return null; 97 | } 98 | 99 | createFileList(); 100 | return null; 101 | } 102 | 103 | /** 104 | * Executed on the Event Dispatch Thread after the {@code doInBackground} 105 | * method is finished. The default 106 | * implementation does nothing. Subclasses may override this method to 107 | * perform completion actions on the Event Dispatch Thread. Note 108 | * that you can query status inside the implementation of this method to 109 | * determine the result of this task or whether this task has been cancelled. 110 | * 111 | * @see #doInBackground 112 | * @see #isCancelled() 113 | * @see #get 114 | */ 115 | @Override 116 | protected void done() { 117 | if(! this.isCancelled()) { 118 | boolean keyFound = false; 119 | 120 | // Set values for the GUI and the Decrypter 121 | gui.setDecrypter(new Decrypter()); 122 | try { 123 | gui.getRpgProject().setOutputPath(File.convertRelativePathToAbsolute(App.outputDir)); 124 | } catch (IOException e) { 125 | ErrorWindow errorWindow = new ErrorWindow( 126 | "Cant convert the relative output Path to an absolute Path...", 127 | ErrorWindow.ERROR_LEVEL_ERROR, 128 | false 129 | ); 130 | errorWindow.show(gui.getMainWindow()); 131 | gui.closeRPGProject(); 132 | return; 133 | } 134 | gui.getMainMenu().enableOnRPGProject(true, gui); 135 | gui.getMainMenu().assignRPGActionListener(gui); 136 | 137 | // Load the Key 138 | try { 139 | gui.getDecrypter().detectEncryptionKeyFromJson(gui.getRpgProject().getSystem(), gui.getRpgProject().getEncryptionKeyName()); 140 | keyFound = true; 141 | } catch(NullPointerException nullPointerException) { 142 | gui.getMainMenu().disableOnNoKey(false, gui); 143 | } 144 | 145 | // Load Info-Values to GUI 146 | gui.projectInfo.setValuesFromRPGProject(gui.getRpgProject()); 147 | gui.projectInfo.setValuesFromDecrypter(gui.getDecrypter()); 148 | gui.projectInfo.refresh(); 149 | gui.getMainWindow().pack(); 150 | 151 | // Done 152 | if(this.showInfoWindow || this.showImportantMessages) { 153 | if(keyFound && this.showInfoWindow) { 154 | InfoWindow infoWindow = new InfoWindow( 155 | "RPG-Maker Project loaded..." + Const.NEW_LINE + Const.NEW_LINE + 156 | "Please use one of these options:" + Const.NEW_LINE + 157 | "- \"Decrypt\" -> \"All Files\" to Decrypt." + Const.NEW_LINE + 158 | "- \"Decrypt\" -> \"Restore Images (No Key)\" for restoring." 159 | ); 160 | infoWindow.show(gui.getMainWindow()); 161 | } else if(! keyFound) { 162 | String text = "RPG-Maker Project loaded..." + Const.NEW_LINE + Const.NEW_LINE + 163 | "Key not Found... You can set it manually under:" + Const.NEW_LINE + 164 | "- \"Decrypt\" -> \"Set Encryption-Key...\" or " + Const.NEW_LINE + 165 | "- \"Encrypt\" -> \"Set Encryption-Key...\"" + Const.NEW_LINE + Const.NEW_LINE + 166 | "You can also still restore the images without the Key:" + Const.NEW_LINE + 167 | "- \"Decrypt\" -> \"Restore Images (No Key)\" for restoring."; 168 | 169 | if(gui.getRpgProject().getEncryptedFiles().size() > 0) { 170 | Object[] options = { 171 | "Detect from Image", 172 | "Ok" 173 | }; 174 | int answer = JOptionPane.showOptionDialog( 175 | gui.getMainWindow(), 176 | text + Const.NEW_LINE + Const.NEW_LINE + 177 | "You can also Auto-Detect the Key from images.", 178 | "Project loaded without Key", 179 | JOptionPane.YES_NO_OPTION, 180 | JOptionPane.WARNING_MESSAGE, 181 | null, 182 | options, 183 | options[1] 184 | ); 185 | 186 | if(answer == 0) { 187 | try { 188 | gui.getDecrypter().detectEncryptionKeyFromImage(gui.getRpgProject().getEncryptedImgFile()); 189 | } catch(Exception e) { 190 | ErrorWindow errorWindow = new ErrorWindow( 191 | "Could not find the Key from Images...", 192 | ErrorWindow.ERROR_LEVEL_ERROR, 193 | false, 194 | e 195 | ); 196 | errorWindow.show(gui.getMainWindow()); 197 | return; 198 | } 199 | 200 | if(gui.getDecrypter().getDecryptCode() != null) 201 | keyFound = true; 202 | 203 | gui.setExtractedKey(); 204 | } 205 | } else if(this.showInfoWindow || this.showImportantMessages) { 206 | ErrorWindow errorWindow = new ErrorWindow( 207 | text, 208 | ErrorWindow.ERROR_LEVEL_WARNING, 209 | false 210 | ); 211 | errorWindow.show(gui.getMainWindow()); 212 | } 213 | } 214 | } 215 | 216 | // Check if there are more jobs to run 217 | if(keyFound) 218 | runEndJobs(); 219 | } 220 | 221 | // Close Project if its set 222 | if(this.closeProjectWhenDone) 223 | gui.closeRPGProject(); 224 | } 225 | 226 | /** 227 | * Creates the File-List 228 | */ 229 | void createFileList() { 230 | gui.fileList = new JList<>(gui.getRpgProject().getProjectFileList()); 231 | gui.fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 232 | 233 | CellRenderer cellRenderer = new CellRenderer(); 234 | cellRenderer.setRelativePath(gui.getRpgProject().getPath()); 235 | 236 | gui.fileList.setCellRenderer(cellRenderer); 237 | gui.fileList.setName("List"); 238 | gui.fileList.setVisibleRowCount(-1); 239 | 240 | gui.projectFilesPanel.removeAll(); 241 | gui.projectFilesPanel.add(new JScrollPane(gui.fileList), BorderLayout.CENTER); 242 | gui.projectFilesPanel.validate(); 243 | gui.projectFilesPanel.setVisible(true); 244 | } 245 | 246 | /** 247 | * Runs all end jobs like encryption or decryption 248 | */ 249 | private void runEndJobs() { 250 | if(this.decryptWhenDone) { 251 | WorkerDecryption decryptWorker = new WorkerDecryption(gui, gui.getRpgProject().getEncryptedFiles()); 252 | decryptWorker.alternateOutPutDir = this.directoryPath; 253 | decryptWorker.closeProjectWhenDone = true; 254 | decryptWorker.ignoreClearing = true; 255 | 256 | decryptWorker.execute(); 257 | } else if(this.encryptWhenDone) { 258 | WorkerEncryption encryptWorker = new WorkerEncryption(gui, gui.getRpgProject().getResourceFiles()); 259 | encryptWorker.alternateOutPutDir = this.directoryPath; 260 | encryptWorker.closeProjectWhenDone = true; 261 | encryptWorker.ignoreClearing = true; 262 | 263 | // Ask if MV or MZ 264 | switch(this.dialogMvOrMZ()) { 265 | case TO_MZ: 266 | encryptWorker.toMv = false; 267 | break; 268 | case TO_MV: 269 | encryptWorker.toMv = true; 270 | break; 271 | default: 272 | gui.closeRPGProject(); 273 | return; 274 | } 275 | 276 | encryptWorker.execute(); 277 | } 278 | 279 | // Ensure the project will only be closed after these jobs are done 280 | if(this.decryptWhenDone || this.encryptWhenDone) 281 | this.closeProjectWhenDone = false; 282 | } 283 | 284 | /** 285 | * Asks if the Encryption should be for RPG-Maker MV or MZ 286 | * 287 | * @return - Answer 288 | */ 289 | private int dialogMvOrMZ() { 290 | Object[] options = { 291 | "MZ", 292 | "MV", 293 | "Cancel" 294 | }; 295 | return JOptionPane.showOptionDialog( 296 | gui.getMainWindow(), 297 | "Do you want to encrypt to RPG-Maker MZ or MV?", 298 | "Encrypt to...?", 299 | JOptionPane.YES_NO_OPTION, 300 | JOptionPane.QUESTION_MESSAGE, 301 | null, 302 | options, 303 | options[1] 304 | ); 305 | } 306 | } 307 | -------------------------------------------------------------------------------- /src/main/resources/icons/petschko_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Petschko/Java-RPG-Maker-MV-Decrypter/b6eb85c2aafacc07f14a6ee1d3def707e8721b3d/src/main/resources/icons/petschko_icon.png -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.4.2;https://petschko.org/upload/projects/java-rpg-maker-decrypter/RPG.Maker.MV.Decrypter_0.4.2.jar;https://gitlab.com/Petschko/Java-RPG-Maker-MV-Decrypter/-/releases/v.0.4.2-alpha 2 | --------------------------------------------------------------------------------