From e5669cd90c7ea6e1a3851ff9065ee687cf7bdeb9 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 27 Apr 2024 02:30:09 -0400 Subject: [PATCH] Remove auto-updater, make it very obvious that 4.X is the next intended version for users to migrate to --- .mvn/wrapper/MavenWrapperDownloader.java | 117 ------- .mvn/wrapper/maven-wrapper.jar | Bin 58727 -> 62547 bytes .mvn/wrapper/maven-wrapper.properties | 8 +- docs/index.html | 24 ++ mvnw | 218 ++++++------ mvnw.cmd | 31 +- pom.xml | 21 +- src/main/java/me/coley/recaf/Recaf.java | 3 +- .../parse/source/WorkspaceTypeResolver.java | 4 +- src/main/java/me/coley/recaf/ui/MainMenu.java | 16 - .../java/me/coley/recaf/ui/MainWindow.java | 69 +++- .../coley/recaf/ui/controls/MarkdownView.java | 315 ++++++++++++++++++ .../recaf/ui/controls/SplitableTabPane.java | 3 +- .../recaf/ui/controls/pane/UpdatePane.java | 192 ----------- .../recaf/ui/controls/popup/UpdateWindow.java | 52 --- .../util/IllegalBytecodePatcherUtil.java | 8 +- .../me/coley/recaf/util/JavaParserUtil.java | 2 +- .../me/coley/recaf/util/self/SelfUpdater.java | 26 -- .../recaf/util/self/UpdateTaskStarter.java | 277 --------------- .../me/coley/recaf/workspace/EntryLoader.java | 4 +- .../recaf/workspace/PhantomResource.java | 55 ++- .../me/coley/recaf/workspace/Workspace.java | 2 +- src/main/resources/style/base.css | 33 +- 23 files changed, 636 insertions(+), 844 deletions(-) delete mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 src/main/java/me/coley/recaf/ui/controls/MarkdownView.java delete mode 100644 src/main/java/me/coley/recaf/ui/controls/pane/UpdatePane.java delete mode 100644 src/main/java/me/coley/recaf/ui/controls/popup/UpdateWindow.java delete mode 100644 src/main/java/me/coley/recaf/util/self/UpdateTaskStarter.java diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2..000000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index c1dd12f17644411d6e840bd5a10c6ecda0175f18..cb28b0e37c7d206feb564310fdeec0927af4123a 100644 GIT binary patch delta 52871 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≷S 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

St0o*K217#e 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 + +

@@ -62,6 +79,13 @@

Recaf

+
+

Recaf 4.0.0

+

Recaf has been rewritten from the ground up and is almost ready for an official release.
+ The new release is designed to facilitate extensive plugin and scripting support, new features and improvements to existing ones.

+

Pre-releases will be available on the project's releases page

+

You can track the progress on the 4.X development branch: dev4

+

What is Recaf?

Recaf is an open-source Java bytecode editor that simplifies the process of editing compiled Java applications. To make things easier Recaf abstracts away much of the internal class file format. Difficult tasks such as updating stack-frames are done automatically. Along with additional features to assist in the process of editing classes, Recaf is the most feature-rich free bytecode editor available.

diff --git a/mvnw b/mvnw index 5643201c7..8d937f4c1 100755 --- a/mvnw +++ b/mvnw @@ -19,7 +19,7 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script +# Apache Maven Wrapper startup batch script, version 3.2.0 # # Required ENV vars: # ------------------ @@ -27,7 +27,6 @@ # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @@ -54,7 +53,7 @@ fi cygwin=false; darwin=false; mingw=false -case "`uname`" in +case "$(uname)" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true @@ -62,9 +61,9 @@ case "`uname`" in # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" + JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME else - export JAVA_HOME="/Library/Java/Home" + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME fi fi ;; @@ -72,68 +71,38 @@ esac if [ -z "$JAVA_HOME" ] ; then if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + JAVA_HOME=$(java-config --jre-home) fi fi -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + JAVA_HOME=$(cygpath --unix "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` + CLASSPATH=$(cygpath --path --unix "$CLASSPATH") fi # For Mingw, ensure paths are in UNIX format before anything is touched if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] && + JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)" fi if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + javaExecutable="$(which javac)" + if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + readLink=$(which readlink) + if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + javaHome="$(dirname "\"$javaExecutable\"")" + javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac" else - javaExecutable="`readlink -f \"$javaExecutable\"`" + javaExecutable="$(readlink -f "\"$javaExecutable\"")" fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` + javaHome="$(dirname "\"$javaExecutable\"")" + javaHome=$(expr "$javaHome" : '\(.*\)/bin') JAVA_HOME="$javaHome" export JAVA_HOME fi @@ -149,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`\\unset -f command; \\command -v java`" + JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)" fi fi @@ -163,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { - if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" @@ -184,96 +150,99 @@ find_maven_basedir() { fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + wdir=$(cd "$wdir/.." || exit 1; pwd) fi # end of workaround done - echo "${basedir}" + printf '%s' "$(cd "$basedir" || exit 1; pwd)" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + # Remove \r in case we run on Windows within Git Bash + # and check out the repository with auto CRLF management + # enabled. Otherwise, we may read lines that are delimited with + # \r\n and produce $'-Xarg\r' rather than -Xarg due to word + # splitting rules. + tr -s '\r\n' ' ' < "$1" + fi +} + +log() { + if [ "$MVNW_VERBOSE" = true ]; then + printf '%s\n' "$1" fi } -BASE_DIR=`find_maven_basedir "$(pwd)"` +BASE_DIR=$(find_maven_basedir "$(dirname "$0")") if [ -z "$BASE_DIR" ]; then exit 1; fi +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +log "$MAVEN_PROJECTBASEDIR" + ########################################################################################## # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central # This allows using the maven wrapper in projects that prohibit checking in binary data. ########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" +if [ -r "$wrapperJarPath" ]; then + log "Found $wrapperJarPath" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi + log "Couldn't find $wrapperJarPath, downloading it ..." + if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + while IFS="=" read -r key value; do + # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' ) + safeValue=$(echo "$value" | tr -d '\r') + case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;; esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + log "Downloading from: $wrapperUrl" + if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") fi if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi + log "Found wget ... using wget" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi + log "Found curl ... using curl" + [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent" if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath" fi - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + log "Falling back to using Java to download" + javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" # For Cygwin, switch paths to Windows format before running javac if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` + javaSource=$(cygpath --path --windows "$javaSource") + javaClass=$(cygpath --path --windows "$javaClass") fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + log " - Compiling MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/javac" "$javaSource") fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + if [ -e "$javaClass" ]; then + log " - Running MavenWrapperDownloader.java ..." + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath" fi fi fi @@ -282,35 +251,58 @@ fi # End of extension ########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR +# If specified, validate the SHA-256 sum of the Maven wrapper jar file +wrapperSha256Sum="" +while IFS="=" read -r key value; do + case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;; + esac +done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" +if [ -n "$wrapperSha256Sum" ]; then + wrapperSha256Result=false + if command -v sha256sum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + elif command -v shasum > /dev/null; then + if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then + wrapperSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." + echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." + exit 1 + fi + if [ $wrapperSha256Result = false ]; then + echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2 + echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2 + echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2 + exit 1 + fi fi + MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + CLASSPATH=$(cygpath --path --windows "$CLASSPATH") [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` + MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") fi # Provide a "standardized" way to retrieve the CLI args that will # work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*" export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +# shellcheck disable=SC2086 # safe args exec "$JAVACMD" \ $MAVEN_OPTS \ $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 8a15b7f31..c4586b564 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -18,13 +18,12 @@ @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script +@REM Apache Maven Wrapper startup batch script, version 3.2.0 @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @@ -120,10 +119,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B ) @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central @@ -134,11 +133,11 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% + echo Downloading from: %WRAPPER_URL% ) powershell -Command "&{"^ @@ -146,7 +145,7 @@ if exist %WRAPPER_JAR% ( "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ "}" if "%MVNW_VERBOSE%" == "true" ( echo Finished downloading %WRAPPER_JAR% @@ -154,6 +153,24 @@ if exist %WRAPPER_JAR% ( ) @REM End of extension +@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file +SET WRAPPER_SHA_256_SUM="" +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B +) +IF NOT %WRAPPER_SHA_256_SUM%=="" ( + powershell -Command "&{"^ + "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^ + "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^ + " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^ + " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^ + " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^ + " exit 1;"^ + "}"^ + "}" + if ERRORLEVEL 1 goto error +) + @REM Provide a "standardized" way to retrieve the CLI args that will @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* diff --git a/pom.xml b/pom.xml index 4c7db4372..92c7c7301 100644 --- a/pom.xml +++ b/pom.xml @@ -3,22 +3,22 @@ me.coley recaf https://github.com/Col-E/Recaf/ - 2.21.13 + 2.21.14 Recaf A modern java bytecode editor UTF-8 - 9.2 + 9.7 1.6.0 - 1.9.6 + 2.0.1 0.152 1.5.498.29 0.6.0 5.8.2 4.6.3 3.21.0 - 3.24.2 + 3.25.9 18 4.0.0 3.1.12.2 @@ -93,7 +93,7 @@ com.github.Col-E jphantom - 1.4.3 + 1.4.4 @@ -135,7 +135,7 @@ com.google.guava guava - 32.0.0-jre + 33.1.0-jre @@ -327,7 +327,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.9.0 + 3.13.0 1.8 1.8 @@ -348,7 +348,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.0.0-M3 + 3.4.1 enforce-maven @@ -465,10 +465,11 @@ --> + org.apache.maven.plugins maven-jar-plugin diff --git a/src/main/java/me/coley/recaf/Recaf.java b/src/main/java/me/coley/recaf/Recaf.java index 06fe895cc..f09431ac2 100644 --- a/src/main/java/me/coley/recaf/Recaf.java +++ b/src/main/java/me/coley/recaf/Recaf.java @@ -31,7 +31,7 @@ * @author Matt */ public class Recaf { - public static final String VERSION = "2.21.13"; + public static final String VERSION = "2.21.14"; public static final String DOC_URL = "https://col-e.github.io/Recaf-documentation/"; public static final int ASM_VERSION = Opcodes.ASM9; private static Controller currentController; @@ -108,7 +108,6 @@ private static void launch(String[] args) { loadPlugins(); // Do version check SelfUpdater.setController(initializer.getController()); - SelfUpdater.setArgs(args); SelfUpdater.checkForUpdates(); // Start the initializer's controller, starting Recaf initializer.startController(); diff --git a/src/main/java/me/coley/recaf/parse/source/WorkspaceTypeResolver.java b/src/main/java/me/coley/recaf/parse/source/WorkspaceTypeResolver.java index 27d8eae1a..ef0cb5847 100644 --- a/src/main/java/me/coley/recaf/parse/source/WorkspaceTypeResolver.java +++ b/src/main/java/me/coley/recaf/parse/source/WorkspaceTypeResolver.java @@ -1,8 +1,8 @@ package me.coley.recaf.parse.source; +import com.github.javaparser.resolution.TypeSolver; import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; -import com.github.javaparser.symbolsolver.model.resolution.SymbolReference; -import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.resolution.model.SymbolReference; import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import javassist.*; diff --git a/src/main/java/me/coley/recaf/ui/MainMenu.java b/src/main/java/me/coley/recaf/ui/MainMenu.java index 2aca0d3cc..90d4e6bf3 100644 --- a/src/main/java/me/coley/recaf/ui/MainMenu.java +++ b/src/main/java/me/coley/recaf/ui/MainMenu.java @@ -128,11 +128,6 @@ public MainMenu(GuiController controller) { mHistory.getItems().add(new ActionMenuItem(translate("misc.open"), this::showHistory)); } mHelp = new Menu(translate("ui.menubar.help")); - if (SelfUpdater.hasUpdate()) { - mHelp.getItems().add(0, - new ActionMenuItem(translate("ui.menubar.help.update") + SelfUpdater.getLatestVersion(), - this::showUpdatePrompt)); - } mHelp.getItems().addAll( new ActionMenuItem(translate("ui.menubar.help.documentation"), this::showDocumentation), new ActionMenuItem(translate("ui.menubar.help.info"), this::showInformation), @@ -408,17 +403,6 @@ private void applyTinyV2Map(TinyV2Mappings.TinyV2SubType subType) { } } - /** - * Show update prompt. - */ - public void showUpdatePrompt() { - Stage stage = controller.windows() - .window(translate("ui.menubar.help.update") + SelfUpdater.getLatestVersion(), - new UpdatePane(controller)); - stage.show(); - stage.toFront(); - } - /** * Display history window. */ diff --git a/src/main/java/me/coley/recaf/ui/MainWindow.java b/src/main/java/me/coley/recaf/ui/MainWindow.java index 48b19314f..869938cd7 100644 --- a/src/main/java/me/coley/recaf/ui/MainWindow.java +++ b/src/main/java/me/coley/recaf/ui/MainWindow.java @@ -2,27 +2,33 @@ import javafx.application.Application; import javafx.application.Platform; +import javafx.geometry.Insets; import javafx.geometry.Orientation; +import javafx.geometry.Pos; +import javafx.scene.Group; +import javafx.scene.Node; import javafx.scene.Scene; +import javafx.scene.control.ScrollPane; import javafx.scene.control.SplitPane; +import javafx.scene.control.Tab; import javafx.scene.image.Image; import javafx.scene.layout.BorderPane; +import javafx.scene.layout.StackPane; import javafx.stage.Stage; import me.coley.recaf.Recaf; import me.coley.recaf.control.gui.GuiController; import me.coley.recaf.plugin.PluginsManager; import me.coley.recaf.plugin.api.InternalPlugin; import me.coley.recaf.plugin.api.WorkspacePlugin; +import me.coley.recaf.ui.controls.MarkdownView; import me.coley.recaf.ui.controls.ViewportTabs; import me.coley.recaf.ui.controls.WorkspaceNavigator; -import me.coley.recaf.ui.controls.popup.UpdateWindow; import me.coley.recaf.ui.controls.view.ClassViewport; import me.coley.recaf.ui.controls.view.FileViewport; import me.coley.recaf.util.OSUtil; import me.coley.recaf.util.ThreadUtil; import me.coley.recaf.util.UiUtil; import me.coley.recaf.util.VMUtil; -import me.coley.recaf.util.self.SelfUpdater; import me.coley.recaf.workspace.InstrumentationResource; import me.coley.recaf.workspace.JavaResource; import me.coley.recaf.workspace.Workspace; @@ -92,9 +98,62 @@ private void setup() { controller.windows().reapplyStyle(scene); controller.config().keys().registerMainWindowKeys(controller, stage, scene); stage.setScene(scene); - // Show update prompt - if (SelfUpdater.hasUpdate()) - UpdateWindow.create(this).show(root); + // Display notice of future versions + tabs.getTabs().add(new Tab("Recaf 4.0.0", generateFutureVersionNotice())); + } + + private Node generateFutureVersionNotice() { + String notice = "# Recaf 4.0.0: New major update\n" + + "\n" + + "You are currently using Recaf 2.21, which was last updated on March 29th 2022. Since then the team behind Recaf has been working on a large number of new features and major overhauls to existing ones. This list is not dynamically updated, so the later you read this the more additional content will be added that is not described in the following lists:\n" + + "\n" + + "### New Features\n" + + "\n" + + "- Completely new backend design which allows much more control for plugin developers\n" + + "- Lightweight *\"plugins\"* in the form of single-Java source scripts that are editable on the fly\n" + + " - Like plugins, they can interact with all of Recaf's features, but they are limited to what you can put into a single `.java` source file.\n" + + "- Dedicated code documentation capabilities\n" + + " - Write comments on classes, fields, and methods in plain text\n" + + " - See the comments you write as JavaDoc in decompiled code\n" + + " - Persistent without actually modifying the contents of the classes you're documenting\n" + + "- View the type hierarchy of classes as a tree of child and parent types\n" + + "- View the graph of which methods call other methods\n" + + "\n" + + "### Improvements\n" + + "\n" + + "- An improved layout & new dark-themed user interface style via AtlantaFX\n" + + " - The class modes of `Decompile` and `Table` are now merged into one with decompilation on the left, and the list of fields and methods in a collapsible tab to the right\n" + + " - New docking framework support, allowing the display of multiple tabs of content all at once\n" + + "- An improved assembler system backed by JASM\n" + + " - Support for editing the entire class bytecode all at once instead of per method\n" + + " - Support for additional attributes being editable from within the assembler such as attached annotations\n" + + " - UI for converting blocks of Java source code into JASM assembler code *(Serving to replace the `EXPR` keyword)*\n" + + "- More flexible search options\n" + + "- More support for patching obfuscated JAR/ZIP files designed to crash common RE tools\n" + + "- More support for patching obfuscated classes designed to crash ASM and other bytecode parsing libraries\n" + + "- Redesigned internal structure to allow more control for plugin development\n" + + "\n" + + "## Download & Getting It\n" + + "\n" + + "The new major version of Recaf 4.X will be uploaded to [the GitHub releases page](https://github.com/Col-E/Recaf/releases). \n" + + "\n" + + "**Requirements**:\n" + + "\n" + + "- Java 22 or higher\n" + + "- JavaFX 21 or higher\n" + + "\n" + + "You can either:\n" + + "- Use [the launcher](https://github.com/Col-E/Recaf-Launcher) that does everything for you\n" + + "- [Manually download Recaf + JavaFX](https://github.com/Col-E/Recaf-Launcher/blob/master/MANUAL.md)\n" + + "\n" + + "## Regarding support for 2.X\n" + + "\n" + + "There will be no support for 2.X going forward from here. For new features, bug fixes, and support you'll need to use Recaf 4.X."; + ScrollPane noticeWrapper = new ScrollPane(new MarkdownView(notice)); + noticeWrapper.setPadding(new Insets(15)); + noticeWrapper.setFitToWidth(true); + noticeWrapper.setFitToHeight(true); + return noticeWrapper; } private void updateWorkspaceNavigator() { diff --git a/src/main/java/me/coley/recaf/ui/controls/MarkdownView.java b/src/main/java/me/coley/recaf/ui/controls/MarkdownView.java new file mode 100644 index 000000000..bfe88af6e --- /dev/null +++ b/src/main/java/me/coley/recaf/ui/controls/MarkdownView.java @@ -0,0 +1,315 @@ +package me.coley.recaf.ui.controls; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.css.PseudoClass; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.layout.*; +import javafx.scene.text.Text; +import javafx.scene.text.TextFlow; +import me.coley.recaf.util.Log; +import me.coley.recaf.util.UiUtil; +import org.commonmark.node.*; +import org.commonmark.parser.Parser; + +import javax.annotation.Nullable; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Displays markdown text. + *
+ * Adapted from MDFX, + * which couldn't be used directly in order to support targeting Java 8. Some minor changes to the visitor internals were also made. + */ +public class MarkdownView extends BorderPane { + private final static String ITALICE_CLASS_NAME = "italic"; + private final static String BOLD_CLASS_NAME = "bold"; + private static final PseudoClass PSEUDO_HOVER = PseudoClass.getPseudoClass("hover"); + // State + private VBox root = newVBox(); + private TextFlow flow = null; + + public MarkdownView(String markdown) { + Parser parser = Parser.builder().build(); + Document document = (Document) parser.parse(markdown); + document.accept(new AbstractVisitor() { + private boolean nodePerWord; + private boolean isListOrdered; + private int listCounter; + + @Override + public void visit(Document document) { + visitChildren(document); + } + + @Override + public void visit(BlockQuote customBlock) { + VBox oldRoot = root; + root = newVBox(); + root.getStyleClass().add("block-quote"); + oldRoot.getChildren().add(root); + + visitChildren(customBlock); + + root = oldRoot; + newParagraph(); + } + + @Override + public void visit(Code code) { + Label label = new Label(code.getLiteral()); + label.getStyleClass().add("code"); + + Region background = new Region(); + background.setManaged(false); + background.getStyleClass().add("code-background"); + label.boundsInParentProperty().addListener((p, oldV, newV) -> { + background.setTranslateX(newV.getMinX() + 2); + background.setTranslateY(newV.getMinY() - 2); + background.resize(newV.getWidth() - 4, newV.getHeight() + 4); + }); + + flow.getChildren().add(background); + flow.getChildren().add(label); + } + + @Override + public void visit(FencedCodeBlock code) { + Label label = new Label(code.getLiteral()); + label.getStyleClass().add("codeblock"); + + VBox vbox = newVBox(); + vbox.getChildren().add(label); + vbox.getStyleClass().add("codeblock-background"); + + root.getChildren().add(vbox); + } + + @Override + public void visit(SoftLineBreak softLineBreak) { + flow.getChildren().add(new Text("\n")); + visitChildren(softLineBreak); + } + + @Override + public void visit(HardLineBreak hardLineBreak) { + newParagraph(); + flow.getChildren().add(new Text("\n")); + visitChildren(hardLineBreak); + } + + @Override + public void visit(Heading heading) { + newParagraph(); + flow.getStyleClass().add("h" + heading.getLevel()); + visitChildren(heading); + } + + @Override + public void visit(Paragraph paragraph) { + newParagraph(); + flow.getStyleClass().add("p"); + visitChildren(paragraph); + } + + @Override + public void visit(BulletList bulletList) { + isListOrdered = false; + visitList(bulletList); + } + + @Override + public void visit(OrderedList orderedList) { + isListOrdered = true; + visitList(orderedList); + } + + private void visitList(ListBlock list) { + // Copy state + boolean prevIsListOrdered = isListOrdered; + int prevListDepth = listCounter; + isListOrdered = false; + VBox oldRoot = root; + + // Visit children + root = newVBox(); + oldRoot.getChildren().add(root); + newParagraph(); + visitChildren(list); + + // Restore + isListOrdered = prevIsListOrdered; + listCounter = prevListDepth; + root = oldRoot; + } + + @Override + public void visit(ListItem listItem) { + VBox oldRoot = root; + + VBox newRoot = newVBox(); + newRoot.getStyleClass().add("li"); + newRoot.setFillWidth(true); + + listCounter += 1; + + String text = isListOrdered ? (" " + (listCounter + 1) + ". ") : " • "; + + Label dot = new Label(text); + dot.getStyleClass().add("li-dot"); + + HBox hbox = new HBox(); + hbox.getChildren().add(dot); + hbox.setAlignment(Pos.TOP_LEFT); + HBox.setHgrow(newRoot, Priority.ALWAYS); + newRoot.setPrefWidth(1.0); // This way, it doesn't take space from the "dot" label + hbox.getChildren().add(newRoot); + + oldRoot.getChildren().add(hbox); + + root = newRoot; + + visitChildren(listItem); + root = oldRoot; + } + + @Override + public void visit(Link link) { + // Save state and update + boolean oldNodePerWord = nodePerWord; + nodePerWord = true; + + TextFlow currentFlow = flow; + int childIndex = currentFlow.getChildren().size(); + visitChildren(link); + int newChildIndex = currentFlow.getChildren().size(); + + List linkNodes = new ArrayList<>(currentFlow.getChildren().subList(childIndex, newChildIndex)); + BooleanProperty lastHoverState = new SimpleBooleanProperty(false); + Runnable updateState = () -> { + boolean isHover = false; + for (Node node : linkNodes) { + if (node.isHover()) { + isHover = true; + } + } + if (isHover != lastHoverState.get()) { + lastHoverState.set(isHover); + for (Node node : linkNodes) { + node.pseudoClassStateChanged(PSEUDO_HOVER, isHover); + } + } + }; + String url = link.getDestination(); + for (Node node : linkNodes) { + node.getStyleClass().add("a"); + node.setOnMousePressed(e -> { + try { + UiUtil.showDocument(new URL(url).toURI()); + } catch (Exception ex) { + Log.error("Could not open URL: " + url); + } + }); + node.setCursor(Cursor.HAND); + node.hoverProperty().addListener((ob, old, cur) -> updateState.run()); + updateState.run(); + } + + // Restore + nodePerWord = oldNodePerWord; + } + + + @Override + public void visit(Emphasis emphasis) { + TextFlow currentFlow = flow; + int childIndex = currentFlow.getChildren().size(); + visitChildren(emphasis); + int newChildIndex = currentFlow.getChildren().size(); + + List emphasisNodes = new ArrayList<>(currentFlow.getChildren().subList(childIndex, newChildIndex)); + for (Node node : emphasisNodes) { + node.getStyleClass().add(ITALICE_CLASS_NAME); + } + } + + @Override + public void visit(StrongEmphasis strongEmphasis) { + TextFlow currentFlow = flow; + int childIndex = currentFlow.getChildren().size(); + visitChildren(strongEmphasis); + int newChildIndex = currentFlow.getChildren().size(); + + List emphasisNodes = new ArrayList<>(currentFlow.getChildren().subList(childIndex, newChildIndex)); + for (Node node : emphasisNodes) { + node.getStyleClass().add(BOLD_CLASS_NAME); + } + } + + @Override + public void visit(org.commonmark.node.Text text) { + String wholeText = text.getLiteral(); + + String[] textsSplit; + if (nodePerWord) { + // Split with " " but keep the " " in the array + textsSplit = wholeText.split("(?<= )"); + // Combine split texts, which only contain a space: + for (int i = 0; i <= textsSplit.length - 1; i += 1) { + if (textsSplit[i].equals(" ")) { + if (i == 0) { + if (i + 1 <= textsSplit.length - 1) { + textsSplit[i + 1] = " " + textsSplit[i + 1]; + textsSplit[i] = ""; + } + } else { + textsSplit[i - 1] = textsSplit[i - 1] + textsSplit[i]; + textsSplit[i] = ""; + } + } + } + } else { + textsSplit = new String[1]; + textsSplit[0] = wholeText; + } + final String[] textSplitfinal = textsSplit; + + for (int i = 0; i <= textsSplit.length - 1; i += 1) { + if (!textSplitfinal[i].isEmpty()) { + addText(textSplitfinal[i]); + } + } + } + }); + getStyleClass().add("content"); + setCenter(root); + } + + @Nullable + public Text addText(String text) { + if (!text.isEmpty()) { + Text t = new Text(text); + t.getStyleClass().add("text"); + flow.getChildren().add(t); + return t; + } + return null; + } + + public TextFlow newParagraph() { + TextFlow newFlow = new TextFlow(); + root.getChildren().add(newFlow); + flow = newFlow; + return newFlow; + } + + private VBox newVBox() { + return new VBox(); + } +} diff --git a/src/main/java/me/coley/recaf/ui/controls/SplitableTabPane.java b/src/main/java/me/coley/recaf/ui/controls/SplitableTabPane.java index bd753b23e..9313ef1d4 100644 --- a/src/main/java/me/coley/recaf/ui/controls/SplitableTabPane.java +++ b/src/main/java/me/coley/recaf/ui/controls/SplitableTabPane.java @@ -36,6 +36,7 @@ public class SplitableTabPane extends TabPane { */ public SplitableTabPane() { TabPane selfPane = this; + /* Disabled in the 2.21.14 update because the splitting logic is garbage. 4x docking is leagues better. // Allow this pane to accept transfers setOnDragOver(dragEvent -> { Dragboard dragboard = dragEvent.getDragboard(); @@ -112,7 +113,7 @@ public SplitableTabPane() { && draggedTab.get().getTabPane() != selfPane) { removeStyle(); } - }); + });*/ } /** diff --git a/src/main/java/me/coley/recaf/ui/controls/pane/UpdatePane.java b/src/main/java/me/coley/recaf/ui/controls/pane/UpdatePane.java deleted file mode 100644 index 687509439..000000000 --- a/src/main/java/me/coley/recaf/ui/controls/pane/UpdatePane.java +++ /dev/null @@ -1,192 +0,0 @@ -package me.coley.recaf.ui.controls.pane; - -import javafx.geometry.Insets; -import javafx.scene.control.Button; -import javafx.scene.control.Hyperlink; -import javafx.scene.control.Label; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.TextFlow; -import me.coley.recaf.control.gui.GuiController; -import me.coley.recaf.ui.controls.ActionButton; -import me.coley.recaf.ui.controls.ExceptionAlert; -import me.coley.recaf.util.Log; -import me.coley.recaf.util.UiUtil; -import me.coley.recaf.util.self.SelfUpdater; -import org.commonmark.node.*; -import org.commonmark.parser.Parser; - -import java.io.IOException; -import java.net.URL; -import java.util.function.Consumer; - -import static me.coley.recaf.util.LangUtil.translate; - -/** - * Panel that shows update information. - * - * @author Matt - */ -public class UpdatePane extends BorderPane { - private final GuiController controller; - - /** - * @param controller - * Controller to use to close Recaf. - */ - public UpdatePane(GuiController controller) { - this.controller = controller; - Button btn = getButton(); - GridPane grid = new GridPane(); - GridPane.setFillHeight(btn, true); - GridPane.setFillWidth(btn, true); - grid.setMaxWidth(800); - grid.setPadding(new Insets(10)); - grid.setVgap(10); - grid.setHgap(10); - grid.add(getNotes(), 0, 0, 2, 1); - grid.add(getInfo(), 0, 1, 1, 1); - grid.add(btn, 1, 1, 1, 1); - grid.add(getSubMessage(), 0, 2, 2, 1); - setTop(getHeader()); - setCenter(grid); - } - - private BorderPane getHeader() { - Label header = new Label("Recaf: " + SelfUpdater.getLatestVersion()); - header.getStyleClass().add("h1"); - BorderPane pane = new BorderPane(header); - pane.getStyleClass().add("update-header"); - return pane; - } - - private BorderPane getNotes() { - TextFlow flow = new TextFlow(); - Parser parser = Parser.builder().build(); - Node document = parser.parse(SelfUpdater.getLatestPatchnotes()); - document.accept(new AbstractVisitor() { - @Override - public void visit(Paragraph paragraph) { - // Add all content to same line - parse(paragraph, this::text, this::link); - newLine(); - } - - @Override - public void visit(Heading heading) { - // Skip the version H2 text - if (heading.getLevel() <= 2) - return; - // Extract heading text - StringBuilder sb = new StringBuilder(); - parse(heading, text -> sb.append(text.getLiteral()), null); - // Render - addText(sb.toString(), "h2"); - newLine(); - } - - @Override - public void visit(BulletList list) { - Node item = list.getFirstChild(); - do { - // Prefix with bullet point - addText(" ● ", null); - // Add all content to same line - parse(item, this::text, this::link); - // New line between items - newLine(); - item = item.getNext(); - } while (item != null); - } - - private void text(Text text) { - addText(text.getLiteral(), null); - } - - private void link(Link link) { - String text = link.getTitle(); - if (text == null) { - StringBuilder sb = new StringBuilder(); - parse(link, t -> sb.append(t.getLiteral()), null); - text = sb.toString(); - } - addLink(text, link.getDestination()); - } - - private void parse(Node node, Consumer textHandler, Consumer linkHandler) { - if (node instanceof Text) { - if (textHandler != null) textHandler.accept((Text) node); - } else if (linkHandler != null && node instanceof Link) { - linkHandler.accept((Link) node); - } else { - Node child = node.getFirstChild(); - do { - parse(child, textHandler, linkHandler); - child = child.getNext(); - } while (child != null); - } - } - - private void addLink(String text, String url) { - Hyperlink link = new Hyperlink(text); - link.getStyleClass().add("a"); - link.setOnAction(e -> { - try { - UiUtil.showDocument(new URL(url).toURI()); - } catch (Exception ex) { - Log.error("Could not open URL: " + url); - } - }); - flow.getChildren().add(link); - } - - private void addText(String text, String style) { - javafx.scene.text.Text t = new javafx.scene.text.Text(text); - if (style != null) - t.getStyleClass().add(style); - flow.getChildren().add(t); - } - - private void newLine() { - javafx.scene.text.Text t = new javafx.scene.text.Text("\n"); - flow.getChildren().add(t); - } - }); - BorderPane pane = new BorderPane(flow); - pane.getStyleClass().add("content"); - pane.getStyleClass().add("update-notes"); - return pane; - } - - private Label getSubMessage() { - Label label = new Label(translate("update.consent")); - label.getStyleClass().add("faint"); - return label; - } - - private VBox getInfo() { - VBox box = new VBox(); - int sizeInMg = SelfUpdater.getLatestArtifactSize() / 1000000; - box.getChildren().addAll(new Label("Size: " + sizeInMg + " MB"), - new Label("Date: " + SelfUpdater.getLatestVersionDate().toString())); - return box; - } - - private Button getButton() { - Button button = new ActionButton(translate("update.download"), this::update); - button.setMaxHeight(Double.MAX_VALUE); - button.setMaxWidth(Double.MAX_VALUE); - return button; - } - - private void update() { - try { - SelfUpdater.updateRecaf(); - controller.exit(); - } catch (IOException ex) { - Log.error(ex, "Failed to start update process"); - ExceptionAlert.show(ex, "Recaf failed to start the update process"); - } - } -} diff --git a/src/main/java/me/coley/recaf/ui/controls/popup/UpdateWindow.java b/src/main/java/me/coley/recaf/ui/controls/popup/UpdateWindow.java deleted file mode 100644 index 682a3de73..000000000 --- a/src/main/java/me/coley/recaf/ui/controls/popup/UpdateWindow.java +++ /dev/null @@ -1,52 +0,0 @@ -package me.coley.recaf.ui.controls.popup; - -import javafx.geometry.HPos; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Control; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; -import me.coley.recaf.Recaf; -import me.coley.recaf.ui.MainWindow; -import me.coley.recaf.ui.controls.ActionButton; -import me.coley.recaf.util.self.SelfUpdater; - -import static me.coley.recaf.util.LangUtil.translate; - -/** - * Update popup window. - * - * @author Matt - */ -public class UpdateWindow extends DragPopup { - private UpdateWindow(Node content, Control handle) { - super(content, handle); - } - - /** - * @param window - * Window reference to handle UI access. - * - * @return Update popup. - */ - public static UpdateWindow create(MainWindow window) { - Label lblTitle = new Label(translate("update.outdated")); - Label lblVersion = new Label(Recaf.VERSION + " → " + SelfUpdater.getLatestVersion()); - Label lblDate = new Label(SelfUpdater.getLatestVersionDate().toString()); - lblTitle.getStyleClass().add("h1"); - lblDate.getStyleClass().add("faint"); - GridPane grid = new GridPane(); - GridPane.setHalignment(lblVersion, HPos.CENTER); - GridPane.setHalignment(lblDate, HPos.CENTER); - grid.setPadding(new Insets(15)); - grid.setHgap(10); - grid.setVgap(10); - grid.setAlignment(Pos.CENTER); - grid.add(new Label(translate("update.available")), 0, 0); - grid.add(new ActionButton(translate("misc.open"), () -> window.getMenubar().showUpdatePrompt()), 1, 0); - grid.add(lblVersion, 0, 1, 2, 1); - grid.add(lblDate, 0, 2, 2, 1); - return new UpdateWindow(grid, lblTitle); - } -} diff --git a/src/main/java/me/coley/recaf/util/IllegalBytecodePatcherUtil.java b/src/main/java/me/coley/recaf/util/IllegalBytecodePatcherUtil.java index 7321bcbcf..fc32e7c1c 100644 --- a/src/main/java/me/coley/recaf/util/IllegalBytecodePatcherUtil.java +++ b/src/main/java/me/coley/recaf/util/IllegalBytecodePatcherUtil.java @@ -1,11 +1,11 @@ package me.coley.recaf.util; -import me.coley.cafedude.classfile.ClassFile; -import me.coley.cafedude.io.ClassFileReader; -import me.coley.cafedude.io.ClassFileWriter; +import software.coley.cafedude.classfile.ClassFile; +import software.coley.cafedude.io.ClassFileReader; +import software.coley.cafedude.io.ClassFileWriter; import java.util.Map; -import me.coley.cafedude.transform.IllegalStrippingTransformer; +import software.coley.cafedude.transform.IllegalStrippingTransformer; /** * Utility to attempt basic recovery of classes that crash ASM. diff --git a/src/main/java/me/coley/recaf/util/JavaParserUtil.java b/src/main/java/me/coley/recaf/util/JavaParserUtil.java index 56a0ca43a..1d60e64ce 100644 --- a/src/main/java/me/coley/recaf/util/JavaParserUtil.java +++ b/src/main/java/me/coley/recaf/util/JavaParserUtil.java @@ -266,7 +266,7 @@ public static String getDescriptor(ResolvedFieldDeclaration type) { * @return Descriptor of the resolved method. */ public static String getDescriptor(ResolvedMethodDeclaration type) { - Optional ast = type.toAst(); + Optional ast = type.toAst(MethodDeclaration.class); String desc = null; if (ast.isPresent()) { desc = getDescriptor(ast.get()); diff --git a/src/main/java/me/coley/recaf/util/self/SelfUpdater.java b/src/main/java/me/coley/recaf/util/self/SelfUpdater.java index 143a11182..6fe1f19c1 100644 --- a/src/main/java/me/coley/recaf/util/self/SelfUpdater.java +++ b/src/main/java/me/coley/recaf/util/self/SelfUpdater.java @@ -32,23 +32,6 @@ public class SelfUpdater { private static Instant latestVersionDate; private static int latestArtifactSize; private static Controller controller; - private static String[] args; - - /** - * Start the update process. - * - * @throws IOException - * When starting the update task fails. - */ - public static void updateRecaf() throws IOException { - // Skip if no updates - if (!hasUpdate()) - return; - String path = SelfReferenceUtil.get().getPath().replace(currentVersion, latestVersion); - Log.info("Start update: '{}' ==> '{}'", latestVersion, path); - UpdateTaskStarter starter = new UpdateTaskStarter(path, latestArtifact, UPDATER_START_DELAY_MS, args); - starter.start(); - } /** * Fetch latest update information. @@ -163,15 +146,6 @@ public static void setController(Controller controller) { SelfUpdater.controller = controller; } - /** - * @param args - * Launch arguments to pass to Recaf instance. - */ - public static void setArgs(String[] args) { - // Copy arguments - SelfUpdater.args = args; - } - /** * Disable update checks. */ diff --git a/src/main/java/me/coley/recaf/util/self/UpdateTaskStarter.java b/src/main/java/me/coley/recaf/util/self/UpdateTaskStarter.java deleted file mode 100644 index 064b5a425..000000000 --- a/src/main/java/me/coley/recaf/util/self/UpdateTaskStarter.java +++ /dev/null @@ -1,277 +0,0 @@ -package me.coley.recaf.util.self; - -import me.coley.recaf.Recaf; -import org.objectweb.asm.*; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * Creates an independent update script and executes it. - * - * @author Matt - */ -public class UpdateTaskStarter implements Opcodes { - private static final String CLASS_NAME = "UpdateRunner"; - private final String filePath; - private final String url; - private final long delay; - private final String[] args; - - /** - * @param filePath - * Destination of downloaded artifact. - * @param url - * Artifact url to download. - * @param delay - * Delay before starting download. - * @param args - * Arguments to pass to downloaded artifact. - */ - public UpdateTaskStarter(String filePath, String url, long delay, String[] args) { - this.filePath = filePath; - this.url = url; - this.delay = delay; - this.args = args; - } - - /** - * Start the updater. - * - * @throws IOException - * When the update runner class cannot be written to, - * or when the process failed to start. - */ - public void start() throws IOException { - // Write updater class - Path updaterPath = Recaf.getDirectory().resolve(CLASS_NAME +".class"); - Files.write(updaterPath, dump(), StandardOpenOption.CREATE); - // Execute - List procArgs = new LinkedList<>(); - procArgs.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); - procArgs.add("-cp"); - procArgs.add(Recaf.getDirectory().toString()); - procArgs.add(CLASS_NAME); - if (args != null) - Collections.addAll(procArgs, args); - new ProcessBuilder(procArgs).start(); - } - - /** - * Auto-generated code by ASMifier, slightly modified. - * - * @return Bytecode of runner class. - */ - private byte[] dump() { - // This is the original method code that we will be writing to a file. - /* - public static void main(String[] args) throws Throwable { - // Wait - Thread.sleep(DELAY_HERE); - // Download - String pathStr = "FILE_PATH_HERE"; - try(InputStream is = new URL("URL_HERE").openStream()) { - Files.copy(is, Paths.get(pathStr), StandardCopyOption.REPLACE_EXISTING); - } - // Execute downloaded jar - List procArgs = new ArrayList<>(); - procArgs.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); - procArgs.add("-jar"); - procArgs.add(pathStr); - Collections.addAll(procArgs, args); - new ProcessBuilder(procArgs).start(); - } - */ - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(50, ACC_PUBLIC + ACC_SUPER, CLASS_NAME, null, "java/lang/Object", null); - // Constructor - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 1); - mv.visitEnd(); - // Main method - mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, - new String[]{"java/lang/Throwable"}); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable"); - Label l3 = new Label(); - Label l4 = new Label(); - Label l5 = new Label(); - mv.visitTryCatchBlock(l3, l4, l5, "java/lang/Throwable"); - Label l6 = new Label(); - mv.visitTryCatchBlock(l3, l4, l6, null); - Label l7 = new Label(); - Label l8 = new Label(); - Label l9 = new Label(); - mv.visitTryCatchBlock(l7, l8, l9, "java/lang/Throwable"); - Label l10 = new Label(); - mv.visitTryCatchBlock(l5, l10, l6, null); - Label l11 = new Label(); - mv.visitLabel(l11); - mv.visitLineNumber(16, l11); - mv.visitLdcInsn(delay); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "sleep", "(J)V", false); - Label l12 = new Label(); - mv.visitLabel(l12); - mv.visitLineNumber(18, l12); - mv.visitLdcInsn(filePath); - mv.visitVarInsn(ASTORE, 1); - Label l13 = new Label(); - mv.visitLabel(l13); - mv.visitLineNumber(19, l13); - mv.visitTypeInsn(NEW, "java/net/URL"); - mv.visitInsn(DUP); - mv.visitLdcInsn(url); - mv.visitMethodInsn(INVOKESPECIAL, "java/net/URL", "", "(Ljava/lang/String;)V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/net/URL", "openStream", "()Ljava/io/InputStream;", false); - mv.visitVarInsn(ASTORE, 2); - Label l14 = new Label(); - mv.visitLabel(l14); - mv.visitInsn(ACONST_NULL); - mv.visitVarInsn(ASTORE, 3); - mv.visitLabel(l3); - mv.visitLineNumber(20, l3); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(ICONST_0); - mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); - mv.visitMethodInsn(INVOKESTATIC, "java/nio/file/Paths", "get", - "(Ljava/lang/String;[Ljava/lang/String;)Ljava/nio/file/Path;", false); - mv.visitInsn(ICONST_1); - mv.visitTypeInsn(ANEWARRAY, "java/nio/file/CopyOption"); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_0); - mv.visitFieldInsn(GETSTATIC, "java/nio/file/StandardCopyOption", "REPLACE_EXISTING", - "Ljava/nio/file/StandardCopyOption;"); - mv.visitInsn(AASTORE); - mv.visitMethodInsn(INVOKESTATIC, "java/nio/file/Files", "copy", - "(Ljava/io/InputStream;Ljava/nio/file/Path;[Ljava/nio/file/CopyOption;)J", false); - mv.visitInsn(POP2); - mv.visitLabel(l4); - mv.visitLineNumber(21, l4); - mv.visitVarInsn(ALOAD, 2); - Label l15 = new Label(); - mv.visitJumpInsn(IFNULL, l15); - mv.visitVarInsn(ALOAD, 3); - Label l16 = new Label(); - mv.visitJumpInsn(IFNULL, l16); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", "close", "()V", false); - mv.visitLabel(l1); - mv.visitJumpInsn(GOTO, l15); - mv.visitLabel(l2); - mv.visitVarInsn(ASTORE, 4); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "addSuppressed", - "(Ljava/lang/Throwable;)V", false); - mv.visitJumpInsn(GOTO, l15); - mv.visitLabel(l16); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", "close", "()V", false); - mv.visitJumpInsn(GOTO, l15); - mv.visitLabel(l5); - mv.visitLineNumber(19, l5); - mv.visitVarInsn(ASTORE, 4); - mv.visitVarInsn(ALOAD, 4); - mv.visitVarInsn(ASTORE, 3); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(ATHROW); - mv.visitLabel(l6); - mv.visitLineNumber(21, l6); - mv.visitVarInsn(ASTORE, 5); - mv.visitLabel(l10); - mv.visitVarInsn(ALOAD, 2); - Label l17 = new Label(); - mv.visitJumpInsn(IFNULL, l17); - mv.visitVarInsn(ALOAD, 3); - Label l18 = new Label(); - mv.visitJumpInsn(IFNULL, l18); - mv.visitLabel(l7); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", "close", "()V", false); - mv.visitLabel(l8); - mv.visitJumpInsn(GOTO, l17); - mv.visitLabel(l9); - mv.visitVarInsn(ASTORE, 6); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ALOAD, 6); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "addSuppressed", - "(Ljava/lang/Throwable;)V", false); - mv.visitJumpInsn(GOTO, l17); - mv.visitLabel(l18); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", "close", "()V", false); - mv.visitLabel(l17); - mv.visitVarInsn(ALOAD, 5); - mv.visitInsn(ATHROW); - mv.visitLabel(l15); - mv.visitLineNumber(23, l15); - mv.visitTypeInsn(NEW, "java/util/ArrayList"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "", "()V", false); - mv.visitVarInsn(ASTORE, 2); - mv.visitVarInsn(ALOAD, 2); - mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false); - mv.visitLdcInsn("java.home"); - mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "getProperty", - "(Ljava/lang/String;)Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", - "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitFieldInsn(GETSTATIC, "java/io/File", "separator", "Ljava/lang/String;"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", - "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitLdcInsn("bin"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", - "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitFieldInsn(GETSTATIC, "java/io/File", "separator", "Ljava/lang/String;"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", - "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitLdcInsn("java"); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", - "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", - "()Ljava/lang/String;", false); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true); - mv.visitInsn(POP); - mv.visitVarInsn(ALOAD, 2); - mv.visitLdcInsn("-jar"); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true); - mv.visitInsn(POP); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true); - mv.visitInsn(POP); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections", "addAll", - "(Ljava/util/Collection;[Ljava/lang/Object;)Z", false); - mv.visitInsn(POP); - mv.visitTypeInsn(NEW, "java/lang/ProcessBuilder"); - mv.visitInsn(DUP); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ProcessBuilder", "", "(Ljava/util/List;)V", false); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ProcessBuilder", "start", "()Ljava/lang/Process;", false); - mv.visitInsn(POP); - mv.visitInsn(RETURN); - mv.visitMaxs(6, 7); - mv.visitEnd(); - cw.visitEnd(); - return cw.toByteArray(); - } -} diff --git a/src/main/java/me/coley/recaf/workspace/EntryLoader.java b/src/main/java/me/coley/recaf/workspace/EntryLoader.java index fdce61b68..3efd06061 100644 --- a/src/main/java/me/coley/recaf/workspace/EntryLoader.java +++ b/src/main/java/me/coley/recaf/workspace/EntryLoader.java @@ -1,7 +1,5 @@ package me.coley.recaf.workspace; -import me.coley.cafedude.InvalidClassException; -import me.coley.cafedude.io.ClassFileReader; import me.coley.recaf.plugin.PluginsManager; import me.coley.recaf.plugin.api.LoadInterceptorPlugin; import me.coley.recaf.util.ClassUtil; @@ -9,6 +7,8 @@ import me.coley.recaf.util.IllegalBytecodePatcherUtil; import me.coley.recaf.util.Log; import org.objectweb.asm.ClassReader; +import software.coley.cafedude.InvalidClassException; +import software.coley.cafedude.io.ClassFileReader; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/me/coley/recaf/workspace/PhantomResource.java b/src/main/java/me/coley/recaf/workspace/PhantomResource.java index b9ea6f105..06cc8aa07 100644 --- a/src/main/java/me/coley/recaf/workspace/PhantomResource.java +++ b/src/main/java/me/coley/recaf/workspace/PhantomResource.java @@ -12,12 +12,14 @@ import org.clyze.jphantom.access.FieldAccessStateMachine; import org.clyze.jphantom.access.MethodAccessStateMachine; import org.clyze.jphantom.adapters.ClassPhantomExtractor; +import org.clyze.jphantom.exc.IllegalBytecodeException; import org.clyze.jphantom.hier.ClassHierarchy; import org.clyze.jphantom.hier.IncrementalClassHierarchy; import org.objectweb.asm.*; import org.objectweb.asm.tree.ClassNode; import java.io.IOException; +import java.lang.reflect.Field; import java.util.*; /** @@ -95,14 +97,51 @@ public void populatePhantoms(Map classes) throws IOException { }); // Execute and populate the current resource with generated classes JPhantom phantom = new JPhantom(nodes, hierarchy, members); - phantom.run(); - phantom.getGenerated().forEach((k, v) -> getClasses().put(k.getInternalName(), decorate(v))); - Log.debug("Phantom analysis complete, generated {} classes", classes.size()); - // Cleanup - Phantoms.refresh(); - ClassAccessStateMachine.refresh(); - FieldAccessStateMachine.refresh(); - MethodAccessStateMachine.refresh(); + try { + int attempts = 10; + do { + attempts--; + try { + phantom.run(); + } catch (IllegalBytecodeException ex) { + try { + // Get type with the unhandled bytecode + Field offendingTypeField = IllegalBytecodeException.class.getDeclaredField("clazz"); + offendingTypeField.setAccessible(true); + Type type = (Type) offendingTypeField.get(ex); + + // Remove it from the input map + Log.warn("Failed handling {}", ex.getLocalizedMessage()); + nodes.remove(type); + + // Cleanup + Phantoms.refresh(); + ClassAccessStateMachine.refresh(); + FieldAccessStateMachine.refresh(); + MethodAccessStateMachine.refresh(); + + // And try again + continue; + } catch (Throwable t) { + // Cannot reflect offending type, do not try again. + attempts = 0; + } + + // If we got partial + Map generated = phantom.getGenerated(); + if (generated == null || generated.isEmpty()) + continue; + } + phantom.getGenerated().forEach((k, v) -> getClasses().put(k.getInternalName(), decorate(v))); + Log.debug("Phantom analysis complete, generated {} classes", classes.size()); + } while (attempts > 0); + } finally { + // Cleanup + Phantoms.refresh(); + ClassAccessStateMachine.refresh(); + FieldAccessStateMachine.refresh(); + MethodAccessStateMachine.refresh(); + } } /** diff --git a/src/main/java/me/coley/recaf/workspace/Workspace.java b/src/main/java/me/coley/recaf/workspace/Workspace.java index 2427d6ce4..8408b7705 100644 --- a/src/main/java/me/coley/recaf/workspace/Workspace.java +++ b/src/main/java/me/coley/recaf/workspace/Workspace.java @@ -3,8 +3,8 @@ import com.github.javaparser.ParseResult; import com.github.javaparser.ParserConfiguration; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.resolution.TypeSolver; import com.github.javaparser.symbolsolver.JavaSymbolSolver; -import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; import me.coley.recaf.Recaf; import me.coley.recaf.compiler.JavacCompiler; import me.coley.recaf.control.Controller; diff --git a/src/main/resources/style/base.css b/src/main/resources/style/base.css index 6f59895f7..ea3a20c02 100644 --- a/src/main/resources/style/base.css +++ b/src/main/resources/style/base.css @@ -3,17 +3,28 @@ * ========================= */ .h1 { - -fx-font-size: 18px; + -fx-font-size: 24px; -fx-font-weight: bold; } .h2 { - -fx-font-size: 15px; + -fx-font-size: 20px; -fx-font-weight: bold; } +.h3 { + -fx-font-size: 17px; + -fx-font-weight: bold; +} +.text { + -fx-fill: rgb(240, 245, 255); +} .a { -fx-underline: true; - -fx-text-fill: rgb(24, 101, 217); - -fx-fill: rgb(24, 101, 217); + -fx-text-fill: rgb(70, 129, 255); + -fx-fill: rgb(70, 129, 255); +} +.a:hover { + -fx-text-fill: rgb(121, 204, 255); + -fx-fill: rgb(121, 204, 255); } .bold { -fx-font-weight: bold; @@ -21,9 +32,23 @@ .underlined { -fx-underline: true; } +.italic { + -fx-font-style: italic; +} + .faint { -fx-fill: rgb(116, 116, 116); } +.code { + -fx-fill: rgb(166, 166, 166); + -fx-text-fill: rgb(166, 166, 166); + + -fx-background-color: rgb(22, 25, 30); + -fx-background-radius: 2; + -fx-border-width: 1; + -fx-border-radius: 2; + -fx-border-color: rgb(116, 116, 116); +} .no-border { -fx-border-width: 0; -fx-background-insets: -1;