diff options
| author | 2022-09-14 13:12:55 +0100 | |
|---|---|---|
| committer | 2022-09-14 13:12:55 +0100 | |
| commit | 9c736848fb7aa82d295b3aa2946e6cd132ee998f (patch) | |
| tree | b982613cfa7201b2db25cb64a5950f9a2c34a5b3 | |
| parent | Nested packages in Swing UI (#458) (diff) | |
| download | enigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.gz enigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.tar.xz enigma-9c736848fb7aa82d295b3aa2946e6cd132ee998f.zip | |
Add checkstyle (#460)
328 files changed, 7514 insertions, 6406 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..308508db --- /dev/null +++ b/.editorconfig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | [*.{gradle,java,kotlin}] | ||
| 2 | indent_style = tab | ||
| 3 | ij_continuation_indent_size = 8 | ||
| 4 | ij_java_imports_layout = $*, |, java.**, |, javax.**, |, *, |, cuchaz.enigma.** | ||
| 5 | ij_java_class_count_to_use_import_on_demand = 999 | ||
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 93a2e1fa..0abdf58e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | name: Build | 1 | name: Build |
| 2 | on: [push, pull_request] | 2 | on: [ push, pull_request ] |
| 3 | jobs: | 3 | jobs: |
| 4 | build: | 4 | build: |
| 5 | strategy: | 5 | strategy: |
| 6 | matrix: | 6 | matrix: |
| 7 | java: [17-jdk] | 7 | java: [ 17-jdk ] |
| 8 | runs-on: ubuntu-20.04 | 8 | runs-on: ubuntu-20.04 |
| 9 | container: | 9 | container: |
| 10 | image: openjdk:${{ matrix.java }} | 10 | image: openjdk:${{ matrix.java }} |
| @@ -13,3 +13,8 @@ jobs: | |||
| 13 | - uses: actions/checkout@v1 | 13 | - uses: actions/checkout@v1 |
| 14 | - uses: gradle/wrapper-validation-action@v1 | 14 | - uses: gradle/wrapper-validation-action@v1 |
| 15 | - run: ./gradlew build --stacktrace --warning-mode fail | 15 | - run: ./gradlew build --stacktrace --warning-mode fail |
| 16 | - uses: Juuxel/publish-checkstyle-report@v1 | ||
| 17 | if: ${{ failure() }} | ||
| 18 | with: | ||
| 19 | reports: | | ||
| 20 | **/build/reports/checkstyle/*.xml | ||
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48aacde3..9a4dc97d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | name: Release | 1 | name: Release |
| 2 | on: [workflow_dispatch] # Manual trigger | 2 | on: [ workflow_dispatch ] # Manual trigger |
| 3 | jobs: | 3 | jobs: |
| 4 | build: | 4 | build: |
| 5 | runs-on: ubuntu-20.04 | 5 | runs-on: ubuntu-20.04 |
| @@ -7,13 +7,14 @@ A tool for deobfuscation of Java bytecode. Forked from <https://bitbucket.org/cu | |||
| 7 | Enigma is distributed under the [LGPL-3.0](LICENSE). | 7 | Enigma is distributed under the [LGPL-3.0](LICENSE). |
| 8 | 8 | ||
| 9 | Enigma includes the following open-source libraries: | 9 | Enigma includes the following open-source libraries: |
| 10 | - A [modified version](https://github.com/FabricMC/procyon) of [Procyon](https://bitbucket.org/mstrobel/procyon) (Apache-2.0) | 10 | |
| 11 | - A [modified version](https://github.com/FabricMC/cfr) of [CFR](https://github.com/leibnitz27/cfr) (MIT) | 11 | - A [modified version](https://github.com/FabricMC/procyon) of [Procyon](https://bitbucket.org/mstrobel/procyon) (Apache-2.0) |
| 12 | - [Guava](https://github.com/google/guava) (Apache-2.0) | 12 | - A [modified version](https://github.com/FabricMC/cfr) of [CFR](https://github.com/leibnitz27/cfr) (MIT) |
| 13 | - [SyntaxPane](https://github.com/Sciss/SyntaxPane) (Apache-2.0) | 13 | - [Guava](https://github.com/google/guava) (Apache-2.0) |
| 14 | - [FlatLaf](https://github.com/JFormDesigner/FlatLaf) (Apache-2.0) | 14 | - [SyntaxPane](https://github.com/Sciss/SyntaxPane) (Apache-2.0) |
| 15 | - [jopt-simple](https://github.com/jopt-simple/jopt-simple) (MIT) | 15 | - [FlatLaf](https://github.com/JFormDesigner/FlatLaf) (Apache-2.0) |
| 16 | - [ASM](https://asm.ow2.io/) (BSD-3-Clause) | 16 | - [jopt-simple](https://github.com/jopt-simple/jopt-simple) (MIT) |
| 17 | - [ASM](https://asm.ow2.io/) (BSD-3-Clause) | ||
| 17 | 18 | ||
| 18 | ## Usage | 19 | ## Usage |
| 19 | 20 | ||
diff --git a/build.gradle b/build.gradle index 80cbd094..782d7ec5 100644 --- a/build.gradle +++ b/build.gradle | |||
| @@ -1,89 +1,95 @@ | |||
| 1 | plugins { | 1 | plugins { |
| 2 | id 'maven-publish' | 2 | id 'maven-publish' |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | subprojects { | 5 | subprojects { |
| 6 | apply plugin: 'java' | 6 | apply plugin: 'java' |
| 7 | apply plugin: 'maven-publish' | 7 | apply plugin: 'maven-publish' |
| 8 | 8 | apply plugin: 'checkstyle' | |
| 9 | sourceCompatibility = JavaVersion.VERSION_17 | 9 | |
| 10 | targetCompatibility = JavaVersion.VERSION_17 | 10 | sourceCompatibility = JavaVersion.VERSION_17 |
| 11 | 11 | targetCompatibility = JavaVersion.VERSION_17 | |
| 12 | repositories { | 12 | |
| 13 | mavenLocal() | 13 | repositories { |
| 14 | mavenCentral() | 14 | mavenLocal() |
| 15 | maven { url 'https://maven.fabricmc.net/' } | 15 | mavenCentral() |
| 16 | } | 16 | maven { url 'https://maven.fabricmc.net/' } |
| 17 | 17 | } | |
| 18 | dependencies { | 18 | |
| 19 | implementation 'com.google.guava:guava:30.1.1-jre' | 19 | dependencies { |
| 20 | implementation 'com.google.code.gson:gson:2.8.7' | 20 | implementation 'com.google.guava:guava:30.1.1-jre' |
| 21 | 21 | implementation 'com.google.code.gson:gson:2.8.7' | |
| 22 | testImplementation 'junit:junit:4.13.2' | 22 | |
| 23 | testImplementation 'org.hamcrest:hamcrest:2.2' | 23 | testImplementation 'junit:junit:4.13.2' |
| 24 | } | 24 | testImplementation 'org.hamcrest:hamcrest:2.2' |
| 25 | 25 | } | |
| 26 | group = 'cuchaz' | 26 | |
| 27 | version = '2.1.0' | 27 | group = 'cuchaz' |
| 28 | 28 | version = '2.1.1' | |
| 29 | version = version + (System.getenv("GITHUB_ACTIONS") ? "" : "+local") | 29 | |
| 30 | 30 | version = version + (System.getenv("GITHUB_ACTIONS") ? "" : "+local") | |
| 31 | task sourcesJar(type: Jar, dependsOn: classes) { | 31 | |
| 32 | classifier = 'sources' | 32 | task sourcesJar(type: Jar, dependsOn: classes) { |
| 33 | from sourceSets.main.allSource | 33 | classifier = 'sources' |
| 34 | } | 34 | from sourceSets.main.allSource |
| 35 | 35 | } | |
| 36 | java { | 36 | |
| 37 | withSourcesJar() | 37 | java { |
| 38 | } | 38 | withSourcesJar() |
| 39 | 39 | } | |
| 40 | tasks.withType(JavaCompile).configureEach { | 40 | |
| 41 | it.options.encoding = "UTF-8" | 41 | tasks.withType(JavaCompile).configureEach { |
| 42 | 42 | it.options.encoding = "UTF-8" | |
| 43 | it.options.release = 17 | 43 | |
| 44 | } | 44 | it.options.release = 17 |
| 45 | 45 | } | |
| 46 | publishing { | 46 | |
| 47 | publications { | 47 | checkstyle { |
| 48 | "$project.name"(MavenPublication) { | 48 | configFile = rootProject.file('checkstyle.xml') |
| 49 | groupId project.group | 49 | toolVersion = '10.3.3' |
| 50 | artifactId project.name | 50 | } |
| 51 | version project.version | 51 | |
| 52 | from components.java | 52 | publishing { |
| 53 | } | 53 | publications { |
| 54 | } | 54 | "$project.name"(MavenPublication) { |
| 55 | } | 55 | groupId project.group |
| 56 | artifactId project.name | ||
| 57 | version project.version | ||
| 58 | from components.java | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 56 | } | 62 | } |
| 57 | 63 | ||
| 58 | allprojects { | 64 | allprojects { |
| 59 | publishing { | 65 | publishing { |
| 60 | repositories { | 66 | repositories { |
| 61 | mavenLocal() | 67 | mavenLocal() |
| 62 | 68 | ||
| 63 | def ENV = System.getenv() | 69 | def ENV = System.getenv() |
| 64 | if (ENV.MAVEN_URL) { | 70 | if (ENV.MAVEN_URL) { |
| 65 | maven { | 71 | maven { |
| 66 | url ENV.MAVEN_URL | 72 | url ENV.MAVEN_URL |
| 67 | credentials { | 73 | credentials { |
| 68 | username ENV.MAVEN_USERNAME | 74 | username ENV.MAVEN_USERNAME |
| 69 | password ENV.MAVEN_PASSWORD | 75 | password ENV.MAVEN_PASSWORD |
| 70 | } | 76 | } |
| 71 | } | 77 | } |
| 72 | } | 78 | } |
| 73 | } | 79 | } |
| 74 | } | 80 | } |
| 75 | } | 81 | } |
| 76 | 82 | ||
| 77 | // A task to ensure that the version being released has not already been released. | 83 | // A task to ensure that the version being released has not already been released. |
| 78 | task checkVersion { | 84 | task checkVersion { |
| 79 | doFirst { | 85 | doFirst { |
| 80 | def xml = new URL("https://maven.fabricmc.net/cuchaz/enigma/maven-metadata.xml").text | 86 | def xml = new URL("https://maven.fabricmc.net/cuchaz/enigma/maven-metadata.xml").text |
| 81 | def metadata = new XmlSlurper().parseText(xml) | 87 | def metadata = new XmlSlurper().parseText(xml) |
| 82 | def versions = metadata.versioning.versions.version*.text(); | 88 | def versions = metadata.versioning.versions.version*.text(); |
| 83 | if (versions.contains(version)) { | 89 | if (versions.contains(version)) { |
| 84 | throw new RuntimeException("${version} has already been released!") | 90 | throw new RuntimeException("${version} has already been released!") |
| 85 | } | 91 | } |
| 86 | } | 92 | } |
| 87 | } | 93 | } |
| 88 | 94 | ||
| 89 | publish.mustRunAfter checkVersion | 95 | publish.mustRunAfter checkVersion |
diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 00000000..5256fb0d --- /dev/null +++ b/checkstyle.xml | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | <?xml version="1.0"?> | ||
| 2 | <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd"> | ||
| 3 | <module name="Checker"> | ||
| 4 | <property name="charset" value="UTF-8"/> | ||
| 5 | <property name="fileExtensions" value="java"/> | ||
| 6 | <property name="localeLanguage" value="en"/> | ||
| 7 | <property name="localeCountry" value="US"/> | ||
| 8 | |||
| 9 | <module name="NewlineAtEndOfFile"/> | ||
| 10 | |||
| 11 | <!-- disallow trailing whitespace --> | ||
| 12 | <module name="RegexpSingleline"> | ||
| 13 | <property name="format" value="\s+$"/> | ||
| 14 | <property name="message" value="trailing whitespace"/> | ||
| 15 | </module> | ||
| 16 | |||
| 17 | <!-- note: RegexpMultiline shows nicer messages than Regexp, but has to be outside TreeWalker --> | ||
| 18 | <!-- disallow multiple consecutive blank lines --> | ||
| 19 | <module name="RegexpMultiline"> | ||
| 20 | <property name="format" value="\n[\t ]*\r?\n[\t ]*\r?\n"/> | ||
| 21 | <property name="message" value="adjacent blank lines"/> | ||
| 22 | </module> | ||
| 23 | |||
| 24 | <!-- disallow blank after { --> | ||
| 25 | <module name="RegexpMultiline"> | ||
| 26 | <property name="format" value="\{[\t ]*\r?\n[\t ]*\r?\n"/> | ||
| 27 | <property name="message" value="blank line after '{'"/> | ||
| 28 | </module> | ||
| 29 | |||
| 30 | <!-- disallow blank before } --> | ||
| 31 | <module name="RegexpMultiline"> | ||
| 32 | <property name="format" value="\n[\t ]*\r?\n[\t ]*\}"/> | ||
| 33 | <property name="message" value="blank line before '}'"/> | ||
| 34 | </module> | ||
| 35 | |||
| 36 | <!-- require blank before { in the same indentation level --> | ||
| 37 | <module name="RegexpMultiline"> | ||
| 38 | <!-- the regex works as follows: | ||
| 39 | It matches (=fails) for \n<indentation><something>\n<same indentation><control statement>[...]{\n | ||
| 40 | while <something> is a single line comment, it'll look for a blank line one line earlier | ||
| 41 | if <something> is a space, indicating a formatting error or ' */', it'll ignore the instance | ||
| 42 | if <something> is a tab, indicating a continued line, it'll ignore the instance | ||
| 43 | <control statement> is 'if', 'do', 'while', 'for', 'try' or nothing (instance initializer block) | ||
| 44 | |||
| 45 | - first \n: with positive lookbehind (?<=\n) to move the error marker to a more reasonable place | ||
| 46 | - capture tabs for <indentation>, later referenced via \1 | ||
| 47 | - remaining preceding line as a non-comment (doesn't start with '/', '//', ' ' or '\t') or multiple lines where all but the first are a single line comment with the same indentation | ||
| 48 | - new line | ||
| 49 | - <indentation> as captured earlier | ||
| 50 | - <control statement> as specified above | ||
| 51 | - { before the next new line --> | ||
| 52 | <property name="format" value="(?<=\n)([\t]+)(?:[^/\r\n \t][^\r\n]*|/[^/\r\n][^\r\n]*|[^/\r\n][^\r\n]*(\r?\n\1//[^\r\n]*)+)\r?\n\1(|(if|do|while|for|try)[^\r\n]+)\{[\t ]*\r?\n"/> | ||
| 53 | <property name="message" value="missing blank line before block at same indentation level"/> | ||
| 54 | </module> | ||
| 55 | |||
| 56 | <!-- require blank after } in the same indentation level --> | ||
| 57 | <module name="RegexpMultiline"> | ||
| 58 | <!-- \n<indentation>}\n<same indentation><whatever unless newline, '}' or starting with cas(e) or def(ault)> --> | ||
| 59 | <property name="format" value="(?<=\n)([\t]+)\}\r?\n\1(?:[^\r\n\}cd]|c[^\r\na]|ca[^\r\ns]|d[^\r\ne]|de[^\r\nf])"/> | ||
| 60 | <property name="message" value="missing blank line after block at same indentation level"/> | ||
| 61 | </module> | ||
| 62 | |||
| 63 | <module name="TreeWalker"> | ||
| 64 | <!-- Ensure all imports are ship shape --> | ||
| 65 | <module name="AvoidStarImport"/> | ||
| 66 | <module name="IllegalImport"/> | ||
| 67 | <module name="RedundantImport"/> | ||
| 68 | <module name="UnusedImports"/> | ||
| 69 | |||
| 70 | <module name="ImportOrder"> | ||
| 71 | <property name="groups" value="java,javax,*,cuchaz.enigma"/> | ||
| 72 | <property name="ordered" value="false"/><!-- the plugin orders alphabetically without considering separators.. --> | ||
| 73 | <property name="separated" value="true"/> | ||
| 74 | <property name="option" value="top"/> | ||
| 75 | <property name="sortStaticImportsAlphabetically" value="true"/> | ||
| 76 | </module> | ||
| 77 | |||
| 78 | <!-- Ensures braces are at the end of a line --> | ||
| 79 | <module name="LeftCurly"/> | ||
| 80 | <module name="RightCurly"/> | ||
| 81 | |||
| 82 | <!-- single line statements on one line, --> | ||
| 83 | <module name="NeedBraces"> | ||
| 84 | <property name="tokens" value="LITERAL_IF,LITERAL_FOR,LITERAL_WHILE"/> | ||
| 85 | <property name="allowSingleLineStatement" value="true"/> | ||
| 86 | </module> | ||
| 87 | <module name="NeedBraces"> | ||
| 88 | <property name="tokens" value="LITERAL_ELSE,LITERAL_DO"/> | ||
| 89 | <property name="allowSingleLineStatement" value="false"/> | ||
| 90 | </module> | ||
| 91 | |||
| 92 | <module name="EmptyLineSeparator"> | ||
| 93 | <property name="allowNoEmptyLineBetweenFields" value="true"/> | ||
| 94 | <property name="allowMultipleEmptyLines" value="false"/> | ||
| 95 | <!-- exclude METHOD_DEF and VARIABLE_DEF --> | ||
| 96 | <property name="tokens" value="PACKAGE_DEF,IMPORT,STATIC_IMPORT,CLASS_DEF,INTERFACE_DEF,ENUM_DEF,STATIC_INIT,INSTANCE_INIT,CTOR_DEF"/> | ||
| 97 | </module> | ||
| 98 | |||
| 99 | <module name="OperatorWrap"/> | ||
| 100 | <module name="SeparatorWrap"> | ||
| 101 | <property name="tokens" value="DOT,ELLIPSIS,AT"/> | ||
| 102 | <property name="option" value="nl"/> | ||
| 103 | </module> | ||
| 104 | <module name="SeparatorWrap"> | ||
| 105 | <property name="tokens" value="COMMA,SEMI"/> | ||
| 106 | <property name="option" value="eol"/> | ||
| 107 | </module> | ||
| 108 | |||
| 109 | <module name="Indentation"> | ||
| 110 | <property name="basicOffset" value="8"/> | ||
| 111 | <property name="caseIndent" value="0"/> | ||
| 112 | <property name="throwsIndent" value="8"/> | ||
| 113 | <property name="arrayInitIndent" value="8"/> | ||
| 114 | <property name="lineWrappingIndentation" value="16"/> | ||
| 115 | </module> | ||
| 116 | |||
| 117 | <module name="ParenPad"/> | ||
| 118 | <module name="NoWhitespaceBefore"/> | ||
| 119 | <module name="NoWhitespaceAfter"> | ||
| 120 | <!-- allow ARRAY_INIT --> | ||
| 121 | <property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP"/> | ||
| 122 | </module> | ||
| 123 | <module name="WhitespaceAfter"/> | ||
| 124 | <module name="WhitespaceAround"> | ||
| 125 | <!-- Allow PLUS, MINUS, MUL, DIV as they may be more readable without spaces in some cases --> | ||
| 126 | <property name="tokens" | ||
| 127 | value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV_ASSIGN,DO_WHILE,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/> | ||
| 128 | </module> | ||
| 129 | <module name="SingleSpaceSeparator"/> | ||
| 130 | <module name="GenericWhitespace"/> | ||
| 131 | <module name="CommentsIndentation"/> | ||
| 132 | |||
| 133 | <module name="ArrayTypeStyle"/> | ||
| 134 | <module name="DefaultComesLast"> | ||
| 135 | <property name="skipIfLastAndSharedWithCase" value="true"/> | ||
| 136 | </module> | ||
| 137 | <module name="SimplifyBooleanExpression"/> | ||
| 138 | <module name="SimplifyBooleanReturn"/> | ||
| 139 | <module name="StringLiteralEquality"/> | ||
| 140 | |||
| 141 | <module name="ModifierOrder"/> | ||
| 142 | <module name="RedundantModifier"/> | ||
| 143 | |||
| 144 | <module name="AnnotationLocation"/> | ||
| 145 | <module name="MissingOverride"/> | ||
| 146 | |||
| 147 | <!-- By default this allows catch blocks with only comments --> | ||
| 148 | <module name="EmptyCatchBlock"/> | ||
| 149 | |||
| 150 | <!-- Enforce tabs --> | ||
| 151 | <module name="RegexpSinglelineJava"> | ||
| 152 | <property name="format" value="^\t* ([^*]|\*[^ /])"/> | ||
| 153 | <property name="message" value="non-tab indentation"/> | ||
| 154 | </module> | ||
| 155 | |||
| 156 | <module name="OuterTypeFilename"/> | ||
| 157 | |||
| 158 | <!--<module name="InvalidJavadocPosition"/>--> | ||
| 159 | <module name="JavadocParagraph"/> | ||
| 160 | <module name="JavadocStyle"/> | ||
| 161 | <module name="AtclauseOrder"> | ||
| 162 | <property name="tagOrder" value="@param,@return,@throws,@deprecated"/> | ||
| 163 | </module> | ||
| 164 | |||
| 165 | <!-- Prevent var for all cases other than new instance creation --> | ||
| 166 | <module name="MatchXpath"> | ||
| 167 | <property name="query" value="//VARIABLE_DEF[./TYPE/IDENT[@text='var'] and not(./ASSIGN/EXPR/LITERAL_NEW)]"/> | ||
| 168 | </module> | ||
| 169 | </module> | ||
| 170 | </module> \ No newline at end of file | ||
diff --git a/enigma-cli/build.gradle b/enigma-cli/build.gradle index 5b84196e..5281e9e6 100644 --- a/enigma-cli/build.gradle +++ b/enigma-cli/build.gradle | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | plugins { | 1 | plugins { |
| 2 | id 'application' | 2 | id 'application' |
| 3 | id 'com.github.johnrengelman.shadow' version '7.0.0' | 3 | id 'com.github.johnrengelman.shadow' version '7.0.0' |
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | dependencies { | 6 | dependencies { |
| 7 | implementation project(':enigma') | 7 | implementation project(':enigma') |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | mainClassName = 'cuchaz.enigma.command.Main' | 10 | mainClassName = 'cuchaz.enigma.command.Main' |
| @@ -12,9 +12,9 @@ mainClassName = 'cuchaz.enigma.command.Main' | |||
| 12 | jar.manifest.attributes 'Main-Class': mainClassName | 12 | jar.manifest.attributes 'Main-Class': mainClassName |
| 13 | 13 | ||
| 14 | publishing { | 14 | publishing { |
| 15 | publications { | 15 | publications { |
| 16 | shadow(MavenPublication) { publication -> | 16 | shadow(MavenPublication) { publication -> |
| 17 | project.shadow.component publication | 17 | project.shadow.component publication |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
| 20 | } | 20 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java index 75ef225a..922d6688 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java | |||
| @@ -1,22 +1,21 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | ||
| 4 | import java.util.Set; | ||
| 5 | import java.util.stream.Collectors; | ||
| 6 | |||
| 3 | import cuchaz.enigma.Enigma; | 7 | import cuchaz.enigma.Enigma; |
| 4 | import cuchaz.enigma.EnigmaProject; | 8 | import cuchaz.enigma.EnigmaProject; |
| 5 | import cuchaz.enigma.ProgressListener; | 9 | import cuchaz.enigma.ProgressListener; |
| 6 | import cuchaz.enigma.analysis.index.JarIndex; | 10 | import cuchaz.enigma.analysis.index.JarIndex; |
| 7 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | 11 | import cuchaz.enigma.classprovider.ClasspathClassProvider; |
| 8 | import cuchaz.enigma.translation.mapping.EntryMapping; | 12 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 13 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; |
| 14 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 11 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 15 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 16 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 13 | 17 | ||
| 14 | import java.nio.file.Path; | ||
| 15 | import java.util.Set; | ||
| 16 | import java.util.stream.Collectors; | ||
| 17 | |||
| 18 | public class CheckMappingsCommand extends Command { | 18 | public class CheckMappingsCommand extends Command { |
| 19 | |||
| 20 | public CheckMappingsCommand() { | 19 | public CheckMappingsCommand() { |
| 21 | super("checkmappings"); | 20 | super("checkmappings"); |
| 22 | } | 21 | } |
| @@ -55,19 +54,11 @@ public class CheckMappingsCommand extends Command { | |||
| 55 | boolean error = false; | 54 | boolean error = false; |
| 56 | 55 | ||
| 57 | for (Set<ClassEntry> partition : idx.getPackageVisibilityIndex().getPartitions()) { | 56 | for (Set<ClassEntry> partition : idx.getPackageVisibilityIndex().getPartitions()) { |
| 58 | long packages = partition.stream() | 57 | long packages = partition.stream().map(project.getMapper()::deobfuscate).map(ClassEntry::getPackageName).distinct().count(); |
| 59 | .map(project.getMapper()::deobfuscate) | 58 | |
| 60 | .map(ClassEntry::getPackageName) | ||
| 61 | .distinct() | ||
| 62 | .count(); | ||
| 63 | if (packages > 1) { | 59 | if (packages > 1) { |
| 64 | error = true; | 60 | error = true; |
| 65 | System.err.println("ERROR: Must be in one package:\n" + partition.stream() | 61 | System.err.println("ERROR: Must be in one package:\n" + partition.stream().map(project.getMapper()::deobfuscate).map(ClassEntry::toString).sorted().collect(Collectors.joining("\n"))); |
| 66 | .map(project.getMapper()::deobfuscate) | ||
| 67 | .map(ClassEntry::toString) | ||
| 68 | .sorted() | ||
| 69 | .collect(Collectors.joining("\n")) | ||
| 70 | ); | ||
| 71 | } | 62 | } |
| 72 | } | 63 | } |
| 73 | 64 | ||
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java b/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java index 0d71f028..04d49f2f 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java | |||
| @@ -1,21 +1,21 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.io.File; | ||
| 4 | import java.nio.file.Files; | ||
| 5 | import java.nio.file.Path; | ||
| 6 | import java.nio.file.Paths; | ||
| 7 | |||
| 8 | import com.google.common.io.MoreFiles; | ||
| 9 | |||
| 3 | import cuchaz.enigma.Enigma; | 10 | import cuchaz.enigma.Enigma; |
| 4 | import cuchaz.enigma.EnigmaProject; | 11 | import cuchaz.enigma.EnigmaProject; |
| 5 | import cuchaz.enigma.ProgressListener; | 12 | import cuchaz.enigma.ProgressListener; |
| 6 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | 13 | import cuchaz.enigma.classprovider.ClasspathClassProvider; |
| 7 | import cuchaz.enigma.translation.mapping.EntryMapping; | 14 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 15 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; |
| 16 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 10 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 17 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 11 | 18 | ||
| 12 | import java.io.File; | ||
| 13 | import java.nio.file.Files; | ||
| 14 | import java.nio.file.Path; | ||
| 15 | import java.nio.file.Paths; | ||
| 16 | |||
| 17 | import com.google.common.io.MoreFiles; | ||
| 18 | |||
| 19 | public abstract class Command { | 19 | public abstract class Command { |
| 20 | public final String name; | 20 | public final String name; |
| 21 | 21 | ||
| @@ -63,15 +63,19 @@ public abstract class Command { | |||
| 63 | if (path == null) { | 63 | if (path == null) { |
| 64 | return null; | 64 | return null; |
| 65 | } | 65 | } |
| 66 | |||
| 66 | File file = new File(path).getAbsoluteFile(); | 67 | File file = new File(path).getAbsoluteFile(); |
| 67 | File dir = file.getParentFile(); | 68 | File dir = file.getParentFile(); |
| 69 | |||
| 68 | if (dir == null) { | 70 | if (dir == null) { |
| 69 | throw new IllegalArgumentException("Cannot write file: " + path); | 71 | throw new IllegalArgumentException("Cannot write file: " + path); |
| 70 | } | 72 | } |
| 73 | |||
| 71 | // quick fix to avoid stupid stuff in Gradle code | 74 | // quick fix to avoid stupid stuff in Gradle code |
| 72 | if (!dir.isDirectory()) { | 75 | if (!dir.isDirectory()) { |
| 73 | dir.mkdirs(); | 76 | dir.mkdirs(); |
| 74 | } | 77 | } |
| 78 | |||
| 75 | return file; | 79 | return file; |
| 76 | } | 80 | } |
| 77 | 81 | ||
| @@ -79,10 +83,13 @@ public abstract class Command { | |||
| 79 | if (path == null) { | 83 | if (path == null) { |
| 80 | return null; | 84 | return null; |
| 81 | } | 85 | } |
| 86 | |||
| 82 | File dir = new File(path).getAbsoluteFile(); | 87 | File dir = new File(path).getAbsoluteFile(); |
| 88 | |||
| 83 | if (!dir.exists()) { | 89 | if (!dir.exists()) { |
| 84 | throw new IllegalArgumentException("Cannot write to folder: " + dir); | 90 | throw new IllegalArgumentException("Cannot write to folder: " + dir); |
| 85 | } | 91 | } |
| 92 | |||
| 86 | return dir; | 93 | return dir; |
| 87 | } | 94 | } |
| 88 | 95 | ||
| @@ -90,10 +97,13 @@ public abstract class Command { | |||
| 90 | if (path == null) { | 97 | if (path == null) { |
| 91 | return null; | 98 | return null; |
| 92 | } | 99 | } |
| 100 | |||
| 93 | File file = new File(path).getAbsoluteFile(); | 101 | File file = new File(path).getAbsoluteFile(); |
| 102 | |||
| 94 | if (!file.exists()) { | 103 | if (!file.exists()) { |
| 95 | throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath()); | 104 | throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath()); |
| 96 | } | 105 | } |
| 106 | |||
| 97 | return file; | 107 | return file; |
| 98 | } | 108 | } |
| 99 | 109 | ||
| @@ -101,10 +111,13 @@ public abstract class Command { | |||
| 101 | if (path == null) { | 111 | if (path == null) { |
| 102 | return null; | 112 | return null; |
| 103 | } | 113 | } |
| 114 | |||
| 104 | Path file = Paths.get(path).toAbsolutePath(); | 115 | Path file = Paths.get(path).toAbsolutePath(); |
| 116 | |||
| 105 | if (!Files.exists(file)) { | 117 | if (!Files.exists(file)) { |
| 106 | throw new IllegalArgumentException("Cannot find file: " + file.toString()); | 118 | throw new IllegalArgumentException("Cannot find file: " + file.toString()); |
| 107 | } | 119 | } |
| 120 | |||
| 108 | return file; | 121 | return file; |
| 109 | } | 122 | } |
| 110 | 123 | ||
| @@ -116,11 +129,11 @@ public abstract class Command { | |||
| 116 | return null; | 129 | return null; |
| 117 | } | 130 | } |
| 118 | } | 131 | } |
| 132 | |||
| 119 | return args[i]; | 133 | return args[i]; |
| 120 | } | 134 | } |
| 121 | 135 | ||
| 122 | public static class ConsoleProgressListener implements ProgressListener { | 136 | public static class ConsoleProgressListener implements ProgressListener { |
| 123 | |||
| 124 | private static final int ReportTime = 5000; // 5s | 137 | private static final int ReportTime = 5000; // 5s |
| 125 | 138 | ||
| 126 | private int totalWork; | 139 | private int totalWork; |
| @@ -146,6 +159,7 @@ public abstract class Command { | |||
| 146 | System.out.println(String.format("\tProgress: %3d%%", percent)); | 159 | System.out.println(String.format("\tProgress: %3d%%", percent)); |
| 147 | this.lastReportTime = now; | 160 | this.lastReportTime = now; |
| 148 | } | 161 | } |
| 162 | |||
| 149 | if (isLastUpdate) { | 163 | if (isLastUpdate) { |
| 150 | double elapsedSeconds = (now - this.startTime) / 1000.0; | 164 | double elapsedSeconds = (now - this.startTime) / 1000.0; |
| 151 | System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); | 165 | System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/ComposeMappingsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/ComposeMappingsCommand.java index e10fd47e..7e9002d8 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/ComposeMappingsCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/ComposeMappingsCommand.java | |||
| @@ -1,42 +1,42 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.MappingOperations; | 3 | import java.io.IOException; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 4 | import java.nio.file.Path; |
| 5 | import java.nio.file.Paths; | ||
| 6 | |||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 8 | import cuchaz.enigma.translation.mapping.MappingOperations; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 9 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 11 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 12 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 9 | import cuchaz.enigma.utils.Utils; | 13 | import cuchaz.enigma.utils.Utils; |
| 10 | 14 | ||
| 11 | import java.io.IOException; | ||
| 12 | import java.nio.file.Path; | ||
| 13 | import java.nio.file.Paths; | ||
| 14 | |||
| 15 | public class ComposeMappingsCommand extends Command { | 15 | public class ComposeMappingsCommand extends Command { |
| 16 | public ComposeMappingsCommand() { | 16 | public ComposeMappingsCommand() { |
| 17 | super("compose-mappings"); | 17 | super("compose-mappings"); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | @Override | 20 | @Override |
| 21 | public String getUsage() { | 21 | public String getUsage() { |
| 22 | return "<left-format> <left> <right-format> <right> <result-format> <result> <keep-mode>"; | 22 | return "<left-format> <left> <right-format> <right> <result-format> <result> <keep-mode>"; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | @Override | 25 | @Override |
| 26 | public boolean isValidArgument(int length) { | 26 | public boolean isValidArgument(int length) { |
| 27 | return length == 7; | 27 | return length == 7; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | @Override | 30 | @Override |
| 31 | public void run(String... args) throws IOException, MappingParseException { | 31 | public void run(String... args) throws IOException, MappingParseException { |
| 32 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 32 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 33 | 33 | ||
| 34 | EntryTree<EntryMapping> left = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); | 34 | EntryTree<EntryMapping> left = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); |
| 35 | EntryTree<EntryMapping> right = MappingCommandsUtil.read(args[2], Paths.get(args[3]), saveParameters); | 35 | EntryTree<EntryMapping> right = MappingCommandsUtil.read(args[2], Paths.get(args[3]), saveParameters); |
| 36 | EntryTree<EntryMapping> result = MappingOperations.compose(left, right, args[6].equals("left") || args[6].equals("both"), args[6].equals("right") || args[6].equals("both")); | 36 | EntryTree<EntryMapping> result = MappingOperations.compose(left, right, args[6].equals("left") || args[6].equals("both"), args[6].equals("right") || args[6].equals("both")); |
| 37 | 37 | ||
| 38 | Path output = Paths.get(args[5]); | 38 | Path output = Paths.get(args[5]); |
| 39 | Utils.delete(output); | 39 | Utils.delete(output); |
| 40 | MappingCommandsUtil.write(result, args[4], output, saveParameters); | 40 | MappingCommandsUtil.write(result, args[4], output, saveParameters); |
| 41 | } | 41 | } |
| 42 | } | 42 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java index 144d89c5..99b27e1f 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/ConvertMappingsCommand.java | |||
| @@ -1,39 +1,39 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 3 | import java.io.IOException; |
| 4 | import java.nio.file.Path; | ||
| 5 | import java.nio.file.Paths; | ||
| 6 | |||
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 8 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 10 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 7 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 11 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 8 | import cuchaz.enigma.utils.Utils; | 12 | import cuchaz.enigma.utils.Utils; |
| 9 | 13 | ||
| 10 | import java.io.IOException; | ||
| 11 | import java.nio.file.Path; | ||
| 12 | import java.nio.file.Paths; | ||
| 13 | |||
| 14 | public class ConvertMappingsCommand extends Command { | 14 | public class ConvertMappingsCommand extends Command { |
| 15 | public ConvertMappingsCommand() { | 15 | public ConvertMappingsCommand() { |
| 16 | super("convert-mappings"); | 16 | super("convert-mappings"); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | @Override | 19 | @Override |
| 20 | public String getUsage() { | 20 | public String getUsage() { |
| 21 | return "<source-format> <source> <result-format> <result>"; | 21 | return "<source-format> <source> <result-format> <result>"; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | @Override | 24 | @Override |
| 25 | public boolean isValidArgument(int length) { | 25 | public boolean isValidArgument(int length) { |
| 26 | return length == 4; | 26 | return length == 4; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | @Override | 29 | @Override |
| 30 | public void run(String... args) throws IOException, MappingParseException { | 30 | public void run(String... args) throws IOException, MappingParseException { |
| 31 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 31 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 32 | 32 | ||
| 33 | EntryTree<EntryMapping> mappings = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); | 33 | EntryTree<EntryMapping> mappings = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); |
| 34 | 34 | ||
| 35 | Path output = Paths.get(args[3]); | 35 | Path output = Paths.get(args[3]); |
| 36 | Utils.delete(output); | 36 | Utils.delete(output); |
| 37 | MappingCommandsUtil.write(mappings, args[2], output, saveParameters); | 37 | MappingCommandsUtil.write(mappings, args[2], output, saveParameters); |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java index 12a4e886..020bd979 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java | |||
| @@ -1,17 +1,16 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.lang.reflect.Field; | ||
| 4 | import java.nio.file.Path; | ||
| 5 | import java.util.Locale; | ||
| 6 | |||
| 3 | import cuchaz.enigma.EnigmaProject; | 7 | import cuchaz.enigma.EnigmaProject; |
| 4 | import cuchaz.enigma.ProgressListener; | ||
| 5 | import cuchaz.enigma.EnigmaProject.DecompileErrorStrategy; | 8 | import cuchaz.enigma.EnigmaProject.DecompileErrorStrategy; |
| 9 | import cuchaz.enigma.ProgressListener; | ||
| 6 | import cuchaz.enigma.source.DecompilerService; | 10 | import cuchaz.enigma.source.DecompilerService; |
| 7 | import cuchaz.enigma.source.Decompilers; | 11 | import cuchaz.enigma.source.Decompilers; |
| 8 | 12 | ||
| 9 | import java.lang.reflect.Field; | ||
| 10 | import java.nio.file.Path; | ||
| 11 | import java.util.Locale; | ||
| 12 | |||
| 13 | public class DecompileCommand extends Command { | 13 | public class DecompileCommand extends Command { |
| 14 | |||
| 15 | public DecompileCommand() { | 14 | public DecompileCommand() { |
| 16 | super("decompile"); | 15 | super("decompile"); |
| 17 | } | 16 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java index b0d2a7d0..c8e62008 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/DeobfuscateCommand.java | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | ||
| 4 | |||
| 3 | import cuchaz.enigma.EnigmaProject; | 5 | import cuchaz.enigma.EnigmaProject; |
| 4 | import cuchaz.enigma.ProgressListener; | 6 | import cuchaz.enigma.ProgressListener; |
| 5 | 7 | ||
| 6 | import java.nio.file.Path; | ||
| 7 | |||
| 8 | public class DeobfuscateCommand extends Command { | 8 | public class DeobfuscateCommand extends Command { |
| 9 | |||
| 10 | public DeobfuscateCommand() { | 9 | public DeobfuscateCommand() { |
| 11 | super("deobfuscate"); | 10 | super("deobfuscate"); |
| 12 | } | 11 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/InvertMappingsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/InvertMappingsCommand.java index 0780a965..af24978b 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/InvertMappingsCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/InvertMappingsCommand.java | |||
| @@ -1,41 +1,41 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.MappingOperations; | 3 | import java.io.IOException; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 4 | import java.nio.file.Path; |
| 5 | import java.nio.file.Paths; | ||
| 6 | |||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 8 | import cuchaz.enigma.translation.mapping.MappingOperations; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 9 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 11 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 12 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 9 | import cuchaz.enigma.utils.Utils; | 13 | import cuchaz.enigma.utils.Utils; |
| 10 | 14 | ||
| 11 | import java.io.IOException; | ||
| 12 | import java.nio.file.Path; | ||
| 13 | import java.nio.file.Paths; | ||
| 14 | |||
| 15 | public class InvertMappingsCommand extends Command { | 15 | public class InvertMappingsCommand extends Command { |
| 16 | public InvertMappingsCommand() { | 16 | public InvertMappingsCommand() { |
| 17 | super("invert-mappings"); | 17 | super("invert-mappings"); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | @Override | 20 | @Override |
| 21 | public String getUsage() { | 21 | public String getUsage() { |
| 22 | return "<source-format> <source> <result-format> <result>"; | 22 | return "<source-format> <source> <result-format> <result>"; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | @Override | 25 | @Override |
| 26 | public boolean isValidArgument(int length) { | 26 | public boolean isValidArgument(int length) { |
| 27 | return length == 4; | 27 | return length == 4; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | @Override | 30 | @Override |
| 31 | public void run(String... args) throws IOException, MappingParseException { | 31 | public void run(String... args) throws IOException, MappingParseException { |
| 32 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 32 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 33 | 33 | ||
| 34 | EntryTree<EntryMapping> source = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); | 34 | EntryTree<EntryMapping> source = MappingCommandsUtil.read(args[0], Paths.get(args[1]), saveParameters); |
| 35 | EntryTree<EntryMapping> result = MappingOperations.invert(source); | 35 | EntryTree<EntryMapping> result = MappingOperations.invert(source); |
| 36 | 36 | ||
| 37 | Path output = Paths.get(args[3]); | 37 | Path output = Paths.get(args[3]); |
| 38 | Utils.delete(output); | 38 | Utils.delete(output); |
| 39 | MappingCommandsUtil.write(result, args[2], output, saveParameters); | 39 | MappingCommandsUtil.write(result, args[2], output, saveParameters); |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/Main.java b/enigma-cli/src/main/java/cuchaz/enigma/command/Main.java index 0a4c1b9b..9021ff15 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/Main.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/Main.java | |||
| @@ -1,36 +1,39 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.command; | 12 | package cuchaz.enigma.command; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.Enigma; | ||
| 15 | |||
| 16 | import java.util.LinkedHashMap; | 14 | import java.util.LinkedHashMap; |
| 17 | import java.util.Locale; | 15 | import java.util.Locale; |
| 18 | import java.util.Map; | 16 | import java.util.Map; |
| 19 | 17 | ||
| 20 | public class Main { | 18 | import cuchaz.enigma.Enigma; |
| 21 | 19 | ||
| 20 | public class Main { | ||
| 22 | private static final Map<String, Command> COMMANDS = new LinkedHashMap<>(); | 21 | private static final Map<String, Command> COMMANDS = new LinkedHashMap<>(); |
| 23 | 22 | ||
| 24 | public static void main(String... args) throws Exception { | 23 | public static void main(String... args) throws Exception { |
| 25 | try { | 24 | try { |
| 26 | // process the command | 25 | // process the command |
| 27 | if (args.length < 1) | 26 | if (args.length < 1) { |
| 28 | throw new IllegalArgumentException("Requires a command"); | 27 | throw new IllegalArgumentException("Requires a command"); |
| 28 | } | ||
| 29 | |||
| 29 | String command = args[0].toLowerCase(Locale.ROOT); | 30 | String command = args[0].toLowerCase(Locale.ROOT); |
| 30 | 31 | ||
| 31 | Command cmd = COMMANDS.get(command); | 32 | Command cmd = COMMANDS.get(command); |
| 32 | if (cmd == null) | 33 | |
| 34 | if (cmd == null) { | ||
| 33 | throw new IllegalArgumentException("Command not recognized: " + command); | 35 | throw new IllegalArgumentException("Command not recognized: " + command); |
| 36 | } | ||
| 34 | 37 | ||
| 35 | if (!cmd.isValidArgument(args.length - 1)) { | 38 | if (!cmd.isValidArgument(args.length - 1)) { |
| 36 | throw new CommandHelpException(cmd); | 39 | throw new CommandHelpException(cmd); |
| @@ -74,6 +77,7 @@ public class Main { | |||
| 74 | 77 | ||
| 75 | private static void register(Command command) { | 78 | private static void register(Command command) { |
| 76 | Command old = COMMANDS.put(command.name, command); | 79 | Command old = COMMANDS.put(command.name, command); |
| 80 | |||
| 77 | if (old != null) { | 81 | if (old != null) { |
| 78 | System.err.println("Command " + old + " with name " + command.name + " has been substituted by " + command); | 82 | System.err.println("Command " + old + " with name " + command.name + " has been substituted by " + command); |
| 79 | } | 83 | } |
| @@ -90,7 +94,6 @@ public class Main { | |||
| 90 | } | 94 | } |
| 91 | 95 | ||
| 92 | private static final class CommandHelpException extends IllegalArgumentException { | 96 | private static final class CommandHelpException extends IllegalArgumentException { |
| 93 | |||
| 94 | final Command command; | 97 | final Command command; |
| 95 | 98 | ||
| 96 | CommandHelpException(Command command) { | 99 | CommandHelpException(Command command) { |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java index 46da89a2..644b08d3 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java | |||
| @@ -1,5 +1,10 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Path; | ||
| 5 | import java.nio.file.Paths; | ||
| 6 | import java.util.Map; | ||
| 7 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 8 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.analysis.IndexTreeBuilder; | 9 | import cuchaz.enigma.analysis.IndexTreeBuilder; |
| 5 | import cuchaz.enigma.analysis.index.BridgeMethodIndex; | 10 | import cuchaz.enigma.analysis.index.BridgeMethodIndex; |
| @@ -18,60 +23,55 @@ import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 23 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | import cuchaz.enigma.utils.Utils; | 24 | import cuchaz.enigma.utils.Utils; |
| 20 | 25 | ||
| 21 | import java.io.IOException; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.nio.file.Paths; | ||
| 24 | import java.util.Map; | ||
| 25 | |||
| 26 | public class MapSpecializedMethodsCommand extends Command { | 26 | public class MapSpecializedMethodsCommand extends Command { |
| 27 | public MapSpecializedMethodsCommand() { | 27 | public MapSpecializedMethodsCommand() { |
| 28 | super("map-specialized-methods"); | 28 | super("map-specialized-methods"); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | @Override | 31 | @Override |
| 32 | public String getUsage() { | 32 | public String getUsage() { |
| 33 | return "<jar> <source-format> <source> <result-format> <result>"; | 33 | return "<jar> <source-format> <source> <result-format> <result>"; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | @Override | 36 | @Override |
| 37 | public boolean isValidArgument(int length) { | 37 | public boolean isValidArgument(int length) { |
| 38 | return length == 5; | 38 | return length == 5; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | @Override | 41 | @Override |
| 42 | public void run(String... args) throws IOException, MappingParseException { | 42 | public void run(String... args) throws IOException, MappingParseException { |
| 43 | run(Paths.get(args[0]), args[1], Paths.get(args[2]), args[3], Paths.get(args[4])); | 43 | run(Paths.get(args[0]), args[1], Paths.get(args[2]), args[3], Paths.get(args[4])); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | public static void run(Path jar, String sourceFormat, Path sourcePath, String resultFormat, Path output) throws IOException, MappingParseException { | 46 | public static void run(Path jar, String sourceFormat, Path sourcePath, String resultFormat, Path output) throws IOException, MappingParseException { |
| 47 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 47 | MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 48 | EntryTree<EntryMapping> source = MappingCommandsUtil.read(sourceFormat, sourcePath, saveParameters); | 48 | EntryTree<EntryMapping> source = MappingCommandsUtil.read(sourceFormat, sourcePath, saveParameters); |
| 49 | EntryTree<EntryMapping> result = new HashEntryTree<>(); | 49 | EntryTree<EntryMapping> result = new HashEntryTree<>(); |
| 50 | 50 | ||
| 51 | JarClassProvider jcp = new JarClassProvider(jar); | 51 | JarClassProvider jcp = new JarClassProvider(jar); |
| 52 | JarIndex jarIndex = JarIndex.empty(); | 52 | JarIndex jarIndex = JarIndex.empty(); |
| 53 | jarIndex.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none()); | 53 | jarIndex.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none()); |
| 54 | 54 | ||
| 55 | BridgeMethodIndex bridgeMethodIndex = jarIndex.getBridgeMethodIndex(); | 55 | BridgeMethodIndex bridgeMethodIndex = jarIndex.getBridgeMethodIndex(); |
| 56 | Translator translator = new MappingTranslator(source, jarIndex.getEntryResolver()); | 56 | Translator translator = new MappingTranslator(source, jarIndex.getEntryResolver()); |
| 57 | IndexTreeBuilder indexTreeBuilder = new IndexTreeBuilder(jarIndex); | 57 | IndexTreeBuilder indexTreeBuilder = new IndexTreeBuilder(jarIndex); |
| 58 | 58 | ||
| 59 | // Copy all non-specialized methods | 59 | // Copy all non-specialized methods |
| 60 | for (EntryTreeNode<EntryMapping> node : source) { | 60 | for (EntryTreeNode<EntryMapping> node : source) { |
| 61 | if (!(node.getEntry() instanceof MethodEntry) || !bridgeMethodIndex.isSpecializedMethod((MethodEntry) node.getEntry())) { | 61 | if (!(node.getEntry() instanceof MethodEntry) || !bridgeMethodIndex.isSpecializedMethod((MethodEntry) node.getEntry())) { |
| 62 | result.insert(node.getEntry(), node.getValue()); | 62 | result.insert(node.getEntry(), node.getValue()); |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // Add correct mappings for specialized methods | 66 | // Add correct mappings for specialized methods |
| 67 | for (Map.Entry<MethodEntry, MethodEntry> entry : bridgeMethodIndex.getBridgeToSpecialized().entrySet()) { | 67 | for (Map.Entry<MethodEntry, MethodEntry> entry : bridgeMethodIndex.getBridgeToSpecialized().entrySet()) { |
| 68 | MethodEntry bridge = entry.getKey(); | 68 | MethodEntry bridge = entry.getKey(); |
| 69 | MethodEntry specialized = indexTreeBuilder.buildMethodInheritance(translator, entry.getValue()).getMethodEntry(); | 69 | MethodEntry specialized = indexTreeBuilder.buildMethodInheritance(translator, entry.getValue()).getMethodEntry(); |
| 70 | String name = translator.translate(bridge).getName(); | 70 | String name = translator.translate(bridge).getName(); |
| 71 | result.insert(specialized, new EntryMapping(name)); | 71 | result.insert(specialized, new EntryMapping(name)); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | Utils.delete(output); | 74 | Utils.delete(output); |
| 75 | MappingCommandsUtil.write(result, resultFormat, output, saveParameters); | 75 | MappingCommandsUtil.write(result, resultFormat, output, saveParameters); |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/MappingCommandsUtil.java b/enigma-cli/src/main/java/cuchaz/enigma/command/MappingCommandsUtil.java index d365129b..787625b6 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/MappingCommandsUtil.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/MappingCommandsUtil.java | |||
| @@ -1,10 +1,14 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Files; | ||
| 5 | import java.nio.file.Path; | ||
| 6 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 7 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 8 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | ||
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 11 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 7 | import cuchaz.enigma.translation.mapping.serde.*; | ||
| 8 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; | 12 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; |
| 9 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsWriter; | 13 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsWriter; |
| 10 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsReader; | 14 | import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsReader; |
| @@ -12,76 +16,77 @@ import cuchaz.enigma.translation.mapping.serde.tiny.TinyMappingsWriter; | |||
| 12 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; | 16 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; |
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 17 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 14 | 18 | ||
| 15 | import java.io.IOException; | ||
| 16 | import java.nio.file.Files; | ||
| 17 | import java.nio.file.Path; | ||
| 18 | |||
| 19 | public final class MappingCommandsUtil { | 19 | public final class MappingCommandsUtil { |
| 20 | private MappingCommandsUtil() {} | 20 | private MappingCommandsUtil() { |
| 21 | 21 | } | |
| 22 | public static EntryTree<EntryMapping> read(String type, Path path, MappingSaveParameters saveParameters) throws MappingParseException, IOException { | 22 | |
| 23 | if (type.equals("enigma")) { | 23 | public static EntryTree<EntryMapping> read(String type, Path path, MappingSaveParameters saveParameters) throws MappingParseException, IOException { |
| 24 | return (Files.isDirectory(path) ? EnigmaMappingsReader.DIRECTORY : EnigmaMappingsReader.ZIP).read(path, ProgressListener.none(), saveParameters); | 24 | if (type.equals("enigma")) { |
| 25 | } | 25 | return (Files.isDirectory(path) ? EnigmaMappingsReader.DIRECTORY : EnigmaMappingsReader.ZIP).read(path, ProgressListener.none(), saveParameters); |
| 26 | 26 | } | |
| 27 | if (type.equals("tiny")) { | 27 | |
| 28 | return TinyMappingsReader.INSTANCE.read(path, ProgressListener.none(), saveParameters); | 28 | if (type.equals("tiny")) { |
| 29 | } | 29 | return TinyMappingsReader.INSTANCE.read(path, ProgressListener.none(), saveParameters); |
| 30 | 30 | } | |
| 31 | MappingFormat format = null; | 31 | |
| 32 | try { | 32 | MappingFormat format = null; |
| 33 | format = MappingFormat.valueOf(type.toUpperCase()); | 33 | |
| 34 | } catch (IllegalArgumentException ignored) { | 34 | try { |
| 35 | if (type.equals("tinyv2")) { | 35 | format = MappingFormat.valueOf(type.toUpperCase()); |
| 36 | format = MappingFormat.TINY_V2; | 36 | } catch (IllegalArgumentException ignored) { |
| 37 | } | 37 | if (type.equals("tinyv2")) { |
| 38 | } | 38 | format = MappingFormat.TINY_V2; |
| 39 | 39 | } | |
| 40 | if (format != null) { | 40 | } |
| 41 | return format.getReader().read(path, ProgressListener.none(), saveParameters); | 41 | |
| 42 | } | 42 | if (format != null) { |
| 43 | 43 | return format.getReader().read(path, ProgressListener.none(), saveParameters); | |
| 44 | throw new IllegalArgumentException("no reader for " + type); | 44 | } |
| 45 | } | 45 | |
| 46 | 46 | throw new IllegalArgumentException("no reader for " + type); | |
| 47 | public static void write(EntryTree<EntryMapping> mappings, String type, Path path, MappingSaveParameters saveParameters) { | 47 | } |
| 48 | if (type.equals("enigma")) { | 48 | |
| 49 | EnigmaMappingsWriter.DIRECTORY.write(mappings, path, ProgressListener.none(), saveParameters); | 49 | public static void write(EntryTree<EntryMapping> mappings, String type, Path path, MappingSaveParameters saveParameters) { |
| 50 | return; | 50 | if (type.equals("enigma")) { |
| 51 | } | 51 | EnigmaMappingsWriter.DIRECTORY.write(mappings, path, ProgressListener.none(), saveParameters); |
| 52 | 52 | return; | |
| 53 | if (type.startsWith("tinyv2:") || type.startsWith("tiny_v2:")) { | 53 | } |
| 54 | String[] split = type.split(":"); | 54 | |
| 55 | 55 | if (type.startsWith("tinyv2:") || type.startsWith("tiny_v2:")) { | |
| 56 | if (split.length != 3) { | 56 | String[] split = type.split(":"); |
| 57 | throw new IllegalArgumentException("specify column names as 'tinyv2:from_namespace:to_namespace'"); | 57 | |
| 58 | } | 58 | if (split.length != 3) { |
| 59 | 59 | throw new IllegalArgumentException("specify column names as 'tinyv2:from_namespace:to_namespace'"); | |
| 60 | new TinyV2Writer(split[1], split[2]).write(mappings, path, ProgressListener.none(), saveParameters); | 60 | } |
| 61 | return; | 61 | |
| 62 | } | 62 | new TinyV2Writer(split[1], split[2]).write(mappings, path, ProgressListener.none(), saveParameters); |
| 63 | 63 | return; | |
| 64 | if (type.startsWith("tiny:")) { | 64 | } |
| 65 | String[] split = type.split(":"); | 65 | |
| 66 | 66 | if (type.startsWith("tiny:")) { | |
| 67 | if (split.length != 3) { | 67 | String[] split = type.split(":"); |
| 68 | throw new IllegalArgumentException("specify column names as 'tiny:from_column:to_column'"); | 68 | |
| 69 | } | 69 | if (split.length != 3) { |
| 70 | 70 | throw new IllegalArgumentException("specify column names as 'tiny:from_column:to_column'"); | |
| 71 | new TinyMappingsWriter(split[1], split[2]).write(mappings, path, ProgressListener.none(), saveParameters); | 71 | } |
| 72 | return; | 72 | |
| 73 | } | 73 | new TinyMappingsWriter(split[1], split[2]).write(mappings, path, ProgressListener.none(), saveParameters); |
| 74 | 74 | return; | |
| 75 | MappingFormat format = null; | 75 | } |
| 76 | try { | 76 | |
| 77 | format = MappingFormat.valueOf(type.toUpperCase()); | 77 | MappingFormat format = null; |
| 78 | } catch (IllegalArgumentException ignored) {} | 78 | |
| 79 | 79 | try { | |
| 80 | if (format != null) { | 80 | format = MappingFormat.valueOf(type.toUpperCase()); |
| 81 | format.getWriter().write(mappings, path, ProgressListener.none(), saveParameters); | 81 | } catch (IllegalArgumentException ignored) { |
| 82 | return; | 82 | // ignored |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | throw new IllegalArgumentException("no writer for " + type); | 85 | if (format != null) { |
| 86 | } | 86 | format.getWriter().write(mappings, path, ProgressListener.none(), saveParameters); |
| 87 | return; | ||
| 88 | } | ||
| 89 | |||
| 90 | throw new IllegalArgumentException("no writer for " + type); | ||
| 91 | } | ||
| 87 | } | 92 | } |
diff --git a/enigma-cli/src/test/java/cuchaz/enigma/command/CheckMappingsCommandTest.java b/enigma-cli/src/test/java/cuchaz/enigma/command/CheckMappingsCommandTest.java index a29bba40..8cfa49e7 100644 --- a/enigma-cli/src/test/java/cuchaz/enigma/command/CheckMappingsCommandTest.java +++ b/enigma-cli/src/test/java/cuchaz/enigma/command/CheckMappingsCommandTest.java | |||
| @@ -1,21 +1,19 @@ | |||
| 1 | package cuchaz.enigma.command; | 1 | package cuchaz.enigma.command; |
| 2 | 2 | ||
| 3 | import org.junit.Test; | ||
| 4 | |||
| 5 | import java.io.File; | 3 | import java.io.File; |
| 6 | 4 | ||
| 5 | import org.junit.Test; | ||
| 6 | |||
| 7 | public class CheckMappingsCommandTest { | 7 | public class CheckMappingsCommandTest { |
| 8 | private static final String PACKAGE_ACCESS = "../enigma/build/test-obf/packageAccess.jar"; | 8 | private static final String PACKAGE_ACCESS = "../enigma/build/test-obf/packageAccess.jar"; |
| 9 | 9 | ||
| 10 | @Test(expected = IllegalStateException.class) | 10 | @Test(expected = IllegalStateException.class) |
| 11 | public void testWrong() throws Exception { | 11 | public void testWrong() throws Exception { |
| 12 | new CheckMappingsCommand().run(new File(PACKAGE_ACCESS).getAbsolutePath(), new File("src/test/resources" + | 12 | new CheckMappingsCommand().run(new File(PACKAGE_ACCESS).getAbsolutePath(), new File("src/test/resources" + "/packageAccess/wrongMappings").getAbsolutePath()); |
| 13 | "/packageAccess/wrongMappings").getAbsolutePath()); | ||
| 14 | } | 13 | } |
| 15 | 14 | ||
| 16 | @Test | 15 | @Test |
| 17 | public void testRight() throws Exception { | 16 | public void testRight() throws Exception { |
| 18 | new CheckMappingsCommand().run(new File(PACKAGE_ACCESS).getAbsolutePath(), new File("src/test/resources" + | 17 | new CheckMappingsCommand().run(new File(PACKAGE_ACCESS).getAbsolutePath(), new File("src/test/resources" + "/packageAccess/correctMappings").getAbsolutePath()); |
| 19 | "/packageAccess/correctMappings").getAbsolutePath()); | ||
| 20 | } | 18 | } |
| 21 | } | 19 | } |
diff --git a/enigma-server/build.gradle b/enigma-server/build.gradle index 27645589..873adb90 100644 --- a/enigma-server/build.gradle +++ b/enigma-server/build.gradle | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | plugins { | 1 | plugins { |
| 2 | id 'application' | 2 | id 'application' |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | dependencies { | 5 | dependencies { |
| 6 | implementation project(':enigma') | 6 | implementation project(':enigma') |
| 7 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' | 7 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | mainClassName = 'cuchaz.enigma.network.DedicatedEnigmaServer' | 10 | mainClassName = 'cuchaz.enigma.network.DedicatedEnigmaServer' |
diff --git a/enigma-server/docs/protocol.md b/enigma-server/docs/protocol.md index 83ef4c01..f642e138 100644 --- a/enigma-server/docs/protocol.md +++ b/enigma-server/docs/protocol.md | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | # Enigma protocol | 1 | # Enigma protocol |
| 2 | |||
| 2 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being | 3 | Enigma uses TCP sockets for communication. Data is sent in each direction as a continuous stream, with packets being |
| 3 | concatenated one after the other. | 4 | concatenated one after the other. |
| 4 | 5 | ||
| @@ -10,6 +11,7 @@ use the same modified UTF format as in `DataOutputStream`, I repeat, the normal | |||
| 10 | Strings, see below. | 11 | Strings, see below. |
| 11 | 12 | ||
| 12 | ## Login protocol | 13 | ## Login protocol |
| 14 | |||
| 13 | ``` | 15 | ``` |
| 14 | Client Server | 16 | Client Server |
| 15 | | | | 17 | | | |
| @@ -22,6 +24,7 @@ Client Server | |||
| 22 | | ConfirmChange | | 24 | | ConfirmChange | |
| 23 | | >>>>>>>>>>>>> | | 25 | | >>>>>>>>>>>>> | |
| 24 | ``` | 26 | ``` |
| 27 | |||
| 25 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, | 28 | 1. On connect, the client sends a login packet to the server. This allows the server to test the validity of the client, |
| 26 | as well as allowing the client to declare metadata about itself, such as the username. | 29 | as well as allowing the client to declare metadata about itself, such as the username. |
| 27 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. | 30 | 1. After validating the login packet, the server sends all its mappings to the client, and the client will apply them. |
| @@ -29,15 +32,18 @@ Client Server | |||
| 29 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be | 32 | has received the mappings and is in sync with the server. Once the server receives this packet, the client will be |
| 30 | allowed to modify mappings. | 33 | allowed to modify mappings. |
| 31 | 34 | ||
| 32 | The server will not accept any other packets from the client until this entire exchange has been completed. | 35 | The server will not accept any other packets from the client until this entire exchange has been completed. |
| 33 | 36 | ||
| 34 | ## Kicking clients | 37 | ## Kicking clients |
| 38 | |||
| 35 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which | 39 | When the server kicks a client, it may optionally send a `Kick` packet immediately before closing the connection, which |
| 36 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - | 40 | contains the reason why the client was kicked (so the client can display it to the user). This is not required though - |
| 37 | the server may simply terminate the connection. | 41 | the server may simply terminate the connection. |
| 38 | 42 | ||
| 39 | ## Changing mappings | 43 | ## Changing mappings |
| 44 | |||
| 40 | This section uses the example of renaming, but the same pattern applies to all mapping changes. | 45 | This section uses the example of renaming, but the same pattern applies to all mapping changes. |
| 46 | |||
| 41 | ``` | 47 | ``` |
| 42 | Client A Server Client B | 48 | Client A Server Client B |
| 43 | | | | | 49 | | | | |
| @@ -66,19 +72,23 @@ Client A Server Client B | |||
| 66 | server will unlock that mapping for that client and allow them to make changes again. | 72 | server will unlock that mapping for that client and allow them to make changes again. |
| 67 | 73 | ||
| 68 | ## Packets | 74 | ## Packets |
| 75 | |||
| 69 | ```c | 76 | ```c |
| 70 | struct Packet { | 77 | struct Packet { |
| 71 | unsigned short packet_id; | 78 | unsigned short packet_id; |
| 72 | data[]; // depends on packet_id | 79 | data[]; // depends on packet_id |
| 73 | } | 80 | } |
| 74 | ``` | 81 | ``` |
| 82 | |||
| 75 | The IDs for client-to-server packets are as follows: | 83 | The IDs for client-to-server packets are as follows: |
| 84 | |||
| 76 | - 0: `Login` | 85 | - 0: `Login` |
| 77 | - 1: `ConfirmChange` | 86 | - 1: `ConfirmChange` |
| 78 | - 6: `Message` | 87 | - 6: `Message` |
| 79 | - 7: `EntryChange` | 88 | - 7: `EntryChange` |
| 80 | 89 | ||
| 81 | The IDs for server-to-client packets are as follows: | 90 | The IDs for server-to-client packets are as follows: |
| 91 | |||
| 82 | - 0: `Kick` | 92 | - 0: `Kick` |
| 83 | - 1: `SyncMappings` | 93 | - 1: `SyncMappings` |
| 84 | - 6: `Message` | 94 | - 6: `Message` |
| @@ -86,17 +96,20 @@ The IDs for server-to-client packets are as follows: | |||
| 86 | - 8: `EntryChange` | 96 | - 8: `EntryChange` |
| 87 | 97 | ||
| 88 | ### The utf struct | 98 | ### The utf struct |
| 99 | |||
| 89 | ```c | 100 | ```c |
| 90 | struct utf { | 101 | struct utf { |
| 91 | unsigned short length; | 102 | unsigned short length; |
| 92 | byte data[length]; | 103 | byte data[length]; |
| 93 | } | 104 | } |
| 94 | ``` | 105 | ``` |
| 106 | |||
| 95 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of | 107 | - `length`: The number of bytes in the UTF-8 encoding of the string. Note, this may not be the same as the number of |
| 96 | Unicode characters in the string. | 108 | Unicode characters in the string. |
| 97 | - `data`: A standard UTF-8 encoded byte array representing the string. | 109 | - `data`: A standard UTF-8 encoded byte array representing the string. |
| 98 | 110 | ||
| 99 | ### The Entry struct | 111 | ### The Entry struct |
| 112 | |||
| 100 | ```c | 113 | ```c |
| 101 | enum EntryType { | 114 | enum EntryType { |
| 102 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 115 | ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| @@ -121,9 +134,10 @@ struct Entry { | |||
| 121 | } | 134 | } |
| 122 | } | 135 | } |
| 123 | ``` | 136 | ``` |
| 137 | |||
| 124 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. | 138 | - `type`: The type of entry this is. One of `ENTRY_CLASS`, `ENTRY_FIELD`, `ENTRY_METHOD` or `ENTRY_LOCAL_VAR`. |
| 125 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their | 139 | - `parent`: The parent entry. Only class entries may have no parent. fields, methods and inner classes must have their |
| 126 | containing class as their parent. Local variables have a method as a parent. | 140 | containing class as their parent. Local variables have a method as a parent. |
| 127 | - `name`: The class/field/method/variable name. | 141 | - `name`: The class/field/method/variable name. |
| 128 | - `javadoc`: The javadoc of an entry, if present. | 142 | - `javadoc`: The javadoc of an entry, if present. |
| 129 | - `descriptor`: The field/method descriptor. | 143 | - `descriptor`: The field/method descriptor. |
| @@ -131,6 +145,7 @@ struct Entry { | |||
| 131 | - `parameter`: Whether the local variable is a parameter. | 145 | - `parameter`: Whether the local variable is a parameter. |
| 132 | 146 | ||
| 133 | ### The Message struct | 147 | ### The Message struct |
| 148 | |||
| 134 | ```c | 149 | ```c |
| 135 | enum MessageType { | 150 | enum MessageType { |
| 136 | MESSAGE_CHAT = 0, | 151 | MESSAGE_CHAT = 0, |
| @@ -176,8 +191,9 @@ struct Message { | |||
| 176 | } data; | 191 | } data; |
| 177 | }; | 192 | }; |
| 178 | ``` | 193 | ``` |
| 194 | |||
| 179 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, | 195 | - `type`: The type of message this is. One of `MESSAGE_CHAT`, `MESSAGE_CONNECT`, `MESSAGE_DISCONNECT`, |
| 180 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. | 196 | `MESSAGE_EDIT_DOCS`, `MESSAGE_MARK_DEOBF`, `MESSAGE_REMOVE_MAPPING`, `MESSAGE_RENAME`. |
| 181 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` | 197 | - `chat`: Chat message. Use in case `type` is `MESSAGE_CHAT` |
| 182 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` | 198 | - `connect`: Sent when a user connects. Use in case `type` is `MESSAGE_CONNECT` |
| 183 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` | 199 | - `disconnect`: Sent when a user disconnects. Use in case `type` is `MESSAGE_DISCONNECT` |
| @@ -191,6 +207,7 @@ struct Message { | |||
| 191 | - `new_name`: The new name for the entry. | 207 | - `new_name`: The new name for the entry. |
| 192 | 208 | ||
| 193 | ### The entry_change struct | 209 | ### The entry_change struct |
| 210 | |||
| 194 | ```c | 211 | ```c |
| 195 | typedef enum tristate_change { | 212 | typedef enum tristate_change { |
| 196 | TRISTATE_CHANGE_UNCHANGED = 0, | 213 | TRISTATE_CHANGE_UNCHANGED = 0, |
| @@ -224,6 +241,7 @@ struct entry_change { | |||
| 224 | } | 241 | } |
| 225 | } | 242 | } |
| 226 | ``` | 243 | ``` |
| 244 | |||
| 227 | - `entry`: The entry this change gets applied to. | 245 | - `entry`: The entry this change gets applied to. |
| 228 | - `flags`: See definition of `entry_change_flags`. | 246 | - `flags`: See definition of `entry_change_flags`. |
| 229 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET | 247 | - `deobf_name`: The new deobfuscated name, if deobf_name_change == TRISTATE_CHANGE_SET |
| @@ -231,6 +249,7 @@ struct entry_change { | |||
| 231 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) | 249 | - `access_modifiers`: The new access modifier, if access_change == TRISTATE_CHANGE_SET (otherwise 0) |
| 232 | 250 | ||
| 233 | ### Login (client-to-server) | 251 | ### Login (client-to-server) |
| 252 | |||
| 234 | ```c | 253 | ```c |
| 235 | struct LoginC2SPacket { | 254 | struct LoginC2SPacket { |
| 236 | unsigned short protocol_version; | 255 | unsigned short protocol_version; |
| @@ -240,47 +259,57 @@ struct LoginC2SPacket { | |||
| 240 | utf username; | 259 | utf username; |
| 241 | } | 260 | } |
| 242 | ``` | 261 | ``` |
| 262 | |||
| 243 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be | 263 | - `protocol_version`: the version of the protocol. If the version does not match on the server, then the client will be |
| 244 | kicked immediately. Currently always equal to 0. | 264 | kicked immediately. Currently always equal to 0. |
| 245 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file | 265 | - `checksum`: the SHA-1 hash of the JAR file the client has open. If this does not match the SHA-1 hash of the JAR file |
| 246 | the server has open, the client will be kicked. | 266 | the server has open, the client will be kicked. |
| 247 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. | 267 | - `password`: the password needed to log into the server. Note that each `char` is 2 bytes, as per the Java data type. |
| 248 | If this password is incorrect, the client will be kicked. | 268 | If this password is incorrect, the client will be kicked. |
| 249 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. | 269 | - `username`: the username of the user logging in. If the username is not unique, the client will be kicked. |
| 250 | 270 | ||
| 251 | ### ConfirmChange (client-to-server) | 271 | ### ConfirmChange (client-to-server) |
| 272 | |||
| 252 | ```c | 273 | ```c |
| 253 | struct ConfirmChangeC2SPacket { | 274 | struct ConfirmChangeC2SPacket { |
| 254 | unsigned short sync_id; | 275 | unsigned short sync_id; |
| 255 | } | 276 | } |
| 256 | ``` | 277 | ``` |
| 278 | |||
| 257 | - `sync_id`: the sync ID to confirm. | 279 | - `sync_id`: the sync ID to confirm. |
| 258 | 280 | ||
| 259 | ### Message (client-to-server) | 281 | ### Message (client-to-server) |
| 282 | |||
| 260 | ```c | 283 | ```c |
| 261 | struct MessageC2SPacket { | 284 | struct MessageC2SPacket { |
| 262 | utf message; | 285 | utf message; |
| 263 | } | 286 | } |
| 264 | ``` | 287 | ``` |
| 288 | |||
| 265 | - `message`: The text message the user sent. | 289 | - `message`: The text message the user sent. |
| 266 | 290 | ||
| 267 | ### EntryChange (client-to-server) | 291 | ### EntryChange (client-to-server) |
| 292 | |||
| 268 | ```c | 293 | ```c |
| 269 | struct EntryChangeC2SPacket { | 294 | struct EntryChangeC2SPacket { |
| 270 | entry_change change; | 295 | entry_change change; |
| 271 | } | 296 | } |
| 272 | ``` | 297 | ``` |
| 298 | |||
| 273 | - `change`: The change to apply. | 299 | - `change`: The change to apply. |
| 274 | 300 | ||
| 275 | ### Kick (server-to-client) | 301 | ### Kick (server-to-client) |
| 302 | |||
| 276 | ```c | 303 | ```c |
| 277 | struct KickS2CPacket { | 304 | struct KickS2CPacket { |
| 278 | utf reason; | 305 | utf reason; |
| 279 | } | 306 | } |
| 280 | ``` | 307 | ``` |
| 308 | |||
| 281 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. | 309 | - `reason`: the reason for the kick, may or may not be a translation key for the client to display to the user. |
| 282 | 310 | ||
| 283 | ### SyncMappings (server-to-client) | 311 | ### SyncMappings (server-to-client) |
| 312 | |||
| 284 | ```c | 313 | ```c |
| 285 | struct SyncMappingsS2CPacket { | 314 | struct SyncMappingsS2CPacket { |
| 286 | int num_roots; | 315 | int num_roots; |
| @@ -296,6 +325,7 @@ struct MappingNode { | |||
| 296 | } | 325 | } |
| 297 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; | 326 | typedef { Entry but without the has_parent or parent fields } NoParentEntry; |
| 298 | ``` | 327 | ``` |
| 328 | |||
| 299 | - `roots`: The root mapping nodes, containing all the entries without parents. | 329 | - `roots`: The root mapping nodes, containing all the entries without parents. |
| 300 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. | 330 | - `obf_entry`: The value of a node, containing the obfuscated name and descriptor of the entry. |
| 301 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. | 331 | - `name`: The deobfuscated name of the entry, if it exists, otherwise the empty string. |
| @@ -303,6 +333,7 @@ typedef { Entry but without the has_parent or parent fields } NoParentEntry; | |||
| 303 | - `children`: The children of this node | 333 | - `children`: The children of this node |
| 304 | 334 | ||
| 305 | ### Message (server-to-client) | 335 | ### Message (server-to-client) |
| 336 | |||
| 306 | ```c | 337 | ```c |
| 307 | struct MessageS2CPacket { | 338 | struct MessageS2CPacket { |
| 308 | Message message; | 339 | Message message; |
| @@ -310,6 +341,7 @@ struct MessageS2CPacket { | |||
| 310 | ``` | 341 | ``` |
| 311 | 342 | ||
| 312 | ### UserList (server-to-client) | 343 | ### UserList (server-to-client) |
| 344 | |||
| 313 | ```c | 345 | ```c |
| 314 | struct UserListS2CPacket { | 346 | struct UserListS2CPacket { |
| 315 | unsigned short len; | 347 | unsigned short len; |
| @@ -318,11 +350,13 @@ struct UserListS2CPacket { | |||
| 318 | ``` | 350 | ``` |
| 319 | 351 | ||
| 320 | ### EntryChange (server-to-client) | 352 | ### EntryChange (server-to-client) |
| 353 | |||
| 321 | ```c | 354 | ```c |
| 322 | struct EntryChangeS2CPacket { | 355 | struct EntryChangeS2CPacket { |
| 323 | uint16_t sync_id; | 356 | uint16_t sync_id; |
| 324 | entry_change change; | 357 | entry_change change; |
| 325 | } | 358 | } |
| 326 | ``` | 359 | ``` |
| 360 | |||
| 327 | - `sync_id`: The sync ID of the change for locking purposes. | 361 | - `sync_id`: The sync ID of the change for locking purposes. |
| 328 | - `change`: The change to apply. \ No newline at end of file | 362 | - `change`: The change to apply. \ No newline at end of file |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java b/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java index a651fe84..8fcd4372 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ClientPacketHandler.java | |||
| @@ -1,22 +1,22 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import java.util.List; | ||
| 4 | |||
| 5 | import cuchaz.enigma.network.packet.Packet; | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryChange; | 6 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 6 | import cuchaz.enigma.network.packet.Packet; | ||
| 7 | |||
| 8 | import java.util.List; | ||
| 9 | 9 | ||
| 10 | public interface ClientPacketHandler { | 10 | public interface ClientPacketHandler { |
| 11 | void openMappings(EntryTree<EntryMapping> mappings); | 11 | void openMappings(EntryTree<EntryMapping> mappings); |
| 12 | 12 | ||
| 13 | boolean applyChangeFromServer(EntryChange<?> change); | 13 | boolean applyChangeFromServer(EntryChange<?> change); |
| 14 | 14 | ||
| 15 | void disconnectIfConnected(String reason); | 15 | void disconnectIfConnected(String reason); |
| 16 | 16 | ||
| 17 | void sendPacket(Packet<ServerPacketHandler> packet); | 17 | void sendPacket(Packet<ServerPacketHandler> packet); |
| 18 | 18 | ||
| 19 | void addMessage(Message message); | 19 | void addMessage(Message message); |
| 20 | 20 | ||
| 21 | void updateUserList(List<String> users); | 21 | void updateUserList(List<String> users); |
| 22 | } | 22 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java index 41f08342..eb22a506 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java | |||
| @@ -1,17 +1,5 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import com.google.common.io.MoreFiles; | ||
| 4 | import cuchaz.enigma.*; | ||
| 5 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | ||
| 6 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | ||
| 9 | import cuchaz.enigma.utils.Utils; | ||
| 10 | import joptsimple.OptionParser; | ||
| 11 | import joptsimple.OptionSet; | ||
| 12 | import joptsimple.OptionSpec; | ||
| 13 | import joptsimple.ValueConverter; | ||
| 14 | |||
| 15 | import java.io.IOException; | 3 | import java.io.IOException; |
| 16 | import java.io.PrintWriter; | 4 | import java.io.PrintWriter; |
| 17 | import java.nio.file.Files; | 5 | import java.nio.file.Files; |
| @@ -22,24 +10,30 @@ import java.util.concurrent.Executors; | |||
| 22 | import java.util.concurrent.LinkedBlockingDeque; | 10 | import java.util.concurrent.LinkedBlockingDeque; |
| 23 | import java.util.concurrent.TimeUnit; | 11 | import java.util.concurrent.TimeUnit; |
| 24 | 12 | ||
| 25 | public class DedicatedEnigmaServer extends EnigmaServer { | 13 | import com.google.common.io.MoreFiles; |
| 14 | import joptsimple.OptionParser; | ||
| 15 | import joptsimple.OptionSet; | ||
| 16 | import joptsimple.OptionSpec; | ||
| 17 | import joptsimple.ValueConverter; | ||
| 18 | |||
| 19 | import cuchaz.enigma.Enigma; | ||
| 20 | import cuchaz.enigma.EnigmaProfile; | ||
| 21 | import cuchaz.enigma.EnigmaProject; | ||
| 22 | import cuchaz.enigma.ProgressListener; | ||
| 23 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | ||
| 24 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 25 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | ||
| 26 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 27 | import cuchaz.enigma.utils.Utils; | ||
| 26 | 28 | ||
| 29 | public class DedicatedEnigmaServer extends EnigmaServer { | ||
| 27 | private final EnigmaProfile profile; | 30 | private final EnigmaProfile profile; |
| 28 | private final MappingFormat mappingFormat; | 31 | private final MappingFormat mappingFormat; |
| 29 | private final Path mappingsFile; | 32 | private final Path mappingsFile; |
| 30 | private final PrintWriter log; | 33 | private final PrintWriter log; |
| 31 | private BlockingQueue<Runnable> tasks = new LinkedBlockingDeque<>(); | 34 | private BlockingQueue<Runnable> tasks = new LinkedBlockingDeque<>(); |
| 32 | 35 | ||
| 33 | public DedicatedEnigmaServer( | 36 | public DedicatedEnigmaServer(byte[] jarChecksum, char[] password, EnigmaProfile profile, MappingFormat mappingFormat, Path mappingsFile, PrintWriter log, EntryRemapper mappings, int port) { |
| 34 | byte[] jarChecksum, | ||
| 35 | char[] password, | ||
| 36 | EnigmaProfile profile, | ||
| 37 | MappingFormat mappingFormat, | ||
| 38 | Path mappingsFile, | ||
| 39 | PrintWriter log, | ||
| 40 | EntryRemapper mappings, | ||
| 41 | int port | ||
| 42 | ) { | ||
| 43 | super(jarChecksum, password, mappings, port); | 37 | super(jarChecksum, password, mappings, port); |
| 44 | this.profile = profile; | 38 | this.profile = profile; |
| 45 | this.mappingFormat = mappingFormat; | 39 | this.mappingFormat = mappingFormat; |
| @@ -61,33 +55,17 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 61 | public static void main(String[] args) { | 55 | public static void main(String[] args) { |
| 62 | OptionParser parser = new OptionParser(); | 56 | OptionParser parser = new OptionParser(); |
| 63 | 57 | ||
| 64 | OptionSpec<Path> jarOpt = parser.accepts("jar", "Jar file to open at startup") | 58 | OptionSpec<Path> jarOpt = parser.accepts("jar", "Jar file to open at startup").withRequiredArg().required().withValuesConvertedBy(PathConverter.INSTANCE); |
| 65 | .withRequiredArg() | ||
| 66 | .required() | ||
| 67 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 68 | 59 | ||
| 69 | OptionSpec<Path> mappingsOpt = parser.accepts("mappings", "Mappings file to open at startup") | 60 | OptionSpec<Path> mappingsOpt = parser.accepts("mappings", "Mappings file to open at startup").withRequiredArg().required().withValuesConvertedBy(PathConverter.INSTANCE); |
| 70 | .withRequiredArg() | ||
| 71 | .required() | ||
| 72 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 73 | 61 | ||
| 74 | OptionSpec<Path> profileOpt = parser.accepts("profile", "Profile json to apply at startup") | 62 | OptionSpec<Path> profileOpt = parser.accepts("profile", "Profile json to apply at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE); |
| 75 | .withRequiredArg() | ||
| 76 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 77 | 63 | ||
| 78 | OptionSpec<Integer> portOpt = parser.accepts("port", "Port to run the server on") | 64 | OptionSpec<Integer> portOpt = parser.accepts("port", "Port to run the server on").withOptionalArg().ofType(Integer.class).defaultsTo(EnigmaServer.DEFAULT_PORT); |
| 79 | .withOptionalArg() | ||
| 80 | .ofType(Integer.class) | ||
| 81 | .defaultsTo(EnigmaServer.DEFAULT_PORT); | ||
| 82 | 65 | ||
| 83 | OptionSpec<String> passwordOpt = parser.accepts("password", "The password to join the server") | 66 | OptionSpec<String> passwordOpt = parser.accepts("password", "The password to join the server").withRequiredArg().defaultsTo(""); |
| 84 | .withRequiredArg() | ||
| 85 | .defaultsTo(""); | ||
| 86 | 67 | ||
| 87 | OptionSpec<Path> logFileOpt = parser.accepts("log", "The log file to write to") | 68 | OptionSpec<Path> logFileOpt = parser.accepts("log", "The log file to write to").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE).defaultsTo(Paths.get("log.txt")); |
| 88 | .withRequiredArg() | ||
| 89 | .withValuesConvertedBy(PathConverter.INSTANCE) | ||
| 90 | .defaultsTo(Paths.get("log.txt")); | ||
| 91 | 69 | ||
| 92 | OptionSet parsedArgs = parser.parse(args); | 70 | OptionSet parsedArgs = parser.parse(args); |
| 93 | Path jar = parsedArgs.valueOf(jarOpt); | 71 | Path jar = parsedArgs.valueOf(jarOpt); |
| @@ -95,14 +73,17 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 95 | Path profileFile = parsedArgs.valueOf(profileOpt); | 73 | Path profileFile = parsedArgs.valueOf(profileOpt); |
| 96 | int port = parsedArgs.valueOf(portOpt); | 74 | int port = parsedArgs.valueOf(portOpt); |
| 97 | char[] password = parsedArgs.valueOf(passwordOpt).toCharArray(); | 75 | char[] password = parsedArgs.valueOf(passwordOpt).toCharArray(); |
| 76 | |||
| 98 | if (password.length > EnigmaServer.MAX_PASSWORD_LENGTH) { | 77 | if (password.length > EnigmaServer.MAX_PASSWORD_LENGTH) { |
| 99 | System.err.println("Password too long, must be at most " + EnigmaServer.MAX_PASSWORD_LENGTH + " characters"); | 78 | System.err.println("Password too long, must be at most " + EnigmaServer.MAX_PASSWORD_LENGTH + " characters"); |
| 100 | System.exit(1); | 79 | System.exit(1); |
| 101 | } | 80 | } |
| 81 | |||
| 102 | Path logFile = parsedArgs.valueOf(logFileOpt); | 82 | Path logFile = parsedArgs.valueOf(logFileOpt); |
| 103 | 83 | ||
| 104 | System.out.println("Starting Enigma server"); | 84 | System.out.println("Starting Enigma server"); |
| 105 | DedicatedEnigmaServer server; | 85 | DedicatedEnigmaServer server; |
| 86 | |||
| 106 | try { | 87 | try { |
| 107 | byte[] checksum = Utils.zipSha1(parsedArgs.valueOf(jarOpt)); | 88 | byte[] checksum = Utils.zipSha1(parsedArgs.valueOf(jarOpt)); |
| 108 | 89 | ||
| @@ -113,10 +94,12 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 113 | 94 | ||
| 114 | MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY; | 95 | MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY; |
| 115 | EntryRemapper mappings; | 96 | EntryRemapper mappings; |
| 97 | |||
| 116 | if (!Files.exists(mappingsFile)) { | 98 | if (!Files.exists(mappingsFile)) { |
| 117 | mappings = EntryRemapper.empty(project.getJarIndex()); | 99 | mappings = EntryRemapper.empty(project.getJarIndex()); |
| 118 | } else { | 100 | } else { |
| 119 | System.out.println("Reading mappings..."); | 101 | System.out.println("Reading mappings..."); |
| 102 | |||
| 120 | if (Files.isDirectory(mappingsFile)) { | 103 | if (Files.isDirectory(mappingsFile)) { |
| 121 | mappingFormat = MappingFormat.ENIGMA_DIRECTORY; | 104 | mappingFormat = MappingFormat.ENIGMA_DIRECTORY; |
| 122 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsFile))) { | 105 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsFile))) { |
| @@ -124,6 +107,7 @@ public class DedicatedEnigmaServer extends EnigmaServer { | |||
| 124 | } else { | 107 | } else { |
| 125 | mappingFormat = MappingFormat.ENIGMA_FILE; | 108 | mappingFormat = MappingFormat.ENIGMA_FILE; |
| 126 | } | 109 | } |
| 110 | |||
| 127 | mappings = EntryRemapper.mapped(project.getJarIndex(), mappingFormat.read(mappingsFile, ProgressListener.none(), profile.getMappingSaveParameters())); | 111 | mappings = EntryRemapper.mapped(project.getJarIndex(), mappingFormat.read(mappingsFile, ProgressListener.none(), profile.getMappingSaveParameters())); |
| 128 | } | 112 | } |
| 129 | 113 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java index 71bd011c..69e4f5ef 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaClient.java | |||
| @@ -1,15 +1,20 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.packet.Packet; | 3 | import java.io.DataInput; |
| 4 | import cuchaz.enigma.network.packet.PacketRegistry; | 4 | import java.io.DataInputStream; |
| 5 | 5 | import java.io.DataOutput; | |
| 6 | import javax.swing.*; | 6 | import java.io.DataOutputStream; |
| 7 | import java.io.*; | 7 | import java.io.EOFException; |
| 8 | import java.io.IOException; | ||
| 8 | import java.net.Socket; | 9 | import java.net.Socket; |
| 9 | import java.net.SocketException; | 10 | import java.net.SocketException; |
| 10 | 11 | ||
| 11 | public class EnigmaClient { | 12 | import javax.swing.SwingUtilities; |
| 12 | 13 | ||
| 14 | import cuchaz.enigma.network.packet.Packet; | ||
| 15 | import cuchaz.enigma.network.packet.PacketRegistry; | ||
| 16 | |||
| 17 | public class EnigmaClient { | ||
| 13 | private final ClientPacketHandler controller; | 18 | private final ClientPacketHandler controller; |
| 14 | 19 | ||
| 15 | private final String ip; | 20 | private final String ip; |
| @@ -29,17 +34,22 @@ public class EnigmaClient { | |||
| 29 | Thread thread = new Thread(() -> { | 34 | Thread thread = new Thread(() -> { |
| 30 | try { | 35 | try { |
| 31 | DataInput input = new DataInputStream(socket.getInputStream()); | 36 | DataInput input = new DataInputStream(socket.getInputStream()); |
| 37 | |||
| 32 | while (true) { | 38 | while (true) { |
| 33 | int packetId; | 39 | int packetId; |
| 40 | |||
| 34 | try { | 41 | try { |
| 35 | packetId = input.readUnsignedByte(); | 42 | packetId = input.readUnsignedByte(); |
| 36 | } catch (EOFException | SocketException e) { | 43 | } catch (EOFException | SocketException e) { |
| 37 | break; | 44 | break; |
| 38 | } | 45 | } |
| 46 | |||
| 39 | Packet<ClientPacketHandler> packet = PacketRegistry.createS2CPacket(packetId); | 47 | Packet<ClientPacketHandler> packet = PacketRegistry.createS2CPacket(packetId); |
| 48 | |||
| 40 | if (packet == null) { | 49 | if (packet == null) { |
| 41 | throw new IOException("Received invalid packet id " + packetId); | 50 | throw new IOException("Received invalid packet id " + packetId); |
| 42 | } | 51 | } |
| 52 | |||
| 43 | packet.read(input); | 53 | packet.read(input); |
| 44 | SwingUtilities.invokeLater(() -> packet.handle(controller)); | 54 | SwingUtilities.invokeLater(() -> packet.handle(controller)); |
| 45 | } | 55 | } |
| @@ -47,6 +57,7 @@ public class EnigmaClient { | |||
| 47 | controller.disconnectIfConnected(e.toString()); | 57 | controller.disconnectIfConnected(e.toString()); |
| 48 | return; | 58 | return; |
| 49 | } | 59 | } |
| 60 | |||
| 50 | controller.disconnectIfConnected("Disconnected"); | 61 | controller.disconnectIfConnected("Disconnected"); |
| 51 | }); | 62 | }); |
| 52 | thread.setName("Client I/O thread"); | 63 | thread.setName("Client I/O thread"); |
| @@ -65,7 +76,6 @@ public class EnigmaClient { | |||
| 65 | } | 76 | } |
| 66 | } | 77 | } |
| 67 | 78 | ||
| 68 | |||
| 69 | public void sendPacket(Packet<ServerPacketHandler> packet) { | 79 | public void sendPacket(Packet<ServerPacketHandler> packet) { |
| 70 | try { | 80 | try { |
| 71 | output.writeByte(PacketRegistry.getC2SId(packet)); | 81 | output.writeByte(PacketRegistry.getC2SId(packet)); |
| @@ -74,5 +84,4 @@ public class EnigmaClient { | |||
| 74 | controller.disconnectIfConnected(e.toString()); | 84 | controller.disconnectIfConnected(e.toString()); |
| 75 | } | 85 | } |
| 76 | } | 86 | } |
| 77 | |||
| 78 | } | 87 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java index 1ce359b6..8872735d 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/EnigmaServer.java | |||
| @@ -1,20 +1,35 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import java.io.*; | 3 | import java.io.DataInput; |
| 4 | import java.io.DataInputStream; | ||
| 5 | import java.io.DataOutput; | ||
| 6 | import java.io.DataOutputStream; | ||
| 7 | import java.io.EOFException; | ||
| 8 | import java.io.IOException; | ||
| 4 | import java.net.ServerSocket; | 9 | import java.net.ServerSocket; |
| 5 | import java.net.Socket; | 10 | import java.net.Socket; |
| 6 | import java.net.SocketException; | 11 | import java.net.SocketException; |
| 7 | import java.util.*; | 12 | import java.util.ArrayList; |
| 13 | import java.util.Collections; | ||
| 14 | import java.util.HashMap; | ||
| 15 | import java.util.HashSet; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.Map; | ||
| 18 | import java.util.Set; | ||
| 8 | import java.util.concurrent.CopyOnWriteArrayList; | 19 | import java.util.concurrent.CopyOnWriteArrayList; |
| 9 | 20 | ||
| 10 | import cuchaz.enigma.network.packet.*; | 21 | import cuchaz.enigma.network.packet.EntryChangeS2CPacket; |
| 22 | import cuchaz.enigma.network.packet.KickS2CPacket; | ||
| 23 | import cuchaz.enigma.network.packet.MessageS2CPacket; | ||
| 24 | import cuchaz.enigma.network.packet.Packet; | ||
| 25 | import cuchaz.enigma.network.packet.PacketRegistry; | ||
| 26 | import cuchaz.enigma.network.packet.UserListS2CPacket; | ||
| 11 | import cuchaz.enigma.translation.mapping.EntryChange; | 27 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 12 | import cuchaz.enigma.translation.mapping.EntryMapping; | 28 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 13 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 29 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 14 | import cuchaz.enigma.translation.representation.entry.Entry; | 30 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 15 | 31 | ||
| 16 | public abstract class EnigmaServer { | 32 | public abstract class EnigmaServer { |
| 17 | |||
| 18 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 | 33 | // https://discordapp.com/channels/507304429255393322/566418023372816394/700292322918793347 |
| 19 | public static final int DEFAULT_PORT = 34712; | 34 | public static final int DEFAULT_PORT = 34712; |
| 20 | public static final int PROTOCOL_VERSION = 1; | 35 | public static final int PROTOCOL_VERSION = 1; |
| @@ -71,17 +86,22 @@ public abstract class EnigmaServer { | |||
| 71 | Thread thread = new Thread(() -> { | 86 | Thread thread = new Thread(() -> { |
| 72 | try { | 87 | try { |
| 73 | DataInput input = new DataInputStream(client.getInputStream()); | 88 | DataInput input = new DataInputStream(client.getInputStream()); |
| 89 | |||
| 74 | while (true) { | 90 | while (true) { |
| 75 | int packetId; | 91 | int packetId; |
| 92 | |||
| 76 | try { | 93 | try { |
| 77 | packetId = input.readUnsignedByte(); | 94 | packetId = input.readUnsignedByte(); |
| 78 | } catch (EOFException | SocketException e) { | 95 | } catch (EOFException | SocketException e) { |
| 79 | break; | 96 | break; |
| 80 | } | 97 | } |
| 98 | |||
| 81 | Packet<ServerPacketHandler> packet = PacketRegistry.createC2SPacket(packetId); | 99 | Packet<ServerPacketHandler> packet = PacketRegistry.createC2SPacket(packetId); |
| 100 | |||
| 82 | if (packet == null) { | 101 | if (packet == null) { |
| 83 | throw new IOException("Received invalid packet id " + packetId); | 102 | throw new IOException("Received invalid packet id " + packetId); |
| 84 | } | 103 | } |
| 104 | |||
| 85 | packet.read(input); | 105 | packet.read(input); |
| 86 | runOnThread(() -> packet.handle(new ServerPacketHandler(client, this))); | 106 | runOnThread(() -> packet.handle(new ServerPacketHandler(client, this))); |
| 87 | } | 107 | } |
| @@ -90,6 +110,7 @@ public abstract class EnigmaServer { | |||
| 90 | e.printStackTrace(); | 110 | e.printStackTrace(); |
| 91 | return; | 111 | return; |
| 92 | } | 112 | } |
| 113 | |||
| 93 | kick(client, "disconnect.disconnected"); | 114 | kick(client, "disconnect.disconnected"); |
| 94 | }); | 115 | }); |
| 95 | thread.setName("Server I/O thread #" + (nextIoId++)); | 116 | thread.setName("Server I/O thread #" + (nextIoId++)); |
| @@ -103,6 +124,7 @@ public abstract class EnigmaServer { | |||
| 103 | for (Socket client : clients) { | 124 | for (Socket client : clients) { |
| 104 | kick(client, "disconnect.server_closed"); | 125 | kick(client, "disconnect.server_closed"); |
| 105 | } | 126 | } |
| 127 | |||
| 106 | try { | 128 | try { |
| 107 | socket.close(); | 129 | socket.close(); |
| 108 | } catch (IOException e) { | 130 | } catch (IOException e) { |
| @@ -114,7 +136,9 @@ public abstract class EnigmaServer { | |||
| 114 | } | 136 | } |
| 115 | 137 | ||
| 116 | public void kick(Socket client, String reason) { | 138 | public void kick(Socket client, String reason) { |
| 117 | if (!clients.remove(client)) return; | 139 | if (!clients.remove(client)) { |
| 140 | return; | ||
| 141 | } | ||
| 118 | 142 | ||
| 119 | sendPacket(client, new KickS2CPacket(reason)); | 143 | sendPacket(client, new KickS2CPacket(reason)); |
| 120 | 144 | ||
| @@ -123,6 +147,7 @@ public abstract class EnigmaServer { | |||
| 123 | return list.isEmpty(); | 147 | return list.isEmpty(); |
| 124 | }); | 148 | }); |
| 125 | String username = usernames.remove(client); | 149 | String username = usernames.remove(client); |
| 150 | |||
| 126 | try { | 151 | try { |
| 127 | client.close(); | 152 | client.close(); |
| 128 | } catch (IOException e) { | 153 | } catch (IOException e) { |
| @@ -134,6 +159,7 @@ public abstract class EnigmaServer { | |||
| 134 | System.out.println("Kicked " + username + " because " + reason); | 159 | System.out.println("Kicked " + username + " because " + reason); |
| 135 | sendMessage(Message.disconnect(username)); | 160 | sendMessage(Message.disconnect(username)); |
| 136 | } | 161 | } |
| 162 | |||
| 137 | sendUsernamePacket(); | 163 | sendUsernamePacket(); |
| 138 | } | 164 | } |
| 139 | 165 | ||
| @@ -159,6 +185,7 @@ public abstract class EnigmaServer { | |||
| 159 | public void sendPacket(Socket client, Packet<ClientPacketHandler> packet) { | 185 | public void sendPacket(Socket client, Packet<ClientPacketHandler> packet) { |
| 160 | if (!client.isClosed()) { | 186 | if (!client.isClosed()) { |
| 161 | int packetId = PacketRegistry.getS2CId(packet); | 187 | int packetId = PacketRegistry.getS2CId(packet); |
| 188 | |||
| 162 | try { | 189 | try { |
| 163 | DataOutput output = new DataOutputStream(client.getOutputStream()); | 190 | DataOutput output = new DataOutputStream(client.getOutputStream()); |
| 164 | output.writeByte(packetId); | 191 | output.writeByte(packetId); |
| @@ -192,9 +219,11 @@ public abstract class EnigmaServer { | |||
| 192 | } | 219 | } |
| 193 | 220 | ||
| 194 | Integer syncId = syncIds.get(entry); | 221 | Integer syncId = syncIds.get(entry); |
| 222 | |||
| 195 | if (syncId == null) { | 223 | if (syncId == null) { |
| 196 | return true; | 224 | return true; |
| 197 | } | 225 | } |
| 226 | |||
| 198 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); | 227 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); |
| 199 | return clients == null || !clients.contains(client); | 228 | return clients == null || !clients.contains(client); |
| 200 | } | 229 | } |
| @@ -202,14 +231,18 @@ public abstract class EnigmaServer { | |||
| 202 | public int lockEntry(Socket exception, Entry<?> entry) { | 231 | public int lockEntry(Socket exception, Entry<?> entry) { |
| 203 | int syncId = nextSyncId; | 232 | int syncId = nextSyncId; |
| 204 | nextSyncId++; | 233 | nextSyncId++; |
| 234 | |||
| 205 | // sync id is sent as an unsigned short, can't have more than 65536 | 235 | // sync id is sent as an unsigned short, can't have more than 65536 |
| 206 | if (nextSyncId == 65536) { | 236 | if (nextSyncId == 65536) { |
| 207 | nextSyncId = DUMMY_SYNC_ID + 1; | 237 | nextSyncId = DUMMY_SYNC_ID + 1; |
| 208 | } | 238 | } |
| 239 | |||
| 209 | Integer oldSyncId = syncIds.get(entry); | 240 | Integer oldSyncId = syncIds.get(entry); |
| 241 | |||
| 210 | if (oldSyncId != null) { | 242 | if (oldSyncId != null) { |
| 211 | clientsNeedingConfirmation.remove(oldSyncId); | 243 | clientsNeedingConfirmation.remove(oldSyncId); |
| 212 | } | 244 | } |
| 245 | |||
| 213 | syncIds.put(entry, syncId); | 246 | syncIds.put(entry, syncId); |
| 214 | inverseSyncIds.put(syncId, entry); | 247 | inverseSyncIds.put(syncId, entry); |
| 215 | Set<Socket> clients = new HashSet<>(this.clients); | 248 | Set<Socket> clients = new HashSet<>(this.clients); |
| @@ -224,8 +257,10 @@ public abstract class EnigmaServer { | |||
| 224 | } | 257 | } |
| 225 | 258 | ||
| 226 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); | 259 | Set<Socket> clients = clientsNeedingConfirmation.get(syncId); |
| 260 | |||
| 227 | if (clients != null) { | 261 | if (clients != null) { |
| 228 | clients.remove(client); | 262 | clients.remove(client); |
| 263 | |||
| 229 | if (clients.isEmpty()) { | 264 | if (clients.isEmpty()) { |
| 230 | clientsNeedingConfirmation.remove(syncId); | 265 | clientsNeedingConfirmation.remove(syncId); |
| 231 | syncIds.remove(inverseSyncIds.remove(syncId)); | 266 | syncIds.remove(inverseSyncIds.remove(syncId)); |
| @@ -236,6 +271,7 @@ public abstract class EnigmaServer { | |||
| 236 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { | 271 | public void sendCorrectMapping(Socket client, Entry<?> entry, boolean refreshClassTree) { |
| 237 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); | 272 | EntryMapping oldMapping = mappings.getDeobfMapping(entry); |
| 238 | String oldName = oldMapping.targetName(); | 273 | String oldName = oldMapping.targetName(); |
| 274 | |||
| 239 | if (oldName == null) { | 275 | if (oldName == null) { |
| 240 | sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); | 276 | sendPacket(client, new EntryChangeS2CPacket(DUMMY_SYNC_ID, EntryChange.modify(entry).clearDeobfName())); |
| 241 | } else { | 277 | } else { |
| @@ -269,5 +305,4 @@ public abstract class EnigmaServer { | |||
| 269 | log(String.format("[MSG] %s", message.translate())); | 305 | log(String.format("[MSG] %s", message.translate())); |
| 270 | sendToAll(new MessageS2CPacket(message)); | 306 | sendToAll(new MessageS2CPacket(message)); |
| 271 | } | 307 | } |
| 272 | |||
| 273 | } | 308 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java index 21c6825b..99e4e99e 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/IntegratedEnigmaServer.java | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 3 | import javax.swing.SwingUtilities; |
| 4 | 4 | ||
| 5 | import javax.swing.*; | 5 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 6 | 6 | ||
| 7 | public class IntegratedEnigmaServer extends EnigmaServer { | 7 | public class IntegratedEnigmaServer extends EnigmaServer { |
| 8 | public IntegratedEnigmaServer(byte[] jarChecksum, char[] password, EntryRemapper mappings, int port) { | 8 | public IntegratedEnigmaServer(byte[] jarChecksum, char[] password, EntryRemapper mappings, int port) { |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/Message.java b/enigma-server/src/main/java/cuchaz/enigma/network/Message.java index c1578387..d49e60cb 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/Message.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/Message.java | |||
| @@ -10,9 +10,8 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 10 | import cuchaz.enigma.utils.I18n; | 10 | import cuchaz.enigma.utils.I18n; |
| 11 | 11 | ||
| 12 | public abstract class Message { | 12 | public abstract class Message { |
| 13 | |||
| 14 | public final String user; | 13 | public final String user; |
| 15 | 14 | ||
| 16 | public static Chat chat(String user, String message) { | 15 | public static Chat chat(String user, String message) { |
| 17 | return new Chat(user, message); | 16 | return new Chat(user, message); |
| 18 | } | 17 | } |
| @@ -47,34 +46,37 @@ public abstract class Message { | |||
| 47 | 46 | ||
| 48 | public static Message read(DataInput input) throws IOException { | 47 | public static Message read(DataInput input) throws IOException { |
| 49 | byte typeId = input.readByte(); | 48 | byte typeId = input.readByte(); |
| 49 | |||
| 50 | if (typeId < 0 || typeId >= Type.values().length) { | 50 | if (typeId < 0 || typeId >= Type.values().length) { |
| 51 | throw new IOException(String.format("Invalid message type ID %d", typeId)); | 51 | throw new IOException(String.format("Invalid message type ID %d", typeId)); |
| 52 | } | 52 | } |
| 53 | |||
| 53 | Type type = Type.values()[typeId]; | 54 | Type type = Type.values()[typeId]; |
| 54 | String user = input.readUTF(); | 55 | String user = input.readUTF(); |
| 56 | |||
| 55 | switch (type) { | 57 | switch (type) { |
| 56 | case CHAT: | 58 | case CHAT: |
| 57 | String message = input.readUTF(); | 59 | String message = input.readUTF(); |
| 58 | return chat(user, message); | 60 | return chat(user, message); |
| 59 | case CONNECT: | 61 | case CONNECT: |
| 60 | return connect(user); | 62 | return connect(user); |
| 61 | case DISCONNECT: | 63 | case DISCONNECT: |
| 62 | return disconnect(user); | 64 | return disconnect(user); |
| 63 | case EDIT_DOCS: | 65 | case EDIT_DOCS: |
| 64 | Entry<?> entry = PacketHelper.readEntry(input); | 66 | Entry<?> entry = PacketHelper.readEntry(input); |
| 65 | return editDocs(user, entry); | 67 | return editDocs(user, entry); |
| 66 | case MARK_DEOBF: | 68 | case MARK_DEOBF: |
| 67 | entry = PacketHelper.readEntry(input); | 69 | entry = PacketHelper.readEntry(input); |
| 68 | return markDeobf(user, entry); | 70 | return markDeobf(user, entry); |
| 69 | case REMOVE_MAPPING: | 71 | case REMOVE_MAPPING: |
| 70 | entry = PacketHelper.readEntry(input); | 72 | entry = PacketHelper.readEntry(input); |
| 71 | return removeMapping(user, entry); | 73 | return removeMapping(user, entry); |
| 72 | case RENAME: | 74 | case RENAME: |
| 73 | entry = PacketHelper.readEntry(input); | 75 | entry = PacketHelper.readEntry(input); |
| 74 | String newName = input.readUTF(); | 76 | String newName = input.readUTF(); |
| 75 | return rename(user, entry, newName); | 77 | return rename(user, entry, newName); |
| 76 | default: | 78 | default: |
| 77 | throw new IllegalStateException("unreachable"); | 79 | throw new IllegalStateException("unreachable"); |
| 78 | } | 80 | } |
| 79 | } | 81 | } |
| 80 | 82 | ||
| @@ -89,8 +91,14 @@ public abstract class Message { | |||
| 89 | 91 | ||
| 90 | @Override | 92 | @Override |
| 91 | public boolean equals(Object o) { | 93 | public boolean equals(Object o) { |
| 92 | if (this == o) return true; | 94 | if (this == o) { |
| 93 | if (o == null || getClass() != o.getClass()) return false; | 95 | return true; |
| 96 | } | ||
| 97 | |||
| 98 | if (o == null || getClass() != o.getClass()) { | ||
| 99 | return false; | ||
| 100 | } | ||
| 101 | |||
| 94 | Message message = (Message) o; | 102 | Message message = (Message) o; |
| 95 | return Objects.equals(user, message.user); | 103 | return Objects.equals(user, message.user); |
| 96 | } | 104 | } |
| @@ -111,7 +119,6 @@ public abstract class Message { | |||
| 111 | } | 119 | } |
| 112 | 120 | ||
| 113 | public static final class Chat extends Message { | 121 | public static final class Chat extends Message { |
| 114 | |||
| 115 | public final String message; | 122 | public final String message; |
| 116 | 123 | ||
| 117 | private Chat(String user, String message) { | 124 | private Chat(String user, String message) { |
| @@ -137,9 +144,18 @@ public abstract class Message { | |||
| 137 | 144 | ||
| 138 | @Override | 145 | @Override |
| 139 | public boolean equals(Object o) { | 146 | public boolean equals(Object o) { |
| 140 | if (this == o) return true; | 147 | if (this == o) { |
| 141 | if (o == null || getClass() != o.getClass()) return false; | 148 | return true; |
| 142 | if (!super.equals(o)) return false; | 149 | } |
| 150 | |||
| 151 | if (o == null || getClass() != o.getClass()) { | ||
| 152 | return false; | ||
| 153 | } | ||
| 154 | |||
| 155 | if (!super.equals(o)) { | ||
| 156 | return false; | ||
| 157 | } | ||
| 158 | |||
| 143 | Chat chat = (Chat) o; | 159 | Chat chat = (Chat) o; |
| 144 | return Objects.equals(message, chat.message); | 160 | return Objects.equals(message, chat.message); |
| 145 | } | 161 | } |
| @@ -153,11 +169,9 @@ public abstract class Message { | |||
| 153 | public String toString() { | 169 | public String toString() { |
| 154 | return String.format("Message.Chat { user: '%s', message: '%s' }", user, message); | 170 | return String.format("Message.Chat { user: '%s', message: '%s' }", user, message); |
| 155 | } | 171 | } |
| 156 | |||
| 157 | } | 172 | } |
| 158 | 173 | ||
| 159 | public static final class Connect extends Message { | 174 | public static final class Connect extends Message { |
| 160 | |||
| 161 | private Connect(String user) { | 175 | private Connect(String user) { |
| 162 | super(user); | 176 | super(user); |
| 163 | } | 177 | } |
| @@ -176,11 +190,9 @@ public abstract class Message { | |||
| 176 | public String toString() { | 190 | public String toString() { |
| 177 | return String.format("Message.Connect { user: '%s' }", user); | 191 | return String.format("Message.Connect { user: '%s' }", user); |
| 178 | } | 192 | } |
| 179 | |||
| 180 | } | 193 | } |
| 181 | 194 | ||
| 182 | public static final class Disconnect extends Message { | 195 | public static final class Disconnect extends Message { |
| 183 | |||
| 184 | private Disconnect(String user) { | 196 | private Disconnect(String user) { |
| 185 | super(user); | 197 | super(user); |
| 186 | } | 198 | } |
| @@ -199,11 +211,9 @@ public abstract class Message { | |||
| 199 | public String toString() { | 211 | public String toString() { |
| 200 | return String.format("Message.Disconnect { user: '%s' }", user); | 212 | return String.format("Message.Disconnect { user: '%s' }", user); |
| 201 | } | 213 | } |
| 202 | |||
| 203 | } | 214 | } |
| 204 | 215 | ||
| 205 | public static final class EditDocs extends Message { | 216 | public static final class EditDocs extends Message { |
| 206 | |||
| 207 | public final Entry<?> entry; | 217 | public final Entry<?> entry; |
| 208 | 218 | ||
| 209 | private EditDocs(String user, Entry<?> entry) { | 219 | private EditDocs(String user, Entry<?> entry) { |
| @@ -229,9 +239,18 @@ public abstract class Message { | |||
| 229 | 239 | ||
| 230 | @Override | 240 | @Override |
| 231 | public boolean equals(Object o) { | 241 | public boolean equals(Object o) { |
| 232 | if (this == o) return true; | 242 | if (this == o) { |
| 233 | if (o == null || getClass() != o.getClass()) return false; | 243 | return true; |
| 234 | if (!super.equals(o)) return false; | 244 | } |
| 245 | |||
| 246 | if (o == null || getClass() != o.getClass()) { | ||
| 247 | return false; | ||
| 248 | } | ||
| 249 | |||
| 250 | if (!super.equals(o)) { | ||
| 251 | return false; | ||
| 252 | } | ||
| 253 | |||
| 235 | EditDocs editDocs = (EditDocs) o; | 254 | EditDocs editDocs = (EditDocs) o; |
| 236 | return Objects.equals(entry, editDocs.entry); | 255 | return Objects.equals(entry, editDocs.entry); |
| 237 | } | 256 | } |
| @@ -245,11 +264,9 @@ public abstract class Message { | |||
| 245 | public String toString() { | 264 | public String toString() { |
| 246 | return String.format("Message.EditDocs { user: '%s', entry: %s }", user, entry); | 265 | return String.format("Message.EditDocs { user: '%s', entry: %s }", user, entry); |
| 247 | } | 266 | } |
| 248 | |||
| 249 | } | 267 | } |
| 250 | 268 | ||
| 251 | public static final class MarkDeobf extends Message { | 269 | public static final class MarkDeobf extends Message { |
| 252 | |||
| 253 | public final Entry<?> entry; | 270 | public final Entry<?> entry; |
| 254 | 271 | ||
| 255 | private MarkDeobf(String user, Entry<?> entry) { | 272 | private MarkDeobf(String user, Entry<?> entry) { |
| @@ -275,9 +292,18 @@ public abstract class Message { | |||
| 275 | 292 | ||
| 276 | @Override | 293 | @Override |
| 277 | public boolean equals(Object o) { | 294 | public boolean equals(Object o) { |
| 278 | if (this == o) return true; | 295 | if (this == o) { |
| 279 | if (o == null || getClass() != o.getClass()) return false; | 296 | return true; |
| 280 | if (!super.equals(o)) return false; | 297 | } |
| 298 | |||
| 299 | if (o == null || getClass() != o.getClass()) { | ||
| 300 | return false; | ||
| 301 | } | ||
| 302 | |||
| 303 | if (!super.equals(o)) { | ||
| 304 | return false; | ||
| 305 | } | ||
| 306 | |||
| 281 | MarkDeobf markDeobf = (MarkDeobf) o; | 307 | MarkDeobf markDeobf = (MarkDeobf) o; |
| 282 | return Objects.equals(entry, markDeobf.entry); | 308 | return Objects.equals(entry, markDeobf.entry); |
| 283 | } | 309 | } |
| @@ -291,11 +317,9 @@ public abstract class Message { | |||
| 291 | public String toString() { | 317 | public String toString() { |
| 292 | return String.format("Message.MarkDeobf { user: '%s', entry: %s }", user, entry); | 318 | return String.format("Message.MarkDeobf { user: '%s', entry: %s }", user, entry); |
| 293 | } | 319 | } |
| 294 | |||
| 295 | } | 320 | } |
| 296 | 321 | ||
| 297 | public static final class RemoveMapping extends Message { | 322 | public static final class RemoveMapping extends Message { |
| 298 | |||
| 299 | public final Entry<?> entry; | 323 | public final Entry<?> entry; |
| 300 | 324 | ||
| 301 | private RemoveMapping(String user, Entry<?> entry) { | 325 | private RemoveMapping(String user, Entry<?> entry) { |
| @@ -321,9 +345,18 @@ public abstract class Message { | |||
| 321 | 345 | ||
| 322 | @Override | 346 | @Override |
| 323 | public boolean equals(Object o) { | 347 | public boolean equals(Object o) { |
| 324 | if (this == o) return true; | 348 | if (this == o) { |
| 325 | if (o == null || getClass() != o.getClass()) return false; | 349 | return true; |
| 326 | if (!super.equals(o)) return false; | 350 | } |
| 351 | |||
| 352 | if (o == null || getClass() != o.getClass()) { | ||
| 353 | return false; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (!super.equals(o)) { | ||
| 357 | return false; | ||
| 358 | } | ||
| 359 | |||
| 327 | RemoveMapping that = (RemoveMapping) o; | 360 | RemoveMapping that = (RemoveMapping) o; |
| 328 | return Objects.equals(entry, that.entry); | 361 | return Objects.equals(entry, that.entry); |
| 329 | } | 362 | } |
| @@ -337,11 +370,9 @@ public abstract class Message { | |||
| 337 | public String toString() { | 370 | public String toString() { |
| 338 | return String.format("Message.RemoveMapping { user: '%s', entry: %s }", user, entry); | 371 | return String.format("Message.RemoveMapping { user: '%s', entry: %s }", user, entry); |
| 339 | } | 372 | } |
| 340 | |||
| 341 | } | 373 | } |
| 342 | 374 | ||
| 343 | public static final class Rename extends Message { | 375 | public static final class Rename extends Message { |
| 344 | |||
| 345 | public final Entry<?> entry; | 376 | public final Entry<?> entry; |
| 346 | public final String newName; | 377 | public final String newName; |
| 347 | 378 | ||
| @@ -370,12 +401,20 @@ public abstract class Message { | |||
| 370 | 401 | ||
| 371 | @Override | 402 | @Override |
| 372 | public boolean equals(Object o) { | 403 | public boolean equals(Object o) { |
| 373 | if (this == o) return true; | 404 | if (this == o) { |
| 374 | if (o == null || getClass() != o.getClass()) return false; | 405 | return true; |
| 375 | if (!super.equals(o)) return false; | 406 | } |
| 407 | |||
| 408 | if (o == null || getClass() != o.getClass()) { | ||
| 409 | return false; | ||
| 410 | } | ||
| 411 | |||
| 412 | if (!super.equals(o)) { | ||
| 413 | return false; | ||
| 414 | } | ||
| 415 | |||
| 376 | Rename rename = (Rename) o; | 416 | Rename rename = (Rename) o; |
| 377 | return Objects.equals(entry, rename.entry) && | 417 | return Objects.equals(entry, rename.entry) && Objects.equals(newName, rename.newName); |
| 378 | Objects.equals(newName, rename.newName); | ||
| 379 | } | 418 | } |
| 380 | 419 | ||
| 381 | @Override | 420 | @Override |
| @@ -387,7 +426,5 @@ public abstract class Message { | |||
| 387 | public String toString() { | 426 | public String toString() { |
| 388 | return String.format("Message.Rename { user: '%s', entry: %s, newName: '%s' }", user, entry, newName); | 427 | return String.format("Message.Rename { user: '%s', entry: %s, newName: '%s' }", user, entry, newName); |
| 389 | } | 428 | } |
| 390 | |||
| 391 | } | 429 | } |
| 392 | |||
| 393 | } | 430 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java b/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java index 45e07508..a8a10296 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ServerAddress.java | |||
| @@ -5,7 +5,6 @@ import java.util.Objects; | |||
| 5 | import javax.annotation.Nullable; | 5 | import javax.annotation.Nullable; |
| 6 | 6 | ||
| 7 | public class ServerAddress { | 7 | public class ServerAddress { |
| 8 | |||
| 9 | public final String address; | 8 | public final String address; |
| 10 | public final int port; | 9 | public final int port; |
| 11 | 10 | ||
| @@ -16,11 +15,26 @@ public class ServerAddress { | |||
| 16 | 15 | ||
| 17 | @Nullable | 16 | @Nullable |
| 18 | public static ServerAddress of(String address, int port) { | 17 | public static ServerAddress of(String address, int port) { |
| 19 | if (port < 0 || port > 65535) return null; | 18 | if (port < 0 || port > 65535) { |
| 20 | if (address == null) return null; | 19 | return null; |
| 21 | if (address.equals("")) return null; | 20 | } |
| 22 | if (!address.matches("[a-zA-Z0-9.:-]+")) return null; | 21 | |
| 23 | if (address.startsWith("-") || address.endsWith("-")) return null; | 22 | if (address == null) { |
| 23 | return null; | ||
| 24 | } | ||
| 25 | |||
| 26 | if (address.equals("")) { | ||
| 27 | return null; | ||
| 28 | } | ||
| 29 | |||
| 30 | if (!address.matches("[a-zA-Z0-9.:-]+")) { | ||
| 31 | return null; | ||
| 32 | } | ||
| 33 | |||
| 34 | if (address.startsWith("-") || address.endsWith("-")) { | ||
| 35 | return null; | ||
| 36 | } | ||
| 37 | |||
| 24 | return new ServerAddress(address, port); | 38 | return new ServerAddress(address, port); |
| 25 | } | 39 | } |
| 26 | 40 | ||
| @@ -28,6 +42,7 @@ public class ServerAddress { | |||
| 28 | public static ServerAddress from(String s, int defaultPort) { | 42 | public static ServerAddress from(String s, int defaultPort) { |
| 29 | String address; | 43 | String address; |
| 30 | int idx = s.indexOf(']'); | 44 | int idx = s.indexOf(']'); |
| 45 | |||
| 31 | if (s.startsWith("[") && idx != -1) { | 46 | if (s.startsWith("[") && idx != -1) { |
| 32 | address = s.substring(1, idx); | 47 | address = s.substring(1, idx); |
| 33 | s = s.substring(idx + 1); | 48 | s = s.substring(idx + 1); |
| @@ -41,10 +56,12 @@ public class ServerAddress { | |||
| 41 | } | 56 | } |
| 42 | 57 | ||
| 43 | int port; | 58 | int port; |
| 59 | |||
| 44 | if (s.isEmpty()) { | 60 | if (s.isEmpty()) { |
| 45 | port = defaultPort; | 61 | port = defaultPort; |
| 46 | } else if (s.startsWith(":")) { | 62 | } else if (s.startsWith(":")) { |
| 47 | s = s.substring(1); | 63 | s = s.substring(1); |
| 64 | |||
| 48 | try { | 65 | try { |
| 49 | port = Integer.parseInt(s); | 66 | port = Integer.parseInt(s); |
| 50 | } catch (NumberFormatException e) { | 67 | } catch (NumberFormatException e) { |
| @@ -53,16 +70,22 @@ public class ServerAddress { | |||
| 53 | } else { | 70 | } else { |
| 54 | return null; | 71 | return null; |
| 55 | } | 72 | } |
| 73 | |||
| 56 | return ServerAddress.of(address, port); | 74 | return ServerAddress.of(address, port); |
| 57 | } | 75 | } |
| 58 | 76 | ||
| 59 | @Override | 77 | @Override |
| 60 | public boolean equals(Object o) { | 78 | public boolean equals(Object o) { |
| 61 | if (this == o) return true; | 79 | if (this == o) { |
| 62 | if (o == null || getClass() != o.getClass()) return false; | 80 | return true; |
| 81 | } | ||
| 82 | |||
| 83 | if (o == null || getClass() != o.getClass()) { | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 63 | ServerAddress that = (ServerAddress) o; | 87 | ServerAddress that = (ServerAddress) o; |
| 64 | return port == that.port && | 88 | return port == that.port && Objects.equals(address, that.address); |
| 65 | Objects.equals(address, that.address); | ||
| 66 | } | 89 | } |
| 67 | 90 | ||
| 68 | @Override | 91 | @Override |
| @@ -74,5 +97,4 @@ public class ServerAddress { | |||
| 74 | public String toString() { | 97 | public String toString() { |
| 75 | return String.format("ServerAddress { address: '%s', port: %d }", address, port); | 98 | return String.format("ServerAddress { address: '%s', port: %d }", address, port); |
| 76 | } | 99 | } |
| 77 | |||
| 78 | } | 100 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java b/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java index 86185536..5b5b0e66 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/ServerPacketHandler.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.network; | |||
| 3 | import java.net.Socket; | 3 | import java.net.Socket; |
| 4 | 4 | ||
| 5 | public class ServerPacketHandler { | 5 | public class ServerPacketHandler { |
| 6 | |||
| 7 | private final Socket client; | 6 | private final Socket client; |
| 8 | private final EnigmaServer server; | 7 | private final EnigmaServer server; |
| 9 | 8 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java index 78ef9645..ab4f5a16 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/ConfirmChangeC2SPacket.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | 6 | ||
| 7 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 8 | |||
| 9 | public class ConfirmChangeC2SPacket implements Packet<ServerPacketHandler> { | 9 | public class ConfirmChangeC2SPacket implements Packet<ServerPacketHandler> { |
| 10 | private int syncId; | 10 | private int syncId; |
| 11 | 11 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java index b97877c6..6a7ffe99 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeC2SPacket.java | |||
| @@ -12,7 +12,6 @@ import cuchaz.enigma.utils.validation.PrintValidatable; | |||
| 12 | import cuchaz.enigma.utils.validation.ValidationContext; | 12 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 13 | 13 | ||
| 14 | public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { | 14 | public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { |
| 15 | |||
| 16 | private EntryChange<?> change; | 15 | private EntryChange<?> change; |
| 17 | 16 | ||
| 18 | EntryChangeC2SPacket() { | 17 | EntryChangeC2SPacket() { |
| @@ -62,5 +61,4 @@ public class EntryChangeC2SPacket implements Packet<ServerPacketHandler> { | |||
| 62 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); | 61 | handler.getServer().sendMessage(Message.editDocs(handler.getServer().getUsername(handler.getClient()), this.change.getTarget())); |
| 63 | } | 62 | } |
| 64 | } | 63 | } |
| 65 | |||
| 66 | } | 64 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java index a237b916..8e4688e3 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/EntryChangeS2CPacket.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.translation.mapping.EntryChange; | 8 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 9 | 9 | ||
| 10 | public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { | 10 | public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { |
| 11 | |||
| 12 | private int syncId; | 11 | private int syncId; |
| 13 | private EntryChange<?> change; | 12 | private EntryChange<?> change; |
| 14 | 13 | ||
| @@ -38,5 +37,4 @@ public class EntryChangeS2CPacket implements Packet<ClientPacketHandler> { | |||
| 38 | handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); | 37 | handler.sendPacket(new ConfirmChangeC2SPacket(this.syncId)); |
| 39 | } | 38 | } |
| 40 | } | 39 | } |
| 41 | |||
| 42 | } | 40 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java index 9a112a80..bd238dc1 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/KickS2CPacket.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | 6 | ||
| 7 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 8 | |||
| 9 | public class KickS2CPacket implements Packet<ClientPacketHandler> { | 9 | public class KickS2CPacket implements Packet<ClientPacketHandler> { |
| 10 | private String reason; | 10 | private String reason; |
| 11 | 11 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java index da0f44a5..e93c1d4d 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/LoginC2SPacket.java | |||
| @@ -1,14 +1,14 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.EnigmaServer; | ||
| 4 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 5 | import cuchaz.enigma.network.Message; | ||
| 6 | |||
| 7 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 8 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 9 | import java.io.IOException; | 5 | import java.io.IOException; |
| 10 | import java.util.Arrays; | 6 | import java.util.Arrays; |
| 11 | 7 | ||
| 8 | import cuchaz.enigma.network.EnigmaServer; | ||
| 9 | import cuchaz.enigma.network.Message; | ||
| 10 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 11 | |||
| 12 | public class LoginC2SPacket implements Packet<ServerPacketHandler> { | 12 | public class LoginC2SPacket implements Packet<ServerPacketHandler> { |
| 13 | private byte[] jarChecksum; | 13 | private byte[] jarChecksum; |
| 14 | private char[] password; | 14 | private char[] password; |
| @@ -28,12 +28,15 @@ public class LoginC2SPacket implements Packet<ServerPacketHandler> { | |||
| 28 | if (input.readUnsignedShort() != EnigmaServer.PROTOCOL_VERSION) { | 28 | if (input.readUnsignedShort() != EnigmaServer.PROTOCOL_VERSION) { |
| 29 | throw new IOException("Mismatching protocol"); | 29 | throw new IOException("Mismatching protocol"); |
| 30 | } | 30 | } |
| 31 | |||
| 31 | this.jarChecksum = new byte[EnigmaServer.CHECKSUM_SIZE]; | 32 | this.jarChecksum = new byte[EnigmaServer.CHECKSUM_SIZE]; |
| 32 | input.readFully(jarChecksum); | 33 | input.readFully(jarChecksum); |
| 33 | this.password = new char[input.readUnsignedByte()]; | 34 | this.password = new char[input.readUnsignedByte()]; |
| 35 | |||
| 34 | for (int i = 0; i < password.length; i++) { | 36 | for (int i = 0; i < password.length; i++) { |
| 35 | password[i] = input.readChar(); | 37 | password[i] = input.readChar(); |
| 36 | } | 38 | } |
| 39 | |||
| 37 | this.username = PacketHelper.readString(input); | 40 | this.username = PacketHelper.readString(input); |
| 38 | } | 41 | } |
| 39 | 42 | ||
| @@ -42,9 +45,11 @@ public class LoginC2SPacket implements Packet<ServerPacketHandler> { | |||
| 42 | output.writeShort(EnigmaServer.PROTOCOL_VERSION); | 45 | output.writeShort(EnigmaServer.PROTOCOL_VERSION); |
| 43 | output.write(jarChecksum); | 46 | output.write(jarChecksum); |
| 44 | output.writeByte(password.length); | 47 | output.writeByte(password.length); |
| 48 | |||
| 45 | for (char c : password) { | 49 | for (char c : password) { |
| 46 | output.writeChar(c); | 50 | output.writeChar(c); |
| 47 | } | 51 | } |
| 52 | |||
| 48 | PacketHelper.writeString(output, username); | 53 | PacketHelper.writeString(output, username); |
| 49 | } | 54 | } |
| 50 | 55 | ||
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java index 3bc09e79..b0610b04 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageC2SPacket.java | |||
| @@ -4,11 +4,10 @@ import java.io.DataInput; | |||
| 4 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 5 | import java.io.IOException; | 5 | import java.io.IOException; |
| 6 | 6 | ||
| 7 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 8 | import cuchaz.enigma.network.Message; | 7 | import cuchaz.enigma.network.Message; |
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 9 | 9 | ||
| 10 | public class MessageC2SPacket implements Packet<ServerPacketHandler> { | 10 | public class MessageC2SPacket implements Packet<ServerPacketHandler> { |
| 11 | |||
| 12 | private String message; | 11 | private String message; |
| 13 | 12 | ||
| 14 | MessageC2SPacket() { | 13 | MessageC2SPacket() { |
| @@ -31,9 +30,9 @@ public class MessageC2SPacket implements Packet<ServerPacketHandler> { | |||
| 31 | @Override | 30 | @Override |
| 32 | public void handle(ServerPacketHandler handler) { | 31 | public void handle(ServerPacketHandler handler) { |
| 33 | String message = this.message.trim(); | 32 | String message = this.message.trim(); |
| 33 | |||
| 34 | if (!message.isEmpty()) { | 34 | if (!message.isEmpty()) { |
| 35 | handler.getServer().sendMessage(Message.chat(handler.getServer().getUsername(handler.getClient()), message)); | 35 | handler.getServer().sendMessage(Message.chat(handler.getServer().getUsername(handler.getClient()), message)); |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | |||
| 39 | } | 38 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java index 2b07968d..9833eebc 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/MessageS2CPacket.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.network.Message; | 8 | import cuchaz.enigma.network.Message; |
| 9 | 9 | ||
| 10 | public class MessageS2CPacket implements Packet<ClientPacketHandler> { | 10 | public class MessageS2CPacket implements Packet<ClientPacketHandler> { |
| 11 | |||
| 12 | private Message message; | 11 | private Message message; |
| 13 | 12 | ||
| 14 | MessageS2CPacket() { | 13 | MessageS2CPacket() { |
| @@ -32,5 +31,4 @@ public class MessageS2CPacket implements Packet<ClientPacketHandler> { | |||
| 32 | public void handle(ClientPacketHandler handler) { | 31 | public void handle(ClientPacketHandler handler) { |
| 33 | handler.addMessage(message); | 32 | handler.addMessage(message); |
| 34 | } | 33 | } |
| 35 | |||
| 36 | } | 34 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java index 2f16dfb9..15054e7b 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/Packet.java | |||
| @@ -5,11 +5,9 @@ import java.io.DataOutput; | |||
| 5 | import java.io.IOException; | 5 | import java.io.IOException; |
| 6 | 6 | ||
| 7 | public interface Packet<H> { | 7 | public interface Packet<H> { |
| 8 | |||
| 9 | void read(DataInput input) throws IOException; | 8 | void read(DataInput input) throws IOException; |
| 10 | 9 | ||
| 11 | void write(DataOutput output) throws IOException; | 10 | void write(DataOutput output) throws IOException; |
| 12 | 11 | ||
| 13 | void handle(H handler); | 12 | void handle(H handler); |
| 14 | |||
| 15 | } | 13 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java index 2649cdc4..ce767c3c 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketHelper.java | |||
| @@ -9,11 +9,14 @@ import cuchaz.enigma.translation.mapping.AccessModifier; | |||
| 9 | import cuchaz.enigma.translation.mapping.EntryChange; | 9 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 11 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 12 | import cuchaz.enigma.translation.representation.entry.*; | 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 13 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 15 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 13 | import cuchaz.enigma.utils.TristateChange; | 17 | import cuchaz.enigma.utils.TristateChange; |
| 14 | 18 | ||
| 15 | public class PacketHelper { | 19 | public class PacketHelper { |
| 16 | |||
| 17 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; | 20 | private static final int ENTRY_CLASS = 0, ENTRY_FIELD = 1, ENTRY_METHOD = 2, ENTRY_LOCAL_VAR = 3; |
| 18 | private static final int MAX_STRING_LENGTH = 65535; | 21 | private static final int MAX_STRING_LENGTH = 65535; |
| 19 | 22 | ||
| @@ -31,45 +34,46 @@ public class PacketHelper { | |||
| 31 | String name = readString(input); | 34 | String name = readString(input); |
| 32 | 35 | ||
| 33 | String javadocs = null; | 36 | String javadocs = null; |
| 37 | |||
| 34 | if (input.readBoolean()) { | 38 | if (input.readBoolean()) { |
| 35 | javadocs = readString(input); | 39 | javadocs = readString(input); |
| 36 | } | 40 | } |
| 37 | 41 | ||
| 38 | switch (type) { | 42 | switch (type) { |
| 39 | case ENTRY_CLASS: { | 43 | case ENTRY_CLASS: { |
| 40 | if (parent != null && !(parent instanceof ClassEntry)) { | 44 | if (parent != null && !(parent instanceof ClassEntry)) { |
| 41 | throw new IOException("Class requires class parent"); | 45 | throw new IOException("Class requires class parent"); |
| 42 | } | ||
| 43 | |||
| 44 | return new ClassEntry((ClassEntry) parent, name, javadocs); | ||
| 45 | } | 46 | } |
| 46 | case ENTRY_FIELD: { | ||
| 47 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 48 | throw new IOException("Field requires class parent"); | ||
| 49 | } | ||
| 50 | 47 | ||
| 51 | TypeDescriptor desc = new TypeDescriptor(readString(input)); | 48 | return new ClassEntry((ClassEntry) parent, name, javadocs); |
| 52 | return new FieldEntry(parentClass, name, desc, javadocs); | 49 | } |
| 50 | case ENTRY_FIELD: { | ||
| 51 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 52 | throw new IOException("Field requires class parent"); | ||
| 53 | } | 53 | } |
| 54 | case ENTRY_METHOD: { | ||
| 55 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 56 | throw new IOException("Method requires class parent"); | ||
| 57 | } | ||
| 58 | 54 | ||
| 59 | MethodDescriptor desc = new MethodDescriptor(readString(input)); | 55 | TypeDescriptor desc = new TypeDescriptor(readString(input)); |
| 60 | return new MethodEntry(parentClass, name, desc, javadocs); | 56 | return new FieldEntry(parentClass, name, desc, javadocs); |
| 57 | } | ||
| 58 | case ENTRY_METHOD: { | ||
| 59 | if (!(parent instanceof ClassEntry parentClass)) { | ||
| 60 | throw new IOException("Method requires class parent"); | ||
| 61 | } | 61 | } |
| 62 | case ENTRY_LOCAL_VAR: { | 62 | |
| 63 | if (!(parent instanceof MethodEntry parentMethod)) { | 63 | MethodDescriptor desc = new MethodDescriptor(readString(input)); |
| 64 | throw new IOException("Local variable requires method parent"); | 64 | return new MethodEntry(parentClass, name, desc, javadocs); |
| 65 | } | 65 | } |
| 66 | 66 | case ENTRY_LOCAL_VAR: { | |
| 67 | int index = input.readUnsignedShort(); | 67 | if (!(parent instanceof MethodEntry parentMethod)) { |
| 68 | boolean parameter = input.readBoolean(); | 68 | throw new IOException("Local variable requires method parent"); |
| 69 | return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); | ||
| 70 | } | 69 | } |
| 71 | default: | 70 | |
| 72 | throw new IOException("Received unknown entry type " + type); | 71 | int index = input.readUnsignedShort(); |
| 72 | boolean parameter = input.readBoolean(); | ||
| 73 | return new LocalVariableEntry(parentMethod, index, name, parameter, javadocs); | ||
| 74 | } | ||
| 75 | default: | ||
| 76 | throw new IOException("Received unknown entry type " + type); | ||
| 73 | } | 77 | } |
| 74 | } | 78 | } |
| 75 | 79 | ||
| @@ -94,6 +98,7 @@ public class PacketHelper { | |||
| 94 | // parent | 98 | // parent |
| 95 | if (includeParent) { | 99 | if (includeParent) { |
| 96 | output.writeBoolean(entry.getParent() != null); | 100 | output.writeBoolean(entry.getParent() != null); |
| 101 | |||
| 97 | if (entry.getParent() != null) { | 102 | if (entry.getParent() != null) { |
| 98 | writeEntry(output, entry.getParent(), true); | 103 | writeEntry(output, entry.getParent(), true); |
| 99 | } | 104 | } |
| @@ -104,6 +109,7 @@ public class PacketHelper { | |||
| 104 | 109 | ||
| 105 | // javadocs | 110 | // javadocs |
| 106 | output.writeBoolean(entry.getJavadocs() != null); | 111 | output.writeBoolean(entry.getJavadocs() != null); |
| 112 | |||
| 107 | if (entry.getJavadocs() != null) { | 113 | if (entry.getJavadocs() != null) { |
| 108 | writeString(output, entry.getJavadocs()); | 114 | writeString(output, entry.getJavadocs()); |
| 109 | } | 115 | } |
| @@ -129,9 +135,11 @@ public class PacketHelper { | |||
| 129 | 135 | ||
| 130 | public static void writeString(DataOutput output, String str) throws IOException { | 136 | public static void writeString(DataOutput output, String str) throws IOException { |
| 131 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8); | 137 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8); |
| 138 | |||
| 132 | if (bytes.length > MAX_STRING_LENGTH) { | 139 | if (bytes.length > MAX_STRING_LENGTH) { |
| 133 | throw new IOException("String too long, was " + bytes.length + " bytes, max " + MAX_STRING_LENGTH + " allowed"); | 140 | throw new IOException("String too long, was " + bytes.length + " bytes, max " + MAX_STRING_LENGTH + " allowed"); |
| 134 | } | 141 | } |
| 142 | |||
| 135 | output.writeShort(bytes.length); | 143 | output.writeShort(bytes.length); |
| 136 | output.write(bytes); | 144 | output.write(bytes); |
| 137 | } | 145 | } |
| @@ -146,30 +154,30 @@ public class PacketHelper { | |||
| 146 | TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; | 154 | TristateChange.Type javadocT = TristateChange.Type.values()[flags >> 4 & 0x3]; |
| 147 | 155 | ||
| 148 | switch (deobfNameT) { | 156 | switch (deobfNameT) { |
| 149 | case RESET: | 157 | case RESET: |
| 150 | change = change.clearDeobfName(); | 158 | change = change.clearDeobfName(); |
| 151 | break; | 159 | break; |
| 152 | case SET: | 160 | case SET: |
| 153 | change = change.withDeobfName(readString(input)); | 161 | change = change.withDeobfName(readString(input)); |
| 154 | break; | 162 | break; |
| 155 | } | 163 | } |
| 156 | 164 | ||
| 157 | switch (accessT) { | 165 | switch (accessT) { |
| 158 | case RESET: | 166 | case RESET: |
| 159 | change = change.clearAccess(); | 167 | change = change.clearAccess(); |
| 160 | break; | 168 | break; |
| 161 | case SET: | 169 | case SET: |
| 162 | change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); | 170 | change = change.withAccess(AccessModifier.values()[flags >> 6 & 0x3]); |
| 163 | break; | 171 | break; |
| 164 | } | 172 | } |
| 165 | 173 | ||
| 166 | switch (javadocT) { | 174 | switch (javadocT) { |
| 167 | case RESET: | 175 | case RESET: |
| 168 | change = change.clearJavadoc(); | 176 | change = change.clearJavadoc(); |
| 169 | break; | 177 | break; |
| 170 | case SET: | 178 | case SET: |
| 171 | change = change.withJavadoc(readString(input)); | 179 | change = change.withJavadoc(readString(input)); |
| 172 | break; | 180 | break; |
| 173 | } | 181 | } |
| 174 | 182 | ||
| 175 | return change; | 183 | return change; |
| @@ -177,9 +185,7 @@ public class PacketHelper { | |||
| 177 | 185 | ||
| 178 | public static void writeEntryChange(DataOutput output, EntryChange<?> change) throws IOException { | 186 | public static void writeEntryChange(DataOutput output, EntryChange<?> change) throws IOException { |
| 179 | writeEntry(output, change.getTarget()); | 187 | writeEntry(output, change.getTarget()); |
| 180 | int flags = change.getDeobfName().getType().ordinal() | | 188 | int flags = change.getDeobfName().getType().ordinal() | change.getAccess().getType().ordinal() << 2 | change.getJavadoc().getType().ordinal() << 4; |
| 181 | change.getAccess().getType().ordinal() << 2 | | ||
| 182 | change.getJavadoc().getType().ordinal() << 4; | ||
| 183 | 189 | ||
| 184 | if (change.getAccess().isSet()) { | 190 | if (change.getAccess().isSet()) { |
| 185 | flags |= change.getAccess().getNewValue().ordinal() << 6; | 191 | flags |= change.getAccess().getNewValue().ordinal() << 6; |
| @@ -195,5 +201,4 @@ public class PacketHelper { | |||
| 195 | writeString(output, change.getJavadoc().getNewValue()); | 201 | writeString(output, change.getJavadoc().getNewValue()); |
| 196 | } | 202 | } |
| 197 | } | 203 | } |
| 198 | |||
| 199 | } | 204 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java index 59999ccc..49d56fd8 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/PacketRegistry.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.network.ClientPacketHandler; | |||
| 8 | import cuchaz.enigma.network.ServerPacketHandler; | 8 | import cuchaz.enigma.network.ServerPacketHandler; |
| 9 | 9 | ||
| 10 | public class PacketRegistry { | 10 | public class PacketRegistry { |
| 11 | |||
| 12 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); | 11 | private static final Map<Class<? extends Packet<ServerPacketHandler>>, Integer> c2sPacketIds = new HashMap<>(); |
| 13 | private static final Map<Integer, Supplier<? extends Packet<ServerPacketHandler>>> c2sPacketCreators = new HashMap<>(); | 12 | private static final Map<Integer, Supplier<? extends Packet<ServerPacketHandler>>> c2sPacketCreators = new HashMap<>(); |
| 14 | private static final Map<Class<? extends Packet<ClientPacketHandler>>, Integer> s2cPacketIds = new HashMap<>(); | 13 | private static final Map<Class<? extends Packet<ClientPacketHandler>>, Integer> s2cPacketIds = new HashMap<>(); |
| @@ -54,5 +53,4 @@ public class PacketRegistry { | |||
| 54 | Supplier<? extends Packet<ClientPacketHandler>> creator = s2cPacketCreators.get(id); | 53 | Supplier<? extends Packet<ClientPacketHandler>> creator = s2cPacketCreators.get(id); |
| 55 | return creator == null ? null : creator.get(); | 54 | return creator == null ? null : creator.get(); |
| 56 | } | 55 | } |
| 57 | |||
| 58 | } | 56 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java index 6d9c0bcb..7e50938e 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/SyncMappingsS2CPacket.java | |||
| @@ -28,6 +28,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 28 | public void read(DataInput input) throws IOException { | 28 | public void read(DataInput input) throws IOException { |
| 29 | mappings = new HashEntryTree<>(); | 29 | mappings = new HashEntryTree<>(); |
| 30 | int size = input.readInt(); | 30 | int size = input.readInt(); |
| 31 | |||
| 31 | for (int i = 0; i < size; i++) { | 32 | for (int i = 0; i < size; i++) { |
| 32 | readEntryTreeNode(input, null); | 33 | readEntryTreeNode(input, null); |
| 33 | } | 34 | } |
| @@ -40,6 +41,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 40 | EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); | 41 | EntryMapping mapping = new EntryMapping(!name.isEmpty() ? name : null, !javadoc.isEmpty() ? javadoc : null); |
| 41 | mappings.insert(entry, mapping); | 42 | mappings.insert(entry, mapping); |
| 42 | int size = input.readUnsignedShort(); | 43 | int size = input.readUnsignedShort(); |
| 44 | |||
| 43 | for (int i = 0; i < size; i++) { | 45 | for (int i = 0; i < size; i++) { |
| 44 | readEntryTreeNode(input, entry); | 46 | readEntryTreeNode(input, entry); |
| 45 | } | 47 | } |
| @@ -49,6 +51,7 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 49 | public void write(DataOutput output) throws IOException { | 51 | public void write(DataOutput output) throws IOException { |
| 50 | List<EntryTreeNode<EntryMapping>> roots = mappings.getRootNodes().toList(); | 52 | List<EntryTreeNode<EntryMapping>> roots = mappings.getRootNodes().toList(); |
| 51 | output.writeInt(roots.size()); | 53 | output.writeInt(roots.size()); |
| 54 | |||
| 52 | for (EntryTreeNode<EntryMapping> node : roots) { | 55 | for (EntryTreeNode<EntryMapping> node : roots) { |
| 53 | writeEntryTreeNode(output, node); | 56 | writeEntryTreeNode(output, node); |
| 54 | } | 57 | } |
| @@ -57,12 +60,16 @@ public class SyncMappingsS2CPacket implements Packet<ClientPacketHandler> { | |||
| 57 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { | 60 | private static void writeEntryTreeNode(DataOutput output, EntryTreeNode<EntryMapping> node) throws IOException { |
| 58 | PacketHelper.writeEntry(output, node.getEntry(), false); | 61 | PacketHelper.writeEntry(output, node.getEntry(), false); |
| 59 | EntryMapping value = node.getValue(); | 62 | EntryMapping value = node.getValue(); |
| 60 | if (value == null) value = EntryMapping.DEFAULT; | 63 | |
| 64 | if (value == null) { | ||
| 65 | value = EntryMapping.DEFAULT; | ||
| 66 | } | ||
| 61 | 67 | ||
| 62 | PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); | 68 | PacketHelper.writeString(output, value.targetName() != null ? value.targetName() : ""); |
| 63 | PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); | 69 | PacketHelper.writeString(output, value.javadoc() != null ? value.javadoc() : ""); |
| 64 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); | 70 | Collection<? extends EntryTreeNode<EntryMapping>> children = node.getChildNodes(); |
| 65 | output.writeShort(children.size()); | 71 | output.writeShort(children.size()); |
| 72 | |||
| 66 | for (EntryTreeNode<EntryMapping> child : children) { | 73 | for (EntryTreeNode<EntryMapping> child : children) { |
| 67 | writeEntryTreeNode(output, child); | 74 | writeEntryTreeNode(output, child); |
| 68 | } | 75 | } |
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java b/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java index b4a277a4..baac2b35 100644 --- a/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java +++ b/enigma-server/src/main/java/cuchaz/enigma/network/packet/UserListS2CPacket.java | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | package cuchaz.enigma.network.packet; | 1 | package cuchaz.enigma.network.packet; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.network.ClientPacketHandler; | ||
| 4 | |||
| 5 | import java.io.DataInput; | 3 | import java.io.DataInput; |
| 6 | import java.io.DataOutput; | 4 | import java.io.DataOutput; |
| 7 | import java.io.IOException; | 5 | import java.io.IOException; |
| 8 | import java.util.ArrayList; | 6 | import java.util.ArrayList; |
| 9 | import java.util.List; | 7 | import java.util.List; |
| 10 | 8 | ||
| 11 | public class UserListS2CPacket implements Packet<ClientPacketHandler> { | 9 | import cuchaz.enigma.network.ClientPacketHandler; |
| 12 | 10 | ||
| 11 | public class UserListS2CPacket implements Packet<ClientPacketHandler> { | ||
| 13 | private List<String> users; | 12 | private List<String> users; |
| 14 | 13 | ||
| 15 | UserListS2CPacket() { | 14 | UserListS2CPacket() { |
| @@ -23,6 +22,7 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 23 | public void read(DataInput input) throws IOException { | 22 | public void read(DataInput input) throws IOException { |
| 24 | int len = input.readUnsignedShort(); | 23 | int len = input.readUnsignedShort(); |
| 25 | users = new ArrayList<>(len); | 24 | users = new ArrayList<>(len); |
| 25 | |||
| 26 | for (int i = 0; i < len; i++) { | 26 | for (int i = 0; i < len; i++) { |
| 27 | users.add(input.readUTF()); | 27 | users.add(input.readUTF()); |
| 28 | } | 28 | } |
| @@ -31,6 +31,7 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 31 | @Override | 31 | @Override |
| 32 | public void write(DataOutput output) throws IOException { | 32 | public void write(DataOutput output) throws IOException { |
| 33 | output.writeShort(users.size()); | 33 | output.writeShort(users.size()); |
| 34 | |||
| 34 | for (String user : users) { | 35 | for (String user : users) { |
| 35 | PacketHelper.writeString(output, user); | 36 | PacketHelper.writeString(output, user); |
| 36 | } | 37 | } |
| @@ -40,5 +41,4 @@ public class UserListS2CPacket implements Packet<ClientPacketHandler> { | |||
| 40 | public void handle(ClientPacketHandler handler) { | 41 | public void handle(ClientPacketHandler handler) { |
| 41 | handler.updateUserList(users); | 42 | handler.updateUserList(users); |
| 42 | } | 43 | } |
| 43 | |||
| 44 | } | 44 | } |
diff --git a/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java b/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java index 3765f7a5..c2920e02 100644 --- a/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java +++ b/enigma-server/src/test/java/cuchaz/enigma/network/ServerAddressTest.java | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | package cuchaz.enigma.network; | 1 | package cuchaz.enigma.network; |
| 2 | 2 | ||
| 3 | import org.junit.Test; | ||
| 4 | |||
| 5 | import static org.junit.Assert.assertEquals; | 3 | import static org.junit.Assert.assertEquals; |
| 6 | import static org.junit.Assert.assertNull; | 4 | import static org.junit.Assert.assertNull; |
| 7 | 5 | ||
| 8 | public class ServerAddressTest { | 6 | import org.junit.Test; |
| 9 | 7 | ||
| 8 | public class ServerAddressTest { | ||
| 10 | @Test | 9 | @Test |
| 11 | public void validAddresses() { | 10 | public void validAddresses() { |
| 12 | assertEquals(ServerAddress.of("127.0.0.1", 22), ServerAddress.from("127.0.0.1", 22)); | 11 | assertEquals(ServerAddress.of("127.0.0.1", 22), ServerAddress.from("127.0.0.1", 22)); |
| @@ -24,5 +23,4 @@ public class ServerAddressTest { | |||
| 24 | assertNull(ServerAddress.from("127.0.0.1:100000000", 22)); | 23 | assertNull(ServerAddress.from("127.0.0.1:100000000", 22)); |
| 25 | assertNull(ServerAddress.from("127.0.0.1:lmao", 22)); | 24 | assertNull(ServerAddress.from("127.0.0.1:lmao", 22)); |
| 26 | } | 25 | } |
| 27 | |||
| 28 | } | 26 | } |
diff --git a/enigma-swing/build.gradle b/enigma-swing/build.gradle index d783e950..a4a13d88 100644 --- a/enigma-swing/build.gradle +++ b/enigma-swing/build.gradle | |||
| @@ -1,18 +1,18 @@ | |||
| 1 | plugins { | 1 | plugins { |
| 2 | id 'application' | 2 | id 'application' |
| 3 | id 'com.github.johnrengelman.shadow' version '7.0.0' | 3 | id 'com.github.johnrengelman.shadow' version '7.0.0' |
| 4 | } | 4 | } |
| 5 | 5 | ||
| 6 | dependencies { | 6 | dependencies { |
| 7 | implementation project(':enigma') | 7 | implementation project(':enigma') |
| 8 | implementation project(':enigma-server') | 8 | implementation project(':enigma-server') |
| 9 | 9 | ||
| 10 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' | 10 | implementation 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3' |
| 11 | implementation 'com.formdev:flatlaf:1.6.1' | 11 | implementation 'com.formdev:flatlaf:1.6.1' |
| 12 | implementation 'com.formdev:flatlaf-extras:1.6.1' // for SVG icons | 12 | implementation 'com.formdev:flatlaf-extras:1.6.1' // for SVG icons |
| 13 | implementation 'de.sciss:syntaxpane:1.2.0' | 13 | implementation 'de.sciss:syntaxpane:1.2.0' |
| 14 | implementation 'com.github.lukeu:swing-dpi:0.9' | 14 | implementation 'com.github.lukeu:swing-dpi:0.9' |
| 15 | implementation 'org.drjekyll:fontchooser:2.5.2' | 15 | implementation 'org.drjekyll:fontchooser:2.5.2' |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | mainClassName = 'cuchaz.enigma.gui.Main' | 18 | mainClassName = 'cuchaz.enigma.gui.Main' |
| @@ -20,9 +20,9 @@ mainClassName = 'cuchaz.enigma.gui.Main' | |||
| 20 | jar.manifest.attributes 'Main-Class': mainClassName | 20 | jar.manifest.attributes 'Main-Class': mainClassName |
| 21 | 21 | ||
| 22 | publishing { | 22 | publishing { |
| 23 | publications { | 23 | publications { |
| 24 | shadow(MavenPublication) { publication -> | 24 | shadow(MavenPublication) { publication -> |
| 25 | publication.from components.java | 25 | publication.from components.java |
| 26 | } | 26 | } |
| 27 | } | 27 | } |
| 28 | } | 28 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java index af105dbd..a213a592 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/BrowserCaret.java | |||
| @@ -1,20 +1,19 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| 14 | import javax.swing.text.DefaultCaret; | 14 | import javax.swing.text.DefaultCaret; |
| 15 | 15 | ||
| 16 | public class BrowserCaret extends DefaultCaret { | 16 | public class BrowserCaret extends DefaultCaret { |
| 17 | |||
| 18 | @Override | 17 | @Override |
| 19 | public boolean isSelectionVisible() { | 18 | public boolean isSelectionVisible() { |
| 20 | return true; | 19 | return true; |
| @@ -24,5 +23,4 @@ public class BrowserCaret extends DefaultCaret { | |||
| 24 | public boolean isVisible() { | 23 | public boolean isVisible() { |
| 25 | return true; | 24 | return true; |
| 26 | } | 25 | } |
| 27 | |||
| 28 | } | 26 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java index b7d3c4ef..4b9fa595 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java | |||
| @@ -1,35 +1,43 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.gui.node.ClassSelectorClassNode; | 14 | import java.awt.Component; |
| 15 | import cuchaz.enigma.gui.util.GuiUtil; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 17 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 18 | |||
| 19 | import javax.swing.*; | ||
| 20 | import javax.swing.event.CellEditorListener; | ||
| 21 | import javax.swing.event.ChangeEvent; | ||
| 22 | import javax.swing.tree.*; | ||
| 23 | import java.awt.*; | ||
| 24 | import java.awt.event.KeyAdapter; | 15 | import java.awt.event.KeyAdapter; |
| 25 | import java.awt.event.KeyEvent; | 16 | import java.awt.event.KeyEvent; |
| 26 | import java.awt.event.MouseAdapter; | 17 | import java.awt.event.MouseAdapter; |
| 27 | import java.awt.event.MouseEvent; | 18 | import java.awt.event.MouseEvent; |
| 19 | import java.util.ArrayList; | ||
| 20 | import java.util.Collection; | ||
| 21 | import java.util.Comparator; | ||
| 22 | import java.util.EventObject; | ||
| 28 | import java.util.List; | 23 | import java.util.List; |
| 29 | import java.util.*; | ||
| 30 | 24 | ||
| 31 | public class ClassSelector extends JTree { | 25 | import javax.swing.JTree; |
| 26 | import javax.swing.event.CellEditorListener; | ||
| 27 | import javax.swing.event.ChangeEvent; | ||
| 28 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 29 | import javax.swing.tree.DefaultTreeCellEditor; | ||
| 30 | import javax.swing.tree.DefaultTreeCellRenderer; | ||
| 31 | import javax.swing.tree.DefaultTreeModel; | ||
| 32 | import javax.swing.tree.TreeNode; | ||
| 33 | import javax.swing.tree.TreePath; | ||
| 34 | |||
| 35 | import cuchaz.enigma.gui.node.ClassSelectorClassNode; | ||
| 36 | import cuchaz.enigma.gui.util.GuiUtil; | ||
| 37 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 38 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 32 | 39 | ||
| 40 | public class ClassSelector extends JTree { | ||
| 33 | public static final Comparator<ClassEntry> DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName); | 41 | public static final Comparator<ClassEntry> DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName); |
| 34 | 42 | ||
| 35 | private final Comparator<ClassEntry> comparator; | 43 | private final Comparator<ClassEntry> comparator; |
| @@ -56,6 +64,7 @@ public class ClassSelector extends JTree { | |||
| 56 | if (selectionListener != null && event.getClickCount() == 2) { | 64 | if (selectionListener != null && event.getClickCount() == 2) { |
| 57 | // get the selected node | 65 | // get the selected node |
| 58 | TreePath path = getSelectionPath(); | 66 | TreePath path = getSelectionPath(); |
| 67 | |||
| 59 | if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode node) { | 68 | if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode node) { |
| 60 | selectionListener.onSelectClass(node.getObfEntry()); | 69 | selectionListener.onSelectClass(node.getObfEntry()); |
| 61 | } | 70 | } |
| @@ -121,23 +130,31 @@ public class ClassSelector extends JTree { | |||
| 121 | TreePath path = getSelectionPath(); | 130 | TreePath path = getSelectionPath(); |
| 122 | 131 | ||
| 123 | Object realPath = path.getLastPathComponent(); | 132 | Object realPath = path.getLastPathComponent(); |
| 133 | |||
| 124 | if (realPath instanceof DefaultMutableTreeNode node && data != null) { | 134 | if (realPath instanceof DefaultMutableTreeNode node && data != null) { |
| 125 | TreeNode parentNode = node.getParent(); | 135 | TreeNode parentNode = node.getParent(); |
| 126 | if (parentNode == null) | 136 | |
| 137 | if (parentNode == null) { | ||
| 127 | return; | 138 | return; |
| 139 | } | ||
| 140 | |||
| 128 | boolean allowEdit = true; | 141 | boolean allowEdit = true; |
| 142 | |||
| 129 | for (int i = 0; i < parentNode.getChildCount(); i++) { | 143 | for (int i = 0; i < parentNode.getChildCount(); i++) { |
| 130 | TreeNode childNode = parentNode.getChildAt(i); | 144 | TreeNode childNode = parentNode.getChildAt(i); |
| 145 | |||
| 131 | if (childNode != null && childNode.toString().equals(data) && childNode != node) { | 146 | if (childNode != null && childNode.toString().equals(data) && childNode != node) { |
| 132 | allowEdit = false; | 147 | allowEdit = false; |
| 133 | break; | 148 | break; |
| 134 | } | 149 | } |
| 135 | } | 150 | } |
| 151 | |||
| 136 | if (allowEdit && renameSelectionListener != null) { | 152 | if (allowEdit && renameSelectionListener != null) { |
| 137 | Object prevData = node.getUserObject(); | 153 | Object prevData = node.getUserObject(); |
| 138 | Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data; | 154 | Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data; |
| 139 | gui.validateImmediateAction(vc -> { | 155 | gui.validateImmediateAction(vc -> { |
| 140 | renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node); | 156 | renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node); |
| 157 | |||
| 141 | if (vc.canProceed()) { | 158 | if (vc.canProceed()) { |
| 142 | node.setUserObject(objectData); // Make sure that it's modified | 159 | node.setUserObject(objectData); // Make sure that it's modified |
| 143 | } else { | 160 | } else { |
| @@ -206,15 +223,19 @@ public class ClassSelector extends JTree { | |||
| 206 | public List<StateEntry> getExpansionState() { | 223 | public List<StateEntry> getExpansionState() { |
| 207 | List<StateEntry> state = new ArrayList<>(); | 224 | List<StateEntry> state = new ArrayList<>(); |
| 208 | int rowCount = getRowCount(); | 225 | int rowCount = getRowCount(); |
| 226 | |||
| 209 | for (int i = 0; i < rowCount; i++) { | 227 | for (int i = 0; i < rowCount; i++) { |
| 210 | TreePath path = getPathForRow(i); | 228 | TreePath path = getPathForRow(i); |
| 229 | |||
| 211 | if (isPathSelected(path)) { | 230 | if (isPathSelected(path)) { |
| 212 | state.add(new StateEntry(State.SELECTED, path)); | 231 | state.add(new StateEntry(State.SELECTED, path)); |
| 213 | } | 232 | } |
| 233 | |||
| 214 | if (isExpanded(path)) { | 234 | if (isExpanded(path)) { |
| 215 | state.add(new StateEntry(State.EXPANDED, path)); | 235 | state.add(new StateEntry(State.EXPANDED, path)); |
| 216 | } | 236 | } |
| 217 | } | 237 | } |
| 238 | |||
| 218 | return state; | 239 | return state; |
| 219 | } | 240 | } |
| 220 | 241 | ||
| @@ -223,8 +244,8 @@ public class ClassSelector extends JTree { | |||
| 223 | 244 | ||
| 224 | for (StateEntry entry : expansionState) { | 245 | for (StateEntry entry : expansionState) { |
| 225 | switch (entry.state) { | 246 | switch (entry.state) { |
| 226 | case SELECTED -> addSelectionPath(entry.path); | 247 | case SELECTED -> addSelectionPath(entry.path); |
| 227 | case EXPANDED -> expandPath(entry.path); | 248 | case EXPANDED -> expandPath(entry.path); |
| 228 | } | 249 | } |
| 229 | } | 250 | } |
| 230 | } | 251 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java index 1e8d6cf0..6028609f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EditableType.java | |||
| @@ -2,7 +2,11 @@ package cuchaz.enigma.gui; | |||
| 2 | 2 | ||
| 3 | import javax.annotation.Nullable; | 3 | import javax.annotation.Nullable; |
| 4 | 4 | ||
| 5 | import cuchaz.enigma.translation.representation.entry.*; | 5 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 6 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 7 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 6 | 10 | ||
| 7 | public enum EditableType { | 11 | public enum EditableType { |
| 8 | CLASS, | 12 | CLASS, |
| @@ -10,8 +14,7 @@ public enum EditableType { | |||
| 10 | FIELD, | 14 | FIELD, |
| 11 | PARAMETER, | 15 | PARAMETER, |
| 12 | LOCAL_VARIABLE, | 16 | LOCAL_VARIABLE, |
| 13 | JAVADOC, | 17 | JAVADOC; |
| 14 | ; | ||
| 15 | 18 | ||
| 16 | @Nullable | 19 | @Nullable |
| 17 | public static EditableType fromEntry(Entry<?> entry) { | 20 | public static EditableType fromEntry(Entry<?> entry) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java index c912be3a..0af8f9c1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaQuickFindDialog.java | |||
| @@ -1,16 +1,22 @@ | |||
| 1 | package cuchaz.enigma.gui; | 1 | package cuchaz.enigma.gui; |
| 2 | 2 | ||
| 3 | import de.sciss.syntaxpane.actions.DocumentSearchData; | 3 | import java.awt.Component; |
| 4 | import de.sciss.syntaxpane.actions.gui.QuickFindDialog; | 4 | import java.awt.Container; |
| 5 | 5 | import java.awt.Point; | |
| 6 | import javax.swing.*; | ||
| 7 | import javax.swing.text.JTextComponent; | ||
| 8 | import java.awt.*; | ||
| 9 | import java.awt.event.KeyAdapter; | 6 | import java.awt.event.KeyAdapter; |
| 10 | import java.awt.event.KeyEvent; | 7 | import java.awt.event.KeyEvent; |
| 11 | import java.util.stream.IntStream; | 8 | import java.util.stream.IntStream; |
| 12 | import java.util.stream.Stream; | 9 | import java.util.stream.Stream; |
| 13 | 10 | ||
| 11 | import javax.swing.JButton; | ||
| 12 | import javax.swing.JTextField; | ||
| 13 | import javax.swing.JToolBar; | ||
| 14 | import javax.swing.SwingUtilities; | ||
| 15 | import javax.swing.text.JTextComponent; | ||
| 16 | |||
| 17 | import de.sciss.syntaxpane.actions.DocumentSearchData; | ||
| 18 | import de.sciss.syntaxpane.actions.gui.QuickFindDialog; | ||
| 19 | |||
| 14 | public class EnigmaQuickFindDialog extends QuickFindDialog { | 20 | public class EnigmaQuickFindDialog extends QuickFindDialog { |
| 15 | public EnigmaQuickFindDialog(JTextComponent target) { | 21 | public EnigmaQuickFindDialog(JTextComponent target) { |
| 16 | super(target, DocumentSearchData.getFromEditor(target)); | 22 | super(target, DocumentSearchData.getFromEditor(target)); |
| @@ -22,6 +28,7 @@ public class EnigmaQuickFindDialog extends QuickFindDialog { | |||
| 22 | @Override | 28 | @Override |
| 23 | public void keyPressed(KeyEvent e) { | 29 | public void keyPressed(KeyEvent e) { |
| 24 | super.keyPressed(e); | 30 | super.keyPressed(e); |
| 31 | |||
| 25 | if (e.getKeyCode() == KeyEvent.VK_ENTER) { | 32 | if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
| 26 | JToolBar toolBar = getToolBar(); | 33 | JToolBar toolBar = getToolBar(); |
| 27 | boolean next = !e.isShiftDown(); | 34 | boolean next = !e.isShiftDown(); |
| @@ -78,13 +85,10 @@ public class EnigmaQuickFindDialog extends QuickFindDialog { | |||
| 78 | } | 85 | } |
| 79 | 86 | ||
| 80 | private static Stream<Component> components(Container container) { | 87 | private static Stream<Component> components(Container container) { |
| 81 | return IntStream.range(0, container.getComponentCount()) | 88 | return IntStream.range(0, container.getComponentCount()).mapToObj(container::getComponent); |
| 82 | .mapToObj(container::getComponent); | ||
| 83 | } | 89 | } |
| 84 | 90 | ||
| 85 | private static <T extends Component> Stream<T> components(Container container, Class<T> type) { | 91 | private static <T extends Component> Stream<T> components(Container container, Class<T> type) { |
| 86 | return components(container) | 92 | return components(container).filter(type::isInstance).map(type::cast); |
| 87 | .filter(type::isInstance) | ||
| 88 | .map(type::cast); | ||
| 89 | } | 93 | } |
| 90 | } | 94 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java index 43745dd9..b81782eb 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java | |||
| @@ -10,7 +10,6 @@ import de.sciss.syntaxpane.util.Configuration; | |||
| 10 | import cuchaz.enigma.gui.config.UiConfig; | 10 | import cuchaz.enigma.gui.config.UiConfig; |
| 11 | 11 | ||
| 12 | public class EnigmaSyntaxKit extends JavaSyntaxKit { | 12 | public class EnigmaSyntaxKit extends JavaSyntaxKit { |
| 13 | |||
| 14 | private static Configuration configuration = null; | 13 | private static Configuration configuration = null; |
| 15 | 14 | ||
| 16 | @Override | 15 | @Override |
| @@ -18,23 +17,20 @@ public class EnigmaSyntaxKit extends JavaSyntaxKit { | |||
| 18 | if (configuration == null) { | 17 | if (configuration == null) { |
| 19 | initConfig(DefaultSyntaxKit.getConfig(JavaSyntaxKit.class)); | 18 | initConfig(DefaultSyntaxKit.getConfig(JavaSyntaxKit.class)); |
| 20 | } | 19 | } |
| 20 | |||
| 21 | return configuration; | 21 | return configuration; |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | public void initConfig(Configuration baseConfig) { | 24 | public void initConfig(Configuration baseConfig) { |
| 25 | configuration = flattenConfiguration(baseConfig, EnigmaSyntaxKit.class); | 25 | configuration = flattenConfiguration(baseConfig, EnigmaSyntaxKit.class); |
| 26 | 26 | ||
| 27 | // Remove all actions except a select few because they disregard the | 27 | // Remove all actions except a select few because they disregard the |
| 28 | // editable state of the editor, or at least are useless anyway because | 28 | // editable state of the editor, or at least are useless anyway because |
| 29 | // they would try editing the file. | 29 | // they would try editing the file. |
| 30 | // Also includes the Action.insert-date action which is written in | 30 | // Also includes the Action.insert-date action which is written in |
| 31 | // Javascript and causes the editor to freeze on first load for a short | 31 | // Javascript and causes the editor to freeze on first load for a short |
| 32 | // time. | 32 | // time. |
| 33 | configuration.keySet().removeIf(s -> s.startsWith("Action.") && | 33 | configuration.keySet().removeIf(s -> s.startsWith("Action.") && !(s.startsWith("Action.find") || s.startsWith("Action.goto-line") || s.startsWith("Action.jump-to-pair") || s.startsWith("Action.quick-find"))); |
| 34 | !(s.startsWith("Action.find") || | ||
| 35 | s.startsWith("Action.goto-line") || | ||
| 36 | s.startsWith("Action.jump-to-pair") || | ||
| 37 | s.startsWith("Action.quick-find"))); | ||
| 38 | 34 | ||
| 39 | // See de.sciss.syntaxpane.TokenType | 35 | // See de.sciss.syntaxpane.TokenType |
| 40 | configuration.put("Style.KEYWORD", String.format("%d, 0", UiConfig.getHighlightColor().getRGB())); | 36 | configuration.put("Style.KEYWORD", String.format("%d, 0", UiConfig.getHighlightColor().getRGB())); |
| @@ -59,27 +55,28 @@ public class EnigmaSyntaxKit extends JavaSyntaxKit { | |||
| 59 | 55 | ||
| 60 | Font editorFont = UiConfig.activeUseCustomFonts() ? UiConfig.getEditorFont() : UiConfig.getFallbackEditorFont(); | 56 | Font editorFont = UiConfig.activeUseCustomFonts() ? UiConfig.getEditorFont() : UiConfig.getFallbackEditorFont(); |
| 61 | configuration.put("DefaultFont", UiConfig.encodeFont(editorFont)); | 57 | configuration.put("DefaultFont", UiConfig.encodeFont(editorFont)); |
| 62 | } | 58 | } |
| 59 | |||
| 60 | /** | ||
| 61 | * Creates a new configuration from the passed configuration so that it has | ||
| 62 | * no parents and all its values are on the same level. This is needed since | ||
| 63 | * there is no way to remove map entries from parent configurations. | ||
| 64 | * | ||
| 65 | * @param source the configuration to flatten | ||
| 66 | * @param configClass the class for the new configuration | ||
| 67 | * @return a new configuration | ||
| 68 | */ | ||
| 69 | private static Configuration flattenConfiguration(Configuration source, Class<?> configClass) { | ||
| 70 | Configuration config = new Configuration(configClass, null); | ||
| 63 | 71 | ||
| 64 | /** | 72 | for (String p : source.stringPropertyNames()) { |
| 65 | * Creates a new configuration from the passed configuration so that it has | 73 | config.put(p, source.getString(p)); |
| 66 | * no parents and all its values are on the same level. This is needed since | 74 | } |
| 67 | * there is no way to remove map entries from parent configurations. | 75 | |
| 68 | * | 76 | return config; |
| 69 | * @param source the configuration to flatten | ||
| 70 | * @param configClass the class for the new configuration | ||
| 71 | * @return a new configuration | ||
| 72 | */ | ||
| 73 | private static Configuration flattenConfiguration(Configuration source, Class<?> configClass) { | ||
| 74 | Configuration config = new Configuration(configClass, null); | ||
| 75 | for (String p : source.stringPropertyNames()) { | ||
| 76 | config.put(p, source.getString(p)); | ||
| 77 | } | ||
| 78 | return config; | ||
| 79 | } | 77 | } |
| 80 | 78 | ||
| 81 | public static void invalidate() { | 79 | public static void invalidate() { |
| 82 | configuration = null; | 80 | configuration = null; |
| 83 | } | 81 | } |
| 84 | |||
| 85 | } | 82 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java index 6246192c..76d18598 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ExceptionIgnorer.java | |||
| @@ -1,28 +1,27 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| 14 | public class ExceptionIgnorer { | 14 | public class ExceptionIgnorer { |
| 15 | |||
| 16 | public static boolean shouldIgnore(Throwable t) { | 15 | public static boolean shouldIgnore(Throwable t) { |
| 17 | |||
| 18 | // is this that pesky concurrent access bug in the highlight painter system? | 16 | // is this that pesky concurrent access bug in the highlight painter system? |
| 19 | // (ancient ui code is ancient) | 17 | // (ancient ui code is ancient) |
| 20 | if (t instanceof ArrayIndexOutOfBoundsException) { | 18 | if (t instanceof ArrayIndexOutOfBoundsException) { |
| 21 | StackTraceElement[] stackTrace = t.getStackTrace(); | 19 | StackTraceElement[] stackTrace = t.getStackTrace(); |
| 22 | if (stackTrace.length > 1) { | ||
| 23 | 20 | ||
| 21 | if (stackTrace.length > 1) { | ||
| 24 | // does this stack frame match javax.swing.text.DefaultHighlighter.paint*() ? | 22 | // does this stack frame match javax.swing.text.DefaultHighlighter.paint*() ? |
| 25 | StackTraceElement frame = stackTrace[1]; | 23 | StackTraceElement frame = stackTrace[1]; |
| 24 | |||
| 26 | if (frame.getClassName().equals("javax.swing.text.DefaultHighlighter") && frame.getMethodName().startsWith("paint")) { | 25 | if (frame.getClassName().equals("javax.swing.text.DefaultHighlighter") && frame.getMethodName().startsWith("paint")) { |
| 27 | return true; | 26 | return true; |
| 28 | } | 27 | } |
| @@ -31,5 +30,4 @@ public class ExceptionIgnorer { | |||
| 31 | 30 | ||
| 32 | return false; | 31 | return false; |
| 33 | } | 32 | } |
| 34 | |||
| 35 | } | 33 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index 5a1e3d8b..b3117ce2 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| @@ -17,7 +17,6 @@ import java.awt.Point; | |||
| 17 | import java.awt.event.ActionEvent; | 17 | import java.awt.event.ActionEvent; |
| 18 | import java.nio.file.Path; | 18 | import java.nio.file.Path; |
| 19 | import java.util.Collection; | 19 | import java.util.Collection; |
| 20 | import java.util.Collections; | ||
| 21 | import java.util.List; | 20 | import java.util.List; |
| 22 | import java.util.Set; | 21 | import java.util.Set; |
| 23 | import java.util.concurrent.CompletableFuture; | 22 | import java.util.concurrent.CompletableFuture; |
| @@ -25,12 +24,23 @@ import java.util.function.Consumer; | |||
| 25 | import java.util.function.Function; | 24 | import java.util.function.Function; |
| 26 | 25 | ||
| 27 | import javax.annotation.Nullable; | 26 | import javax.annotation.Nullable; |
| 28 | import javax.swing.*; | 27 | import javax.swing.AbstractAction; |
| 28 | import javax.swing.DefaultListModel; | ||
| 29 | import javax.swing.JButton; | ||
| 30 | import javax.swing.JFileChooser; | ||
| 31 | import javax.swing.JFrame; | ||
| 32 | import javax.swing.JLabel; | ||
| 33 | import javax.swing.JList; | ||
| 34 | import javax.swing.JOptionPane; | ||
| 35 | import javax.swing.JPanel; | ||
| 36 | import javax.swing.JScrollBar; | ||
| 37 | import javax.swing.JScrollPane; | ||
| 38 | import javax.swing.JSplitPane; | ||
| 39 | import javax.swing.JTabbedPane; | ||
| 40 | import javax.swing.JTextField; | ||
| 41 | import javax.swing.SwingUtilities; | ||
| 42 | import javax.swing.WindowConstants; | ||
| 29 | import javax.swing.tree.DefaultMutableTreeNode; | 43 | import javax.swing.tree.DefaultMutableTreeNode; |
| 30 | import javax.swing.tree.TreeNode; | ||
| 31 | import javax.swing.tree.TreePath; | ||
| 32 | |||
| 33 | import com.google.common.collect.Lists; | ||
| 34 | 44 | ||
| 35 | import cuchaz.enigma.Enigma; | 45 | import cuchaz.enigma.Enigma; |
| 36 | import cuchaz.enigma.EnigmaProfile; | 46 | import cuchaz.enigma.EnigmaProfile; |
| @@ -39,8 +49,19 @@ import cuchaz.enigma.gui.config.Themes; | |||
| 39 | import cuchaz.enigma.gui.config.UiConfig; | 49 | import cuchaz.enigma.gui.config.UiConfig; |
| 40 | import cuchaz.enigma.gui.dialog.JavadocDialog; | 50 | import cuchaz.enigma.gui.dialog.JavadocDialog; |
| 41 | import cuchaz.enigma.gui.dialog.SearchDialog; | 51 | import cuchaz.enigma.gui.dialog.SearchDialog; |
| 42 | import cuchaz.enigma.gui.elements.*; | 52 | import cuchaz.enigma.gui.elements.CallsTree; |
| 43 | import cuchaz.enigma.gui.panels.*; | 53 | import cuchaz.enigma.gui.elements.CollapsibleTabbedPane; |
| 54 | import cuchaz.enigma.gui.elements.EditorTabbedPane; | ||
| 55 | import cuchaz.enigma.gui.elements.ImplementationsTree; | ||
| 56 | import cuchaz.enigma.gui.elements.InheritanceTree; | ||
| 57 | import cuchaz.enigma.gui.elements.MainWindow; | ||
| 58 | import cuchaz.enigma.gui.elements.MenuBar; | ||
| 59 | import cuchaz.enigma.gui.elements.ValidatableUi; | ||
| 60 | import cuchaz.enigma.gui.panels.DeobfPanel; | ||
| 61 | import cuchaz.enigma.gui.panels.EditorPanel; | ||
| 62 | import cuchaz.enigma.gui.panels.IdentifierPanel; | ||
| 63 | import cuchaz.enigma.gui.panels.ObfPanel; | ||
| 64 | import cuchaz.enigma.gui.panels.StructurePanel; | ||
| 44 | import cuchaz.enigma.gui.renderer.MessageListCellRenderer; | 65 | import cuchaz.enigma.gui.renderer.MessageListCellRenderer; |
| 45 | import cuchaz.enigma.gui.util.GuiUtil; | 66 | import cuchaz.enigma.gui.util.GuiUtil; |
| 46 | import cuchaz.enigma.gui.util.LanguageUtil; | 67 | import cuchaz.enigma.gui.util.LanguageUtil; |
| @@ -57,7 +78,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage; | |||
| 57 | import cuchaz.enigma.utils.validation.ValidationContext; | 78 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 58 | 79 | ||
| 59 | public class Gui { | 80 | public class Gui { |
| 60 | |||
| 61 | private final MainWindow mainWindow = new MainWindow(Enigma.NAME); | 81 | private final MainWindow mainWindow = new MainWindow(Enigma.NAME); |
| 62 | private final GuiController controller; | 82 | private final GuiController controller; |
| 63 | 83 | ||
| @@ -179,6 +199,7 @@ public class Gui { | |||
| 179 | 199 | ||
| 180 | // restore state | 200 | // restore state |
| 181 | int[] layout = UiConfig.getLayout(); | 201 | int[] layout = UiConfig.getLayout(); |
| 202 | |||
| 182 | if (layout.length >= 4) { | 203 | if (layout.length >= 4) { |
| 183 | this.splitClasses.setDividerLocation(layout[0]); | 204 | this.splitClasses.setDividerLocation(layout[0]); |
| 184 | this.splitCenter.setDividerLocation(layout[1]); | 205 | this.splitCenter.setDividerLocation(layout[1]); |
| @@ -200,6 +221,7 @@ public class Gui { | |||
| 200 | frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); | 221 | frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); |
| 201 | 222 | ||
| 202 | Point windowPos = UiConfig.getWindowPos("Main Window", null); | 223 | Point windowPos = UiConfig.getWindowPos("Main Window", null); |
| 224 | |||
| 203 | if (windowPos != null) { | 225 | if (windowPos != null) { |
| 204 | frame.setLocation(windowPos); | 226 | frame.setLocation(windowPos); |
| 205 | } else { | 227 | } else { |
| @@ -327,18 +349,26 @@ public class Gui { | |||
| 327 | 349 | ||
| 328 | public void startDocChange(EditorPanel editor) { | 350 | public void startDocChange(EditorPanel editor) { |
| 329 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 351 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 330 | if (cursorReference == null || !this.isEditable(EditableType.JAVADOC)) return; | 352 | |
| 353 | if (cursorReference == null || !this.isEditable(EditableType.JAVADOC)) { | ||
| 354 | return; | ||
| 355 | } | ||
| 356 | |||
| 331 | JavadocDialog.show(mainWindow.frame(), getController(), cursorReference); | 357 | JavadocDialog.show(mainWindow.frame(), getController(), cursorReference); |
| 332 | } | 358 | } |
| 333 | 359 | ||
| 334 | public void startRename(EditorPanel editor, String text) { | 360 | public void startRename(EditorPanel editor, String text) { |
| 335 | if (editor != this.editorTabbedPane.getActiveEditor()) return; | 361 | if (editor != this.editorTabbedPane.getActiveEditor()) { |
| 362 | return; | ||
| 363 | } | ||
| 336 | 364 | ||
| 337 | infoPanel.startRenaming(text); | 365 | infoPanel.startRenaming(text); |
| 338 | } | 366 | } |
| 339 | 367 | ||
| 340 | public void startRename(EditorPanel editor) { | 368 | public void startRename(EditorPanel editor) { |
| 341 | if (editor != this.editorTabbedPane.getActiveEditor()) return; | 369 | if (editor != this.editorTabbedPane.getActiveEditor()) { |
| 370 | return; | ||
| 371 | } | ||
| 342 | 372 | ||
| 343 | infoPanel.startRenaming(); | 373 | infoPanel.startRenaming(); |
| 344 | } | 374 | } |
| @@ -349,7 +379,10 @@ public class Gui { | |||
| 349 | 379 | ||
| 350 | public void showInheritance(EditorPanel editor) { | 380 | public void showInheritance(EditorPanel editor) { |
| 351 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 381 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 352 | if (cursorReference == null) return; | 382 | |
| 383 | if (cursorReference == null) { | ||
| 384 | return; | ||
| 385 | } | ||
| 353 | 386 | ||
| 354 | this.inheritanceTree.display(cursorReference.entry); | 387 | this.inheritanceTree.display(cursorReference.entry); |
| 355 | tabs.setSelectedIndex(1); | 388 | tabs.setSelectedIndex(1); |
| @@ -357,7 +390,10 @@ public class Gui { | |||
| 357 | 390 | ||
| 358 | public void showImplementations(EditorPanel editor) { | 391 | public void showImplementations(EditorPanel editor) { |
| 359 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 392 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 360 | if (cursorReference == null) return; | 393 | |
| 394 | if (cursorReference == null) { | ||
| 395 | return; | ||
| 396 | } | ||
| 361 | 397 | ||
| 362 | this.implementationsTree.display(cursorReference.entry); | 398 | this.implementationsTree.display(cursorReference.entry); |
| 363 | tabs.setSelectedIndex(2); | 399 | tabs.setSelectedIndex(2); |
| @@ -365,7 +401,10 @@ public class Gui { | |||
| 365 | 401 | ||
| 366 | public void showCalls(EditorPanel editor, boolean recurse) { | 402 | public void showCalls(EditorPanel editor, boolean recurse) { |
| 367 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 403 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 368 | if (cursorReference == null) return; | 404 | |
| 405 | if (cursorReference == null) { | ||
| 406 | return; | ||
| 407 | } | ||
| 369 | 408 | ||
| 370 | this.callsTree.showCalls(cursorReference.entry, recurse); | 409 | this.callsTree.showCalls(cursorReference.entry, recurse); |
| 371 | tabs.setSelectedIndex(3); | 410 | tabs.setSelectedIndex(3); |
| @@ -373,7 +412,10 @@ public class Gui { | |||
| 373 | 412 | ||
| 374 | public void toggleMapping(EditorPanel editor) { | 413 | public void toggleMapping(EditorPanel editor) { |
| 375 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); | 414 | EntryReference<Entry<?>, Entry<?>> cursorReference = editor.getCursorReference(); |
| 376 | if (cursorReference == null) return; | 415 | |
| 416 | if (cursorReference == null) { | ||
| 417 | return; | ||
| 418 | } | ||
| 377 | 419 | ||
| 378 | Entry<?> obfEntry = cursorReference.entry; | 420 | Entry<?> obfEntry = cursorReference.entry; |
| 379 | toggleMappingFromEntry(obfEntry); | 421 | toggleMappingFromEntry(obfEntry); |
| @@ -388,14 +430,15 @@ public class Gui { | |||
| 388 | } | 430 | } |
| 389 | 431 | ||
| 390 | public void showDiscardDiag(Function<Integer, Void> callback, String... options) { | 432 | public void showDiscardDiag(Function<Integer, Void> callback, String... options) { |
| 391 | int response = JOptionPane.showOptionDialog(this.mainWindow.frame(), I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION, | 433 | int response = JOptionPane.showOptionDialog(this.mainWindow.frame(), I18n.translate("prompt.close.summary"), I18n.translate("prompt.close.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]); |
| 392 | JOptionPane.QUESTION_MESSAGE, null, options, options[2]); | ||
| 393 | callback.apply(response); | 434 | callback.apply(response); |
| 394 | } | 435 | } |
| 395 | 436 | ||
| 396 | public CompletableFuture<Void> saveMapping() { | 437 | public CompletableFuture<Void> saveMapping() { |
| 397 | if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) | 438 | if (this.enigmaMappingsFileChooser.getSelectedFile() != null || this.enigmaMappingsFileChooser.showSaveDialog(this.mainWindow.frame()) == JFileChooser.APPROVE_OPTION) { |
| 398 | return this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile().toPath()); | 439 | return this.controller.saveMappings(this.enigmaMappingsFileChooser.getSelectedFile().toPath()); |
| 440 | } | ||
| 441 | |||
| 399 | return CompletableFuture.completedFuture(null); | 442 | return CompletableFuture.completedFuture(null); |
| 400 | } | 443 | } |
| 401 | 444 | ||
| @@ -421,16 +464,13 @@ public class Gui { | |||
| 421 | private void exit() { | 464 | private void exit() { |
| 422 | UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen()); | 465 | UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen()); |
| 423 | UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize()); | 466 | UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize()); |
| 424 | UiConfig.setLayout( | 467 | UiConfig.setLayout(this.splitClasses.getDividerLocation(), this.splitCenter.getDividerLocation(), this.splitRight.getDividerLocation(), this.logSplit.getDividerLocation()); |
| 425 | this.splitClasses.getDividerLocation(), | ||
| 426 | this.splitCenter.getDividerLocation(), | ||
| 427 | this.splitRight.getDividerLocation(), | ||
| 428 | this.logSplit.getDividerLocation()); | ||
| 429 | UiConfig.save(); | 468 | UiConfig.save(); |
| 430 | 469 | ||
| 431 | if (searchDialog != null) { | 470 | if (searchDialog != null) { |
| 432 | searchDialog.dispose(); | 471 | searchDialog.dispose(); |
| 433 | } | 472 | } |
| 473 | |||
| 434 | this.mainWindow.frame().dispose(); | 474 | this.mainWindow.frame().dispose(); |
| 435 | System.exit(0); | 475 | System.exit(0); |
| 436 | } | 476 | } |
| @@ -452,6 +492,7 @@ public class Gui { | |||
| 452 | 492 | ||
| 453 | onRenameFromClassTree(vc, prevDataChild, dataChild, node); | 493 | onRenameFromClassTree(vc, prevDataChild, dataChild, node); |
| 454 | } | 494 | } |
| 495 | |||
| 455 | node.setUserObject(data); | 496 | node.setUserObject(data); |
| 456 | // Ob package will never be modified, just reload deob view | 497 | // Ob package will never be modified, just reload deob view |
| 457 | this.deobfPanel.deobfClasses.reload(); | 498 | this.deobfPanel.deobfClasses.reload(); |
| @@ -462,11 +503,7 @@ public class Gui { | |||
| 462 | // fast enough for now | 503 | // fast enough for now |
| 463 | EntryRemapper mapper = this.controller.project.getMapper(); | 504 | EntryRemapper mapper = this.controller.project.getMapper(); |
| 464 | ClassEntry deobf = (ClassEntry) prevData; | 505 | ClassEntry deobf = (ClassEntry) prevData; |
| 465 | ClassEntry obf = mapper.getObfToDeobf().getAllEntries() | 506 | ClassEntry obf = mapper.getObfToDeobf().getAllEntries().filter(e -> e instanceof ClassEntry).map(e -> (ClassEntry) e).filter(e -> mapper.deobfuscate(e).equals(deobf)).findAny().orElse(deobf); |
| 466 | .filter(e -> e instanceof ClassEntry) | ||
| 467 | .map(e -> (ClassEntry) e) | ||
| 468 | .filter(e -> mapper.deobfuscate(e).equals(deobf)) | ||
| 469 | .findAny().orElse(deobf); | ||
| 470 | 507 | ||
| 471 | this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); | 508 | this.controller.applyChange(vc, EntryChange.modify(obf).withDeobfName(((ClassEntry) data).getFullName())); |
| 472 | } else { | 509 | } else { |
| @@ -493,16 +530,12 @@ public class Gui { | |||
| 493 | this.obfPanel.obfClasses.removeEntry(classEntry); | 530 | this.obfPanel.obfClasses.removeEntry(classEntry); |
| 494 | this.deobfPanel.deobfClasses.reload(); | 531 | this.deobfPanel.deobfClasses.reload(); |
| 495 | this.obfPanel.obfClasses.reload(); | 532 | this.obfPanel.obfClasses.reload(); |
| 496 | } | 533 | } else if (!isOldOb) { // Deob -> ob |
| 497 | // Deob -> ob | ||
| 498 | else if (!isOldOb) { | ||
| 499 | this.obfPanel.obfClasses.moveClassIn(classEntry); | 534 | this.obfPanel.obfClasses.moveClassIn(classEntry); |
| 500 | this.deobfPanel.deobfClasses.removeEntry(classEntry); | 535 | this.deobfPanel.deobfClasses.removeEntry(classEntry); |
| 501 | this.deobfPanel.deobfClasses.reload(); | 536 | this.deobfPanel.deobfClasses.reload(); |
| 502 | this.obfPanel.obfClasses.reload(); | 537 | this.obfPanel.obfClasses.reload(); |
| 503 | } | 538 | } else if (isOldOb) { // Local move |
| 504 | // Local move | ||
| 505 | else if (isOldOb) { | ||
| 506 | this.obfPanel.obfClasses.moveClassIn(classEntry); | 539 | this.obfPanel.obfClasses.moveClassIn(classEntry); |
| 507 | this.obfPanel.obfClasses.reload(); | 540 | this.obfPanel.obfClasses.reload(); |
| 508 | } else { | 541 | } else { |
| @@ -526,6 +559,7 @@ public class Gui { | |||
| 526 | if (searchDialog == null) { | 559 | if (searchDialog == null) { |
| 527 | searchDialog = new SearchDialog(this); | 560 | searchDialog = new SearchDialog(this); |
| 528 | } | 561 | } |
| 562 | |||
| 529 | return searchDialog; | 563 | return searchDialog; |
| 530 | } | 564 | } |
| 531 | 565 | ||
| @@ -549,9 +583,11 @@ public class Gui { | |||
| 549 | 583 | ||
| 550 | private void sendMessage() { | 584 | private void sendMessage() { |
| 551 | String text = chatBox.getText().trim(); | 585 | String text = chatBox.getText().trim(); |
| 586 | |||
| 552 | if (!text.isEmpty()) { | 587 | if (!text.isEmpty()) { |
| 553 | getController().sendPacket(new MessageC2SPacket(text)); | 588 | getController().sendPacket(new MessageC2SPacket(text)); |
| 554 | } | 589 | } |
| 590 | |||
| 555 | chatBox.setText(""); | 591 | chatBox.setText(""); |
| 556 | } | 592 | } |
| 557 | 593 | ||
| @@ -617,16 +653,17 @@ public class Gui { | |||
| 617 | public boolean validateImmediateAction(Consumer<ValidationContext> op) { | 653 | public boolean validateImmediateAction(Consumer<ValidationContext> op) { |
| 618 | ValidationContext vc = new ValidationContext(); | 654 | ValidationContext vc = new ValidationContext(); |
| 619 | op.accept(vc); | 655 | op.accept(vc); |
| 656 | |||
| 620 | if (!vc.canProceed()) { | 657 | if (!vc.canProceed()) { |
| 621 | List<ParameterizedMessage> messages = vc.getMessages(); | 658 | List<ParameterizedMessage> messages = vc.getMessages(); |
| 622 | String text = ValidatableUi.formatMessages(messages); | 659 | String text = ValidatableUi.formatMessages(messages); |
| 623 | JOptionPane.showMessageDialog(this.getFrame(), text, String.format("%d message(s)", messages.size()), JOptionPane.ERROR_MESSAGE); | 660 | JOptionPane.showMessageDialog(this.getFrame(), text, String.format("%d message(s)", messages.size()), JOptionPane.ERROR_MESSAGE); |
| 624 | } | 661 | } |
| 662 | |||
| 625 | return vc.canProceed(); | 663 | return vc.canProceed(); |
| 626 | } | 664 | } |
| 627 | 665 | ||
| 628 | public boolean isEditable(EditableType t) { | 666 | public boolean isEditable(EditableType t) { |
| 629 | return this.editableTypes.contains(t); | 667 | return this.editableTypes.contains(t); |
| 630 | } | 668 | } |
| 631 | |||
| 632 | } | 669 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 47a854f9..0eb9a167 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| @@ -32,7 +32,17 @@ import com.google.common.collect.Lists; | |||
| 32 | import cuchaz.enigma.Enigma; | 32 | import cuchaz.enigma.Enigma; |
| 33 | import cuchaz.enigma.EnigmaProfile; | 33 | import cuchaz.enigma.EnigmaProfile; |
| 34 | import cuchaz.enigma.EnigmaProject; | 34 | import cuchaz.enigma.EnigmaProject; |
| 35 | import cuchaz.enigma.analysis.*; | 35 | import cuchaz.enigma.analysis.ClassImplementationsTreeNode; |
| 36 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; | ||
| 37 | import cuchaz.enigma.analysis.ClassReferenceTreeNode; | ||
| 38 | import cuchaz.enigma.analysis.EntryReference; | ||
| 39 | import cuchaz.enigma.analysis.FieldReferenceTreeNode; | ||
| 40 | import cuchaz.enigma.analysis.IndexTreeBuilder; | ||
| 41 | import cuchaz.enigma.analysis.MethodImplementationsTreeNode; | ||
| 42 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; | ||
| 43 | import cuchaz.enigma.analysis.MethodReferenceTreeNode; | ||
| 44 | import cuchaz.enigma.analysis.StructureTreeNode; | ||
| 45 | import cuchaz.enigma.analysis.StructureTreeOptions; | ||
| 36 | import cuchaz.enigma.api.service.ObfuscationTestService; | 46 | import cuchaz.enigma.api.service.ObfuscationTestService; |
| 37 | import cuchaz.enigma.classhandle.ClassHandle; | 47 | import cuchaz.enigma.classhandle.ClassHandle; |
| 38 | import cuchaz.enigma.classhandle.ClassHandleProvider; | 48 | import cuchaz.enigma.classhandle.ClassHandleProvider; |
| @@ -44,7 +54,12 @@ import cuchaz.enigma.gui.newabstraction.EntryValidation; | |||
| 44 | import cuchaz.enigma.gui.stats.StatsGenerator; | 54 | import cuchaz.enigma.gui.stats.StatsGenerator; |
| 45 | import cuchaz.enigma.gui.stats.StatsMember; | 55 | import cuchaz.enigma.gui.stats.StatsMember; |
| 46 | import cuchaz.enigma.gui.util.History; | 56 | import cuchaz.enigma.gui.util.History; |
| 47 | import cuchaz.enigma.network.*; | 57 | import cuchaz.enigma.network.ClientPacketHandler; |
| 58 | import cuchaz.enigma.network.EnigmaClient; | ||
| 59 | import cuchaz.enigma.network.EnigmaServer; | ||
| 60 | import cuchaz.enigma.network.IntegratedEnigmaServer; | ||
| 61 | import cuchaz.enigma.network.Message; | ||
| 62 | import cuchaz.enigma.network.ServerPacketHandler; | ||
| 48 | import cuchaz.enigma.network.packet.EntryChangeC2SPacket; | 63 | import cuchaz.enigma.network.packet.EntryChangeC2SPacket; |
| 49 | import cuchaz.enigma.network.packet.LoginC2SPacket; | 64 | import cuchaz.enigma.network.packet.LoginC2SPacket; |
| 50 | import cuchaz.enigma.network.packet.Packet; | 65 | import cuchaz.enigma.network.packet.Packet; |
| @@ -54,7 +69,12 @@ import cuchaz.enigma.source.SourceIndex; | |||
| 54 | import cuchaz.enigma.source.Token; | 69 | import cuchaz.enigma.source.Token; |
| 55 | import cuchaz.enigma.translation.TranslateResult; | 70 | import cuchaz.enigma.translation.TranslateResult; |
| 56 | import cuchaz.enigma.translation.Translator; | 71 | import cuchaz.enigma.translation.Translator; |
| 57 | import cuchaz.enigma.translation.mapping.*; | 72 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 73 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 74 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 75 | import cuchaz.enigma.translation.mapping.EntryUtil; | ||
| 76 | import cuchaz.enigma.translation.mapping.MappingDelta; | ||
| 77 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | ||
| 58 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 78 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; |
| 59 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 79 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; |
| 60 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 80 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| @@ -90,9 +110,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 90 | 110 | ||
| 91 | public GuiController(Gui gui, EnigmaProfile profile) { | 111 | public GuiController(Gui gui, EnigmaProfile profile) { |
| 92 | this.gui = gui; | 112 | this.gui = gui; |
| 93 | this.enigma = Enigma.builder() | 113 | this.enigma = Enigma.builder().setProfile(profile).build(); |
| 94 | .setProfile(profile) | ||
| 95 | .build(); | ||
| 96 | } | 114 | } |
| 97 | 115 | ||
| 98 | public boolean isDirty() { | 116 | public boolean isDirty() { |
| @@ -121,7 +139,9 @@ public class GuiController implements ClientPacketHandler { | |||
| 121 | } | 139 | } |
| 122 | 140 | ||
| 123 | public CompletableFuture<Void> openMappings(MappingFormat format, Path path) { | 141 | public CompletableFuture<Void> openMappings(MappingFormat format, Path path) { |
| 124 | if (project == null) return CompletableFuture.completedFuture(null); | 142 | if (project == null) { |
| 143 | return CompletableFuture.completedFuture(null); | ||
| 144 | } | ||
| 125 | 145 | ||
| 126 | gui.setMappingsFile(path); | 146 | gui.setMappingsFile(path); |
| 127 | 147 | ||
| @@ -145,7 +165,9 @@ public class GuiController implements ClientPacketHandler { | |||
| 145 | 165 | ||
| 146 | @Override | 166 | @Override |
| 147 | public void openMappings(EntryTree<EntryMapping> mappings) { | 167 | public void openMappings(EntryTree<EntryMapping> mappings) { |
| 148 | if (project == null) return; | 168 | if (project == null) { |
| 169 | return; | ||
| 170 | } | ||
| 149 | 171 | ||
| 150 | project.setMappings(mappings); | 172 | project.setMappings(mappings); |
| 151 | refreshClasses(); | 173 | refreshClasses(); |
| @@ -168,7 +190,9 @@ public class GuiController implements ClientPacketHandler { | |||
| 168 | * @return the future of saving | 190 | * @return the future of saving |
| 169 | */ | 191 | */ |
| 170 | public CompletableFuture<Void> saveMappings(Path path, MappingFormat format) { | 192 | public CompletableFuture<Void> saveMappings(Path path, MappingFormat format) { |
| 171 | if (project == null) return CompletableFuture.completedFuture(null); | 193 | if (project == null) { |
| 194 | return CompletableFuture.completedFuture(null); | ||
| 195 | } | ||
| 172 | 196 | ||
| 173 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { | 197 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { |
| 174 | EntryRemapper mapper = project.getMapper(); | 198 | EntryRemapper mapper = project.getMapper(); |
| @@ -189,7 +213,9 @@ public class GuiController implements ClientPacketHandler { | |||
| 189 | } | 213 | } |
| 190 | 214 | ||
| 191 | public void closeMappings() { | 215 | public void closeMappings() { |
| 192 | if (project == null) return; | 216 | if (project == null) { |
| 217 | return; | ||
| 218 | } | ||
| 193 | 219 | ||
| 194 | project.setMappings(null); | 220 | project.setMappings(null); |
| 195 | 221 | ||
| @@ -202,9 +228,11 @@ public class GuiController implements ClientPacketHandler { | |||
| 202 | Path jarPath = this.project.getJarPath(); | 228 | Path jarPath = this.project.getJarPath(); |
| 203 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; | 229 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; |
| 204 | Path loadedMappingPath = this.loadedMappingPath; | 230 | Path loadedMappingPath = this.loadedMappingPath; |
| 231 | |||
| 205 | if (jarPath != null) { | 232 | if (jarPath != null) { |
| 206 | this.closeJar(); | 233 | this.closeJar(); |
| 207 | CompletableFuture<Void> f = this.openJar(jarPath); | 234 | CompletableFuture<Void> f = this.openJar(jarPath); |
| 235 | |||
| 208 | if (loadedMappingFormat != null && loadedMappingPath != null) { | 236 | if (loadedMappingFormat != null && loadedMappingPath != null) { |
| 209 | f.whenComplete((v, t) -> this.openMappings(loadedMappingFormat, loadedMappingPath)); | 237 | f.whenComplete((v, t) -> this.openMappings(loadedMappingFormat, loadedMappingPath)); |
| 210 | } | 238 | } |
| @@ -214,6 +242,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 214 | public void reloadMappings() { | 242 | public void reloadMappings() { |
| 215 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; | 243 | MappingFormat loadedMappingFormat = this.loadedMappingFormat; |
| 216 | Path loadedMappingPath = this.loadedMappingPath; | 244 | Path loadedMappingPath = this.loadedMappingPath; |
| 245 | |||
| 217 | if (loadedMappingFormat != null && loadedMappingPath != null) { | 246 | if (loadedMappingFormat != null && loadedMappingPath != null) { |
| 218 | this.closeMappings(); | 247 | this.closeMappings(); |
| 219 | this.openMappings(loadedMappingFormat, loadedMappingPath); | 248 | this.openMappings(loadedMappingFormat, loadedMappingPath); |
| @@ -221,29 +250,34 @@ public class GuiController implements ClientPacketHandler { | |||
| 221 | } | 250 | } |
| 222 | 251 | ||
| 223 | public CompletableFuture<Void> dropMappings() { | 252 | public CompletableFuture<Void> dropMappings() { |
| 224 | if (project == null) return CompletableFuture.completedFuture(null); | 253 | if (project == null) { |
| 254 | return CompletableFuture.completedFuture(null); | ||
| 255 | } | ||
| 225 | 256 | ||
| 226 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> project.dropMappings(progress)); | 257 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> project.dropMappings(progress)); |
| 227 | } | 258 | } |
| 228 | 259 | ||
| 229 | public CompletableFuture<Void> exportSource(final Path path) { | 260 | public CompletableFuture<Void> exportSource(final Path path) { |
| 230 | if (project == null) return CompletableFuture.completedFuture(null); | 261 | if (project == null) { |
| 262 | return CompletableFuture.completedFuture(null); | ||
| 263 | } | ||
| 231 | 264 | ||
| 232 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { | 265 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { |
| 233 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); | 266 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); |
| 234 | jar.decompileStream(progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE) | 267 | jar.decompileStream(progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE).forEach(source -> { |
| 235 | .forEach(source -> { | 268 | try { |
| 236 | try { | 269 | source.writeTo(source.resolvePath(path)); |
| 237 | source.writeTo(source.resolvePath(path)); | 270 | } catch (IOException e) { |
| 238 | } catch (IOException e) { | 271 | e.printStackTrace(); |
| 239 | e.printStackTrace(); | 272 | } |
| 240 | } | 273 | }); |
| 241 | }); | ||
| 242 | }); | 274 | }); |
| 243 | } | 275 | } |
| 244 | 276 | ||
| 245 | public CompletableFuture<Void> exportJar(final Path path) { | 277 | public CompletableFuture<Void> exportJar(final Path path) { |
| 246 | if (project == null) return CompletableFuture.completedFuture(null); | 278 | if (project == null) { |
| 279 | return CompletableFuture.completedFuture(null); | ||
| 280 | } | ||
| 247 | 281 | ||
| 248 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { | 282 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { |
| 249 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); | 283 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); |
| @@ -269,20 +303,14 @@ public class GuiController implements ClientPacketHandler { | |||
| 269 | } | 303 | } |
| 270 | 304 | ||
| 271 | try { | 305 | try { |
| 272 | return tokenHandle.getSource().get() | 306 | return tokenHandle.getSource().get().map(DecompiledClassSource::getIndex).map(index -> new ReadableToken(index.getLineNumber(token.start), index.getColumnNumber(token.start), index.getColumnNumber(token.end))).unwrapOr(null); |
| 273 | .map(DecompiledClassSource::getIndex) | ||
| 274 | .map(index -> new ReadableToken( | ||
| 275 | index.getLineNumber(token.start), | ||
| 276 | index.getColumnNumber(token.start), | ||
| 277 | index.getColumnNumber(token.end))) | ||
| 278 | .unwrapOr(null); | ||
| 279 | } catch (InterruptedException | ExecutionException e) { | 307 | } catch (InterruptedException | ExecutionException e) { |
| 280 | throw new RuntimeException(e); | 308 | throw new RuntimeException(e); |
| 281 | } | 309 | } |
| 282 | } | 310 | } |
| 283 | 311 | ||
| 284 | /** | 312 | /** |
| 285 | * Navigates to the declaration with respect to navigation history | 313 | * Navigates to the declaration with respect to navigation history. |
| 286 | * | 314 | * |
| 287 | * @param entry the entry whose declaration will be navigated to | 315 | * @param entry the entry whose declaration will be navigated to |
| 288 | */ | 316 | */ |
| @@ -290,11 +318,12 @@ public class GuiController implements ClientPacketHandler { | |||
| 290 | if (entry == null) { | 318 | if (entry == null) { |
| 291 | throw new IllegalArgumentException("Entry cannot be null!"); | 319 | throw new IllegalArgumentException("Entry cannot be null!"); |
| 292 | } | 320 | } |
| 321 | |||
| 293 | openReference(EntryReference.declaration(entry, entry.getName())); | 322 | openReference(EntryReference.declaration(entry, entry.getName())); |
| 294 | } | 323 | } |
| 295 | 324 | ||
| 296 | /** | 325 | /** |
| 297 | * Navigates to the reference with respect to navigation history | 326 | * Navigates to the reference with respect to navigation history. |
| 298 | * | 327 | * |
| 299 | * @param reference the reference | 328 | * @param reference the reference |
| 300 | */ | 329 | */ |
| @@ -302,6 +331,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 302 | if (reference == null) { | 331 | if (reference == null) { |
| 303 | throw new IllegalArgumentException("Reference cannot be null!"); | 332 | throw new IllegalArgumentException("Reference cannot be null!"); |
| 304 | } | 333 | } |
| 334 | |||
| 305 | if (this.referenceHistory == null) { | 335 | if (this.referenceHistory == null) { |
| 306 | this.referenceHistory = new History<>(reference); | 336 | this.referenceHistory = new History<>(reference); |
| 307 | } else { | 337 | } else { |
| @@ -317,11 +347,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 317 | EntryRemapper mapper = this.project.getMapper(); | 347 | EntryRemapper mapper = this.project.getMapper(); |
| 318 | 348 | ||
| 319 | SourceIndex index = source.getIndex(); | 349 | SourceIndex index = source.getIndex(); |
| 320 | return mapper.getObfResolver().resolveReference(reference, ResolutionStrategy.RESOLVE_CLOSEST) | 350 | return mapper.getObfResolver().resolveReference(reference, ResolutionStrategy.RESOLVE_CLOSEST).stream().flatMap(r -> index.getReferenceTokens(r).stream()).sorted().toList(); |
| 321 | .stream() | ||
| 322 | .flatMap(r -> index.getReferenceTokens(r).stream()) | ||
| 323 | .sorted() | ||
| 324 | .toList(); | ||
| 325 | } | 351 | } |
| 326 | 352 | ||
| 327 | public void openPreviousReference() { | 353 | public void openPreviousReference() { |
| @@ -349,6 +375,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 349 | // entry is not in the jar. Ignore it | 375 | // entry is not in the jar. Ignore it |
| 350 | return; | 376 | return; |
| 351 | } | 377 | } |
| 378 | |||
| 352 | openDeclaration(entry); | 379 | openDeclaration(entry); |
| 353 | } | 380 | } |
| 354 | 381 | ||
| @@ -356,12 +383,15 @@ public class GuiController implements ClientPacketHandler { | |||
| 356 | if (!project.isRenamable(reference.getLocationClassEntry())) { | 383 | if (!project.isRenamable(reference.getLocationClassEntry())) { |
| 357 | return; | 384 | return; |
| 358 | } | 385 | } |
| 386 | |||
| 359 | openReference(reference); | 387 | openReference(reference); |
| 360 | } | 388 | } |
| 361 | 389 | ||
| 362 | public void refreshClasses() { | 390 | public void refreshClasses() { |
| 363 | if (project == null) return; | 391 | if (project == null) { |
| 364 | 392 | return; | |
| 393 | } | ||
| 394 | |||
| 365 | List<ClassEntry> obfClasses = Lists.newArrayList(); | 395 | List<ClassEntry> obfClasses = Lists.newArrayList(); |
| 366 | List<ClassEntry> deobfClasses = Lists.newArrayList(); | 396 | List<ClassEntry> deobfClasses = Lists.newArrayList(); |
| 367 | this.addSeparatedClasses(obfClasses, deobfClasses); | 397 | this.addSeparatedClasses(obfClasses, deobfClasses); |
| @@ -373,8 +403,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 373 | EntryRemapper mapper = project.getMapper(); | 403 | EntryRemapper mapper = project.getMapper(); |
| 374 | 404 | ||
| 375 | Collection<ClassEntry> classes = project.getJarIndex().getEntryIndex().getClasses(); | 405 | Collection<ClassEntry> classes = project.getJarIndex().getEntryIndex().getClasses(); |
| 376 | Stream<ClassEntry> visibleClasses = classes.stream() | 406 | Stream<ClassEntry> visibleClasses = classes.stream().filter(entry -> !entry.isInnerClass()); |
| 377 | .filter(entry -> !entry.isInnerClass()); | ||
| 378 | 407 | ||
| 379 | visibleClasses.forEach(entry -> { | 408 | visibleClasses.forEach(entry -> { |
| 380 | if (gui.isSingleClassTree()) { | 409 | if (gui.isSingleClassTree()) { |
| @@ -428,12 +457,15 @@ public class GuiController implements ClientPacketHandler { | |||
| 428 | public MethodImplementationsTreeNode getMethodImplementations(MethodEntry entry) { | 457 | public MethodImplementationsTreeNode getMethodImplementations(MethodEntry entry) { |
| 429 | Translator translator = project.getMapper().getDeobfuscator(); | 458 | Translator translator = project.getMapper().getDeobfuscator(); |
| 430 | List<MethodImplementationsTreeNode> rootNodes = indexTreeBuilder.buildMethodImplementations(translator, entry); | 459 | List<MethodImplementationsTreeNode> rootNodes = indexTreeBuilder.buildMethodImplementations(translator, entry); |
| 460 | |||
| 431 | if (rootNodes.isEmpty()) { | 461 | if (rootNodes.isEmpty()) { |
| 432 | return null; | 462 | return null; |
| 433 | } | 463 | } |
| 464 | |||
| 434 | if (rootNodes.size() > 1) { | 465 | if (rootNodes.size() > 1) { |
| 435 | System.err.println("WARNING: Method " + entry + " implements multiple interfaces. Only showing first one."); | 466 | System.err.println("WARNING: Method " + entry + " implements multiple interfaces. Only showing first one."); |
| 436 | } | 467 | } |
| 468 | |||
| 437 | return MethodImplementationsTreeNode.findNode(rootNodes.get(0), entry); | 469 | return MethodImplementationsTreeNode.findNode(rootNodes.get(0), entry); |
| 438 | } | 470 | } |
| 439 | 471 | ||
| @@ -481,13 +513,20 @@ public class GuiController implements ClientPacketHandler { | |||
| 481 | public void applyChange(ValidationContext vc, EntryChange<?> change) { | 513 | public void applyChange(ValidationContext vc, EntryChange<?> change) { |
| 482 | this.applyChange0(vc, change); | 514 | this.applyChange0(vc, change); |
| 483 | gui.showStructure(gui.getActiveEditor()); | 515 | gui.showStructure(gui.getActiveEditor()); |
| 484 | if (!vc.canProceed()) return; | 516 | |
| 517 | if (!vc.canProceed()) { | ||
| 518 | return; | ||
| 519 | } | ||
| 520 | |||
| 485 | this.sendPacket(new EntryChangeC2SPacket(change)); | 521 | this.sendPacket(new EntryChangeC2SPacket(change)); |
| 486 | } | 522 | } |
| 487 | 523 | ||
| 488 | private void applyChange0(ValidationContext vc, EntryChange<?> change) { | 524 | private void applyChange0(ValidationContext vc, EntryChange<?> change) { |
| 489 | validateChange(vc, change); | 525 | validateChange(vc, change); |
| 490 | if (!vc.canProceed()) return; | 526 | |
| 527 | if (!vc.canProceed()) { | ||
| 528 | return; | ||
| 529 | } | ||
| 491 | 530 | ||
| 492 | Entry<?> target = change.getTarget(); | 531 | Entry<?> target = change.getTarget(); |
| 493 | EntryMapping prev = this.project.getMapper().getDeobfMapping(target); | 532 | EntryMapping prev = this.project.getMapper().getDeobfMapping(target); |
| @@ -506,6 +545,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 506 | if (!Objects.equals(prev.javadoc(), mapping.javadoc())) { | 545 | if (!Objects.equals(prev.javadoc(), mapping.javadoc())) { |
| 507 | this.chp.invalidateJavadoc(target.getTopLevelClass()); | 546 | this.chp.invalidateJavadoc(target.getTopLevelClass()); |
| 508 | } | 547 | } |
| 548 | |||
| 509 | gui.showStructure(gui.getActiveEditor()); | 549 | gui.showStructure(gui.getActiveEditor()); |
| 510 | } | 550 | } |
| 511 | 551 | ||
| @@ -517,10 +557,7 @@ public class GuiController implements ClientPacketHandler { | |||
| 517 | File statsFile = File.createTempFile("stats", ".html"); | 557 | File statsFile = File.createTempFile("stats", ".html"); |
| 518 | 558 | ||
| 519 | try (FileWriter w = new FileWriter(statsFile)) { | 559 | try (FileWriter w = new FileWriter(statsFile)) { |
| 520 | w.write( | 560 | w.write(Utils.readResourceToString("/stats.html").replace("/*data*/", data)); |
| 521 | Utils.readResourceToString("/stats.html") | ||
| 522 | .replace("/*data*/", data) | ||
| 523 | ); | ||
| 524 | } | 561 | } |
| 525 | 562 | ||
| 526 | Desktop.getDesktop().open(statsFile); | 563 | Desktop.getDesktop().open(statsFile); |
| @@ -573,15 +610,18 @@ public class GuiController implements ClientPacketHandler { | |||
| 573 | if (client != null) { | 610 | if (client != null) { |
| 574 | client.disconnect(); | 611 | client.disconnect(); |
| 575 | } | 612 | } |
| 613 | |||
| 576 | if (server != null) { | 614 | if (server != null) { |
| 577 | server.stop(); | 615 | server.stop(); |
| 578 | } | 616 | } |
| 617 | |||
| 579 | client = null; | 618 | client = null; |
| 580 | server = null; | 619 | server = null; |
| 581 | SwingUtilities.invokeLater(() -> { | 620 | SwingUtilities.invokeLater(() -> { |
| 582 | if (reason != null) { | 621 | if (reason != null) { |
| 583 | JOptionPane.showMessageDialog(gui.getFrame(), I18n.translate(reason), I18n.translate("disconnect.disconnected"), JOptionPane.INFORMATION_MESSAGE); | 622 | JOptionPane.showMessageDialog(gui.getFrame(), I18n.translate(reason), I18n.translate("disconnect.disconnected"), JOptionPane.INFORMATION_MESSAGE); |
| 584 | } | 623 | } |
| 624 | |||
| 585 | gui.setConnectionState(ConnectionState.NOT_CONNECTED); | 625 | gui.setConnectionState(ConnectionState.NOT_CONNECTED); |
| 586 | }); | 626 | }); |
| 587 | } | 627 | } |
| @@ -602,5 +642,4 @@ public class GuiController implements ClientPacketHandler { | |||
| 602 | public void updateUserList(List<String> users) { | 642 | public void updateUserList(List<String> users) { |
| 603 | gui.setUserList(users); | 643 | gui.setUserList(users); |
| 604 | } | 644 | } |
| 605 | |||
| 606 | } | 645 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java index 1172a393..56f43859 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Main.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| @@ -20,7 +20,11 @@ import java.util.List; | |||
| 20 | import java.util.Set; | 20 | import java.util.Set; |
| 21 | 21 | ||
| 22 | import com.google.common.io.MoreFiles; | 22 | import com.google.common.io.MoreFiles; |
| 23 | import joptsimple.*; | 23 | import joptsimple.OptionException; |
| 24 | import joptsimple.OptionParser; | ||
| 25 | import joptsimple.OptionSet; | ||
| 26 | import joptsimple.OptionSpec; | ||
| 27 | import joptsimple.ValueConverter; | ||
| 24 | 28 | ||
| 25 | import cuchaz.enigma.EnigmaProfile; | 29 | import cuchaz.enigma.EnigmaProfile; |
| 26 | import cuchaz.enigma.gui.config.Themes; | 30 | import cuchaz.enigma.gui.config.Themes; |
| @@ -30,21 +34,14 @@ import cuchaz.enigma.translation.mapping.serde.MappingFormat; | |||
| 30 | import cuchaz.enigma.utils.I18n; | 34 | import cuchaz.enigma.utils.I18n; |
| 31 | 35 | ||
| 32 | public class Main { | 36 | public class Main { |
| 33 | |||
| 34 | public static void main(String[] args) throws IOException { | 37 | public static void main(String[] args) throws IOException { |
| 35 | OptionParser parser = new OptionParser(); | 38 | OptionParser parser = new OptionParser(); |
| 36 | 39 | ||
| 37 | OptionSpec<Path> jar = parser.accepts("jar", "Jar file to open at startup") | 40 | OptionSpec<Path> jar = parser.accepts("jar", "Jar file to open at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE); |
| 38 | .withRequiredArg() | ||
| 39 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 40 | 41 | ||
| 41 | OptionSpec<Path> mappings = parser.accepts("mappings", "Mappings file to open at startup") | 42 | OptionSpec<Path> mappings = parser.accepts("mappings", "Mappings file to open at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE); |
| 42 | .withRequiredArg() | ||
| 43 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 44 | 43 | ||
| 45 | OptionSpec<Path> profile = parser.accepts("profile", "Profile json to apply at startup") | 44 | OptionSpec<Path> profile = parser.accepts("profile", "Profile json to apply at startup").withRequiredArg().withValuesConvertedBy(PathConverter.INSTANCE); |
| 46 | .withRequiredArg() | ||
| 47 | .withValuesConvertedBy(PathConverter.INSTANCE); | ||
| 48 | 45 | ||
| 49 | parser.acceptsAll(List.of("edit-all", "e"), "Enable editing everything"); | 46 | parser.acceptsAll(List.of("edit-all", "e"), "Enable editing everything"); |
| 50 | parser.acceptsAll(List.of("no-edit-all", "E"), "Disable editing everything"); | 47 | parser.acceptsAll(List.of("no-edit-all", "E"), "Disable editing everything"); |
| @@ -78,26 +75,26 @@ public class Main { | |||
| 78 | for (OptionSpec<?> spec : options.specs()) { | 75 | for (OptionSpec<?> spec : options.specs()) { |
| 79 | for (String s : spec.options()) { | 76 | for (String s : spec.options()) { |
| 80 | switch (s) { | 77 | switch (s) { |
| 81 | case "edit-all" -> editables.addAll(List.of(EditableType.values())); | 78 | case "edit-all" -> editables.addAll(List.of(EditableType.values())); |
| 82 | case "no-edit-all" -> editables.clear(); | 79 | case "no-edit-all" -> editables.clear(); |
| 83 | case "edit-classes" -> editables.add(EditableType.CLASS); | 80 | case "edit-classes" -> editables.add(EditableType.CLASS); |
| 84 | case "no-edit-classes" -> editables.remove(EditableType.CLASS); | 81 | case "no-edit-classes" -> editables.remove(EditableType.CLASS); |
| 85 | case "edit-methods" -> editables.add(EditableType.METHOD); | 82 | case "edit-methods" -> editables.add(EditableType.METHOD); |
| 86 | case "no-edit-methods" -> editables.remove(EditableType.METHOD); | 83 | case "no-edit-methods" -> editables.remove(EditableType.METHOD); |
| 87 | case "edit-fields" -> editables.add(EditableType.FIELD); | 84 | case "edit-fields" -> editables.add(EditableType.FIELD); |
| 88 | case "no-edit-fields" -> editables.remove(EditableType.FIELD); | 85 | case "no-edit-fields" -> editables.remove(EditableType.FIELD); |
| 89 | case "edit-parameters" -> editables.add(EditableType.PARAMETER); | 86 | case "edit-parameters" -> editables.add(EditableType.PARAMETER); |
| 90 | case "no-edit-parameters" -> editables.remove(EditableType.PARAMETER); | 87 | case "no-edit-parameters" -> editables.remove(EditableType.PARAMETER); |
| 91 | case "edit-locals" -> { | 88 | case "edit-locals" -> { |
| 92 | editables.add(EditableType.LOCAL_VARIABLE); | 89 | editables.add(EditableType.LOCAL_VARIABLE); |
| 93 | System.err.println("warning: --edit-locals has no effect as local variables are currently not editable"); | 90 | System.err.println("warning: --edit-locals has no effect as local variables are currently not editable"); |
| 94 | } | 91 | } |
| 95 | case "no-edit-locals" -> { | 92 | case "no-edit-locals" -> { |
| 96 | editables.remove(EditableType.LOCAL_VARIABLE); | 93 | editables.remove(EditableType.LOCAL_VARIABLE); |
| 97 | System.err.println("warning: --no-edit-locals has no effect as local variables are currently not editable"); | 94 | System.err.println("warning: --no-edit-locals has no effect as local variables are currently not editable"); |
| 98 | } | 95 | } |
| 99 | case "edit-javadocs" -> editables.add(EditableType.JAVADOC); | 96 | case "edit-javadocs" -> editables.add(EditableType.JAVADOC); |
| 100 | case "no-edit-javadocs" -> editables.remove(EditableType.JAVADOC); | 97 | case "no-edit-javadocs" -> editables.remove(EditableType.JAVADOC); |
| 101 | } | 98 | } |
| 102 | } | 99 | } |
| 103 | } | 100 | } |
| @@ -110,7 +107,7 @@ public class Main { | |||
| 110 | 107 | ||
| 111 | Gui gui = new Gui(parsedProfile, editables); | 108 | Gui gui = new Gui(parsedProfile, editables); |
| 112 | GuiController controller = gui.getController(); | 109 | GuiController controller = gui.getController(); |
| 113 | 110 | ||
| 114 | if (options.has("single-class-tree")) { | 111 | if (options.has("single-class-tree")) { |
| 115 | gui.setSingleClassTree(true); | 112 | gui.setSingleClassTree(true); |
| 116 | } | 113 | } |
| @@ -120,6 +117,7 @@ public class Main { | |||
| 120 | CrashDialog.init(gui.getFrame()); | 117 | CrashDialog.init(gui.getFrame()); |
| 121 | Thread.setDefaultUncaughtExceptionHandler((thread, t) -> { | 118 | Thread.setDefaultUncaughtExceptionHandler((thread, t) -> { |
| 122 | t.printStackTrace(System.err); | 119 | t.printStackTrace(System.err); |
| 120 | |||
| 123 | if (!ExceptionIgnorer.shouldIgnore(t)) { | 121 | if (!ExceptionIgnorer.shouldIgnore(t)) { |
| 124 | CrashDialog.show(t); | 122 | CrashDialog.show(t); |
| 125 | } | 123 | } |
| @@ -128,19 +126,19 @@ public class Main { | |||
| 128 | 126 | ||
| 129 | if (options.has(jar)) { | 127 | if (options.has(jar)) { |
| 130 | Path jarPath = options.valueOf(jar); | 128 | Path jarPath = options.valueOf(jar); |
| 131 | controller.openJar(jarPath) | 129 | controller.openJar(jarPath).whenComplete((v, t) -> { |
| 132 | .whenComplete((v, t) -> { | 130 | if (options.has(mappings)) { |
| 133 | if (options.has(mappings)) { | 131 | Path mappingsPath = options.valueOf(mappings); |
| 134 | Path mappingsPath = options.valueOf(mappings); | 132 | |
| 135 | if (Files.isDirectory(mappingsPath)) { | 133 | if (Files.isDirectory(mappingsPath)) { |
| 136 | controller.openMappings(MappingFormat.ENIGMA_DIRECTORY, mappingsPath); | 134 | controller.openMappings(MappingFormat.ENIGMA_DIRECTORY, mappingsPath); |
| 137 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsPath))) { | 135 | } else if ("zip".equalsIgnoreCase(MoreFiles.getFileExtension(mappingsPath))) { |
| 138 | controller.openMappings(MappingFormat.ENIGMA_ZIP, mappingsPath); | 136 | controller.openMappings(MappingFormat.ENIGMA_ZIP, mappingsPath); |
| 139 | } else { | 137 | } else { |
| 140 | controller.openMappings(MappingFormat.ENIGMA_FILE, mappingsPath); | 138 | controller.openMappings(MappingFormat.ENIGMA_FILE, mappingsPath); |
| 141 | } | 139 | } |
| 142 | } | 140 | } |
| 143 | }); | 141 | }); |
| 144 | } | 142 | } |
| 145 | } catch (OptionException e) { | 143 | } catch (OptionException e) { |
| 146 | System.out.println("Invalid arguments: " + e.getMessage()); | 144 | System.out.println("Invalid arguments: " + e.getMessage()); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java index 309f9106..c4541fc6 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java | |||
| @@ -1,21 +1,22 @@ | |||
| 1 | package cuchaz.enigma.gui; | 1 | package cuchaz.enigma.gui; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.gui.node.ClassSelectorClassNode; | 3 | import java.util.Collection; |
| 4 | import cuchaz.enigma.gui.node.ClassSelectorPackageNode; | 4 | import java.util.Comparator; |
| 5 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 5 | import java.util.Enumeration; |
| 6 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 6 | import java.util.HashMap; |
| 7 | import java.util.Map; | ||
| 7 | 8 | ||
| 8 | import javax.swing.tree.DefaultMutableTreeNode; | 9 | import javax.swing.tree.DefaultMutableTreeNode; |
| 9 | import javax.swing.tree.MutableTreeNode; | 10 | import javax.swing.tree.MutableTreeNode; |
| 10 | import javax.swing.tree.TreeNode; | 11 | import javax.swing.tree.TreeNode; |
| 11 | import javax.swing.tree.TreePath; | 12 | import javax.swing.tree.TreePath; |
| 12 | import java.util.Collection; | ||
| 13 | import java.util.Comparator; | ||
| 14 | import java.util.HashMap; | ||
| 15 | import java.util.Map; | ||
| 16 | 13 | ||
| 17 | public class NestedPackages { | 14 | import cuchaz.enigma.gui.node.ClassSelectorClassNode; |
| 15 | import cuchaz.enigma.gui.node.ClassSelectorPackageNode; | ||
| 16 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 17 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 18 | 18 | ||
| 19 | public class NestedPackages { | ||
| 19 | private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(); | 20 | private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(); |
| 20 | private final Map<String, DefaultMutableTreeNode> packageToNode = new HashMap<>(); | 21 | private final Map<String, DefaultMutableTreeNode> packageToNode = new HashMap<>(); |
| 21 | private final Map<ClassEntry, ClassSelectorClassNode> classToNode = new HashMap<>(); | 22 | private final Map<ClassEntry, ClassSelectorClassNode> classToNode = new HashMap<>(); |
| @@ -42,20 +43,20 @@ public class NestedPackages { | |||
| 42 | return 0; | 43 | return 0; |
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| 45 | for (var entry : entries) { | 46 | for (ClassEntry entry : entries) { |
| 46 | addEntry(entry); | 47 | addEntry(entry); |
| 47 | } | 48 | } |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | public void addEntry(ClassEntry entry) { | 51 | public void addEntry(ClassEntry entry) { |
| 51 | var translated = remapper.deobfuscate(entry); | 52 | ClassEntry translated = remapper.deobfuscate(entry); |
| 52 | var me = new ClassSelectorClassNode(entry, translated); | 53 | var me = new ClassSelectorClassNode(entry, translated); |
| 53 | classToNode.put(entry, me); | 54 | classToNode.put(entry, me); |
| 54 | insert(getPackage(translated.getPackageName()), me); | 55 | insert(getPackage(translated.getPackageName()), me); |
| 55 | } | 56 | } |
| 56 | 57 | ||
| 57 | public DefaultMutableTreeNode getPackage(String packageName) { | 58 | public DefaultMutableTreeNode getPackage(String packageName) { |
| 58 | var node = packageToNode.get(packageName); | 59 | DefaultMutableTreeNode node = packageToNode.get(packageName); |
| 59 | 60 | ||
| 60 | if (packageName == null) { | 61 | if (packageName == null) { |
| 61 | return root; | 62 | return root; |
| @@ -75,7 +76,7 @@ public class NestedPackages { | |||
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | public TreePath getPackagePath(String packageName) { | 78 | public TreePath getPackagePath(String packageName) { |
| 78 | var node = packageToNode.getOrDefault(packageName, root); | 79 | DefaultMutableTreeNode node = packageToNode.getOrDefault(packageName, root); |
| 79 | return new TreePath(node.getPath()); | 80 | return new TreePath(node.getPath()); |
| 80 | } | 81 | } |
| 81 | 82 | ||
| @@ -84,15 +85,15 @@ public class NestedPackages { | |||
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | public void removeClassNode(ClassEntry entry) { | 87 | public void removeClassNode(ClassEntry entry) { |
| 87 | var node = classToNode.remove(entry); | 88 | ClassSelectorClassNode node = classToNode.remove(entry); |
| 88 | 89 | ||
| 89 | if (node != null) { | 90 | if (node != null) { |
| 90 | node.removeFromParent(); | 91 | node.removeFromParent(); |
| 91 | // remove dangling packages | 92 | // remove dangling packages |
| 92 | var packageNode = packageToNode.get(entry.getPackageName()); | 93 | DefaultMutableTreeNode packageNode = packageToNode.get(entry.getPackageName()); |
| 93 | 94 | ||
| 94 | while (packageNode != null && packageNode.getChildCount() == 0) { | 95 | while (packageNode != null && packageNode.getChildCount() == 0) { |
| 95 | var theNode = packageNode; | 96 | DefaultMutableTreeNode theNode = packageNode; |
| 96 | packageNode = (DefaultMutableTreeNode) packageNode.getParent(); | 97 | packageNode = (DefaultMutableTreeNode) packageNode.getParent(); |
| 97 | theNode.removeFromParent(); | 98 | theNode.removeFromParent(); |
| 98 | 99 | ||
| @@ -108,8 +109,8 @@ public class NestedPackages { | |||
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) { | 111 | private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) { |
| 111 | var index = 0; | 112 | int index = 0; |
| 112 | var children = parent.children(); | 113 | Enumeration<TreeNode> children = parent.children(); |
| 113 | 114 | ||
| 114 | while (children.hasMoreElements()) { | 115 | while (children.hasMoreElements()) { |
| 115 | if (comparator.compare(children.nextElement(), child) < 0) { | 116 | if (comparator.compare(children.nextElement(), child) < 0) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java index b7fa2eba..ff80e17f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/QuickFindAction.java | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | package cuchaz.enigma.gui; | 1 | package cuchaz.enigma.gui; |
| 2 | 2 | ||
| 3 | import de.sciss.syntaxpane.SyntaxDocument; | 3 | import java.awt.event.ActionEvent; |
| 4 | import de.sciss.syntaxpane.actions.DefaultSyntaxAction; | ||
| 5 | 4 | ||
| 6 | import javax.swing.text.JTextComponent; | 5 | import javax.swing.text.JTextComponent; |
| 7 | import java.awt.event.ActionEvent; | 6 | |
| 7 | import de.sciss.syntaxpane.SyntaxDocument; | ||
| 8 | import de.sciss.syntaxpane.actions.DefaultSyntaxAction; | ||
| 8 | 9 | ||
| 9 | public final class QuickFindAction extends DefaultSyntaxAction { | 10 | public final class QuickFindAction extends DefaultSyntaxAction { |
| 10 | public QuickFindAction() { | 11 | public QuickFindAction() { |
| @@ -26,6 +27,7 @@ public final class QuickFindAction extends DefaultSyntaxAction { | |||
| 26 | 27 | ||
| 27 | public static Data get(JTextComponent target) { | 28 | public static Data get(JTextComponent target) { |
| 28 | Object o = target.getDocument().getProperty(KEY); | 29 | Object o = target.getDocument().getProperty(KEY); |
| 30 | |||
| 29 | if (o instanceof Data) { | 31 | if (o instanceof Data) { |
| 30 | return (Data) o; | 32 | return (Data) o; |
| 31 | } | 33 | } |
| @@ -39,6 +41,7 @@ public final class QuickFindAction extends DefaultSyntaxAction { | |||
| 39 | if (findDialog == null) { | 41 | if (findDialog == null) { |
| 40 | findDialog = new EnigmaQuickFindDialog(target); | 42 | findDialog = new EnigmaQuickFindDialog(target); |
| 41 | } | 43 | } |
| 44 | |||
| 42 | findDialog.showFor(target); | 45 | findDialog.showFor(target); |
| 43 | } | 46 | } |
| 44 | } | 47 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java index 3e4b30cd..eac11ed4 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ReadableToken.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| 14 | public class ReadableToken { | 14 | public class ReadableToken { |
| 15 | |||
| 16 | public int line; | 15 | public int line; |
| 17 | public int startColumn; | 16 | public int startColumn; |
| 18 | public int endColumn; | 17 | public int endColumn; |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java index 4ef04428..000793e6 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/TokenListCellRenderer.java | |||
| @@ -1,23 +1,26 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.source.Token; | 14 | import java.awt.Component; |
| 15 | 15 | ||
| 16 | import javax.swing.*; | 16 | import javax.swing.DefaultListCellRenderer; |
| 17 | import java.awt.*; | 17 | import javax.swing.JLabel; |
| 18 | import javax.swing.JList; | ||
| 19 | import javax.swing.ListCellRenderer; | ||
| 18 | 20 | ||
| 19 | public class TokenListCellRenderer implements ListCellRenderer<Token> { | 21 | import cuchaz.enigma.source.Token; |
| 20 | 22 | ||
| 23 | public class TokenListCellRenderer implements ListCellRenderer<Token> { | ||
| 21 | private GuiController controller; | 24 | private GuiController controller; |
| 22 | private DefaultListCellRenderer defaultRenderer; | 25 | private DefaultListCellRenderer defaultRenderer; |
| 23 | 26 | ||
| @@ -32,5 +35,4 @@ public class TokenListCellRenderer implements ListCellRenderer<Token> { | |||
| 32 | label.setText(this.controller.getReadableToken(token).toString()); | 35 | label.setText(this.controller.getReadableToken(token).toString()); |
| 33 | return label; | 36 | return label; |
| 34 | } | 37 | } |
| 35 | |||
| 36 | } | 38 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java index cec3fa1e..2088aac2 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/LookAndFeel.java | |||
| @@ -40,11 +40,11 @@ public enum LookAndFeel { | |||
| 40 | 40 | ||
| 41 | try { | 41 | try { |
| 42 | switch (this) { | 42 | switch (this) { |
| 43 | case NONE -> UIManager.setLookAndFeel(NONE_LAF); | 43 | case NONE -> UIManager.setLookAndFeel(NONE_LAF); |
| 44 | case DEFAULT -> UIManager.setLookAndFeel(new FlatLightLaf()); | 44 | case DEFAULT -> UIManager.setLookAndFeel(new FlatLightLaf()); |
| 45 | case METAL -> UIManager.setLookAndFeel(new MetalLookAndFeel()); | 45 | case METAL -> UIManager.setLookAndFeel(new MetalLookAndFeel()); |
| 46 | case DARCULA -> UIManager.setLookAndFeel(new FlatDarkLaf()); | 46 | case DARCULA -> UIManager.setLookAndFeel(new FlatDarkLaf()); |
| 47 | case SYSTEM -> UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); | 47 | case SYSTEM -> UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); |
| 48 | } | 48 | } |
| 49 | } catch (Exception e) { | 49 | } catch (Exception e) { |
| 50 | throw new Error("Failed to set global look and feel", e); | 50 | throw new Error("Failed to set global look and feel", e); |
| @@ -66,5 +66,4 @@ public enum LookAndFeel { | |||
| 66 | int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue()); | 66 | int b = (int) (0.3 * c.getRed() + 0.59 * c.getGreen() + 0.11 * c.getBlue()); |
| 67 | return b < 85; | 67 | return b < 85; |
| 68 | } | 68 | } |
| 69 | |||
| 70 | } | 69 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java index 4439cb8a..eaf20e7f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/NetConfig.java | |||
| @@ -4,7 +4,6 @@ import cuchaz.enigma.config.ConfigContainer; | |||
| 4 | import cuchaz.enigma.network.EnigmaServer; | 4 | import cuchaz.enigma.network.EnigmaServer; |
| 5 | 5 | ||
| 6 | public final class NetConfig { | 6 | public final class NetConfig { |
| 7 | |||
| 8 | private NetConfig() { | 7 | private NetConfig() { |
| 9 | } | 8 | } |
| 10 | 9 | ||
| @@ -53,5 +52,4 @@ public final class NetConfig { | |||
| 53 | public static void setServerPort(int port) { | 52 | public static void setServerPort(int port) { |
| 54 | cfg.data().section("Server").setInt("Port", port); | 53 | cfg.data().section("Server").setInt("Port", port); |
| 55 | } | 54 | } |
| 56 | |||
| 57 | } | 55 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java index 660d2313..2e84991b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/OldConfigImporter.java | |||
| @@ -5,7 +5,6 @@ import java.awt.Font; | |||
| 5 | import cuchaz.enigma.gui.config.legacy.Config; | 5 | import cuchaz.enigma.gui.config.legacy.Config; |
| 6 | 6 | ||
| 7 | public final class OldConfigImporter { | 7 | public final class OldConfigImporter { |
| 8 | |||
| 9 | private OldConfigImporter() { | 8 | private OldConfigImporter() { |
| 10 | } | 9 | } |
| 11 | 10 | ||
| @@ -13,14 +12,15 @@ public final class OldConfigImporter { | |||
| 13 | public static void doImport() { | 12 | public static void doImport() { |
| 14 | if (Config.CONFIG_FILE.exists()) { | 13 | if (Config.CONFIG_FILE.exists()) { |
| 15 | Config config = new Config(); | 14 | Config config = new Config(); |
| 15 | |||
| 16 | if (config.editorFont != null) { | 16 | if (config.editorFont != null) { |
| 17 | UiConfig.setEditorFont(Font.decode(config.editorFont)); | 17 | UiConfig.setEditorFont(Font.decode(config.editorFont)); |
| 18 | } | 18 | } |
| 19 | |||
| 19 | UiConfig.setLanguage(config.language); | 20 | UiConfig.setLanguage(config.language); |
| 20 | UiConfig.setLookAndFeel(config.lookAndFeel); | 21 | UiConfig.setLookAndFeel(config.lookAndFeel); |
| 21 | UiConfig.setScaleFactor(config.scaleFactor); | 22 | UiConfig.setScaleFactor(config.scaleFactor); |
| 22 | UiConfig.setDecompiler(config.decompiler); | 23 | UiConfig.setDecompiler(config.decompiler); |
| 23 | } | 24 | } |
| 24 | } | 25 | } |
| 25 | |||
| 26 | } | 26 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java index 839a5cbc..e2db9682 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/Themes.java | |||
| @@ -16,7 +16,6 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 16 | import cuchaz.enigma.source.RenamableTokenType; | 16 | import cuchaz.enigma.source.RenamableTokenType; |
| 17 | 17 | ||
| 18 | public class Themes { | 18 | public class Themes { |
| 19 | |||
| 20 | private static final Set<ThemeChangeListener> listeners = new HashSet<>(); | 19 | private static final Set<ThemeChangeListener> listeners = new HashSet<>(); |
| 21 | 20 | ||
| 22 | // Calling this after the UI is initialized (e.g. when the user changes | 21 | // Calling this after the UI is initialized (e.g. when the user changes |
| @@ -87,11 +86,8 @@ public class Themes { | |||
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | public static ImmutableMap<RenamableTokenType, BoxHighlightPainter> getBoxHighlightPainters() { | 88 | public static ImmutableMap<RenamableTokenType, BoxHighlightPainter> getBoxHighlightPainters() { |
| 90 | return ImmutableMap.of( | 89 | return ImmutableMap.of(RenamableTokenType.OBFUSCATED, BoxHighlightPainter.create(UiConfig.getObfuscatedColor(), UiConfig.getObfuscatedOutlineColor()), RenamableTokenType.PROPOSED, BoxHighlightPainter.create(UiConfig.getProposedColor(), UiConfig.getProposedOutlineColor()), |
| 91 | RenamableTokenType.OBFUSCATED, BoxHighlightPainter.create(UiConfig.getObfuscatedColor(), UiConfig.getObfuscatedOutlineColor()), | 90 | RenamableTokenType.DEOBFUSCATED, BoxHighlightPainter.create(UiConfig.getDeobfuscatedColor(), UiConfig.getDeobfuscatedOutlineColor())); |
| 92 | RenamableTokenType.PROPOSED, BoxHighlightPainter.create(UiConfig.getProposedColor(), UiConfig.getProposedOutlineColor()), | ||
| 93 | RenamableTokenType.DEOBFUSCATED, BoxHighlightPainter.create(UiConfig.getDeobfuscatedColor(), UiConfig.getDeobfuscatedOutlineColor()) | ||
| 94 | ); | ||
| 95 | } | 91 | } |
| 96 | 92 | ||
| 97 | public static void addListener(ThemeChangeListener listener) { | 93 | public static void addListener(ThemeChangeListener listener) { |
| @@ -101,5 +97,4 @@ public class Themes { | |||
| 101 | public static void removeListener(ThemeChangeListener listener) { | 97 | public static void removeListener(ThemeChangeListener listener) { |
| 102 | listeners.remove(listener); | 98 | listeners.remove(listener); |
| 103 | } | 99 | } |
| 104 | |||
| 105 | } | 100 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java index 8a10acec..cdf27cac 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | package cuchaz.enigma.gui.config; | 1 | package cuchaz.enigma.gui.config; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.Color; |
| 4 | import java.awt.Dimension; | ||
| 5 | import java.awt.Font; | ||
| 6 | import java.awt.Point; | ||
| 7 | import java.awt.Toolkit; | ||
| 4 | import java.util.Optional; | 8 | import java.util.Optional; |
| 5 | import java.util.OptionalInt; | 9 | import java.util.OptionalInt; |
| 6 | 10 | ||
| @@ -10,7 +14,6 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 10 | import cuchaz.enigma.utils.I18n; | 14 | import cuchaz.enigma.utils.I18n; |
| 11 | 15 | ||
| 12 | public final class UiConfig { | 16 | public final class UiConfig { |
| 13 | |||
| 14 | private UiConfig() { | 17 | private UiConfig() { |
| 15 | } | 18 | } |
| 16 | 19 | ||
| @@ -82,11 +85,11 @@ public final class UiConfig { | |||
| 82 | * @return an integer array composed of these 4 dimensions | 85 | * @return an integer array composed of these 4 dimensions |
| 83 | */ | 86 | */ |
| 84 | public static int[] getLayout() { | 87 | public static int[] getLayout() { |
| 85 | return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[] { -1, -1, -1, -1 }); | 88 | return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[]{-1, -1, -1, -1}); |
| 86 | } | 89 | } |
| 87 | 90 | ||
| 88 | public static void setLayout(int leftV, int left, int right, int rightH) { | 91 | public static void setLayout(int leftV, int left, int right, int rightH) { |
| 89 | swing.data().section("Main Window").setIntArray("Layout", new int[] { leftV, left, right, rightH }); | 92 | swing.data().section("Main Window").setIntArray("Layout", new int[]{leftV, left, right, rightH}); |
| 90 | } | 93 | } |
| 91 | 94 | ||
| 92 | public static LookAndFeel getLookAndFeel() { | 95 | public static LookAndFeel getLookAndFeel() { |
| @@ -287,6 +290,7 @@ public final class UiConfig { | |||
| 287 | ConfigSection section = swing.data().section(window); | 290 | ConfigSection section = swing.data().section(window); |
| 288 | OptionalInt width = section.getInt(String.format("Width %s", screenSize.width)); | 291 | OptionalInt width = section.getInt(String.format("Width %s", screenSize.width)); |
| 289 | OptionalInt height = section.getInt(String.format("Height %s", screenSize.height)); | 292 | OptionalInt height = section.getInt(String.format("Height %s", screenSize.height)); |
| 293 | |||
| 290 | if (width.isPresent() && height.isPresent()) { | 294 | if (width.isPresent() && height.isPresent()) { |
| 291 | return new Dimension(width.getAsInt(), height.getAsInt()); | 295 | return new Dimension(width.getAsInt(), height.getAsInt()); |
| 292 | } else { | 296 | } else { |
| @@ -306,6 +310,7 @@ public final class UiConfig { | |||
| 306 | ConfigSection section = swing.data().section(window); | 310 | ConfigSection section = swing.data().section(window); |
| 307 | OptionalInt x = section.getInt(String.format("X %s", screenSize.width)); | 311 | OptionalInt x = section.getInt(String.format("X %s", screenSize.width)); |
| 308 | OptionalInt y = section.getInt(String.format("Y %s", screenSize.height)); | 312 | OptionalInt y = section.getInt(String.format("Y %s", screenSize.height)); |
| 313 | |||
| 309 | if (x.isPresent() && y.isPresent()) { | 314 | if (x.isPresent() && y.isPresent()) { |
| 310 | int ix = x.getAsInt(); | 315 | int ix = x.getAsInt(); |
| 311 | int iy = y.getAsInt(); | 316 | int iy = y.getAsInt(); |
| @@ -354,6 +359,7 @@ public final class UiConfig { | |||
| 354 | 359 | ||
| 355 | public static void setLookAndFeelDefaults(LookAndFeel laf, boolean isDark) { | 360 | public static void setLookAndFeelDefaults(LookAndFeel laf, boolean isDark) { |
| 356 | ConfigSection s = swing.data().section("Themes").section(laf.name()).section("Colors"); | 361 | ConfigSection s = swing.data().section("Themes").section(laf.name()).section("Colors"); |
| 362 | |||
| 357 | if (!isDark) { | 363 | if (!isDark) { |
| 358 | // Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139 | 364 | // Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139 |
| 359 | s.setIfAbsentRgbColor("Line Numbers Foreground", 0x333300); | 365 | s.setIfAbsentRgbColor("Line Numbers Foreground", 0x333300); |
| @@ -412,5 +418,4 @@ public final class UiConfig { | |||
| 412 | s.setIfAbsentRgbColor("Text", 0xF8F8F2); | 418 | s.setIfAbsentRgbColor("Text", 0xF8F8F2); |
| 413 | } | 419 | } |
| 414 | } | 420 | } |
| 415 | |||
| 416 | } | 421 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java index 1265750f..0e8f7da2 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/legacy/Config.java | |||
| @@ -6,7 +6,15 @@ import java.lang.reflect.Type; | |||
| 6 | import java.nio.charset.Charset; | 6 | import java.nio.charset.Charset; |
| 7 | 7 | ||
| 8 | import com.google.common.io.Files; | 8 | import com.google.common.io.Files; |
| 9 | import com.google.gson.*; | 9 | import com.google.gson.Gson; |
| 10 | import com.google.gson.GsonBuilder; | ||
| 11 | import com.google.gson.InstanceCreator; | ||
| 12 | import com.google.gson.JsonDeserializationContext; | ||
| 13 | import com.google.gson.JsonDeserializer; | ||
| 14 | import com.google.gson.JsonElement; | ||
| 15 | import com.google.gson.JsonPrimitive; | ||
| 16 | import com.google.gson.JsonSerializationContext; | ||
| 17 | import com.google.gson.JsonSerializer; | ||
| 10 | 18 | ||
| 11 | import cuchaz.enigma.gui.config.Decompiler; | 19 | import cuchaz.enigma.gui.config.Decompiler; |
| 12 | import cuchaz.enigma.utils.I18n; | 20 | import cuchaz.enigma.utils.I18n; |
| @@ -28,7 +36,7 @@ public class Config { | |||
| 28 | } | 36 | } |
| 29 | 37 | ||
| 30 | Color baseColor = new Color(rgb); | 38 | Color baseColor = new Color(rgb); |
| 31 | return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int)(255 * alpha)); | 39 | return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int) (255 * alpha)); |
| 32 | } | 40 | } |
| 33 | } | 41 | } |
| 34 | 42 | ||
| @@ -73,12 +81,7 @@ public class Config { | |||
| 73 | public Decompiler decompiler = Decompiler.CFR; | 81 | public Decompiler decompiler = Decompiler.CFR; |
| 74 | 82 | ||
| 75 | public Config() { | 83 | public Config() { |
| 76 | gson = new GsonBuilder() | 84 | gson = new GsonBuilder().registerTypeAdapter(Integer.class, new IntSerializer()).registerTypeAdapter(Integer.class, new IntDeserializer()).registerTypeAdapter(Config.class, (InstanceCreator<Config>) type -> this).setPrettyPrinting().create(); |
| 77 | .registerTypeAdapter(Integer.class, new IntSerializer()) | ||
| 78 | .registerTypeAdapter(Integer.class, new IntDeserializer()) | ||
| 79 | .registerTypeAdapter(Config.class, (InstanceCreator<Config>) type -> this) | ||
| 80 | .setPrettyPrinting() | ||
| 81 | .create(); | ||
| 82 | this.loadConfig(); | 85 | this.loadConfig(); |
| 83 | } | 86 | } |
| 84 | 87 | ||
| @@ -105,5 +108,4 @@ public class Config { | |||
| 105 | return (int) Long.parseLong(json.getAsString().replace("#", ""), 16); | 108 | return (int) Long.parseLong(json.getAsString().replace("#", ""), 16); |
| 106 | } | 109 | } |
| 107 | } | 110 | } |
| 108 | |||
| 109 | } | 111 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java index f8922e64..c2211209 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.dialog; | 12 | package cuchaz.enigma.gui.dialog; |
| 13 | 13 | ||
| @@ -15,7 +15,11 @@ import java.awt.Container; | |||
| 15 | import java.awt.GridBagConstraints; | 15 | import java.awt.GridBagConstraints; |
| 16 | import java.awt.GridBagLayout; | 16 | import java.awt.GridBagLayout; |
| 17 | 17 | ||
| 18 | import javax.swing.*; | 18 | import javax.swing.JButton; |
| 19 | import javax.swing.JDialog; | ||
| 20 | import javax.swing.JFrame; | ||
| 21 | import javax.swing.JLabel; | ||
| 22 | import javax.swing.WindowConstants; | ||
| 19 | 23 | ||
| 20 | import cuchaz.enigma.Enigma; | 24 | import cuchaz.enigma.Enigma; |
| 21 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; | 25 | import cuchaz.enigma.gui.util.GridBagConstraintsBuilder; |
| @@ -23,16 +27,12 @@ import cuchaz.enigma.gui.util.GuiUtil; | |||
| 23 | import cuchaz.enigma.utils.I18n; | 27 | import cuchaz.enigma.utils.I18n; |
| 24 | 28 | ||
| 25 | public class AboutDialog { | 29 | public class AboutDialog { |
| 26 | |||
| 27 | public static void show(JFrame parent) { | 30 | public static void show(JFrame parent) { |
| 28 | JDialog frame = new JDialog(parent, String.format(I18n.translate("menu.help.about.title"), Enigma.NAME), true); | 31 | JDialog frame = new JDialog(parent, String.format(I18n.translate("menu.help.about.title"), Enigma.NAME), true); |
| 29 | Container pane = frame.getContentPane(); | 32 | Container pane = frame.getContentPane(); |
| 30 | pane.setLayout(new GridBagLayout()); | 33 | pane.setLayout(new GridBagLayout()); |
| 31 | 34 | ||
| 32 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() | 35 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST); |
| 33 | .insets(2) | ||
| 34 | .weight(1.0, 0.0) | ||
| 35 | .anchor(GridBagConstraints.WEST); | ||
| 36 | 36 | ||
| 37 | JLabel title = new JLabel(Enigma.NAME); | 37 | JLabel title = new JLabel(Enigma.NAME); |
| 38 | title.setFont(title.getFont().deriveFont(title.getFont().getSize2D() * 1.5f)); | 38 | title.setFont(title.getFont().deriveFont(title.getFont().getSize2D() * 1.5f)); |
| @@ -52,5 +52,4 @@ public class AboutDialog { | |||
| 52 | frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); | 52 | frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); |
| 53 | frame.setVisible(true); | 53 | frame.setVisible(true); |
| 54 | } | 54 | } |
| 55 | |||
| 56 | } | 55 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java index c9ca8090..76232c44 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java | |||
| @@ -1,6 +1,12 @@ | |||
| 1 | package cuchaz.enigma.gui.dialog; | 1 | package cuchaz.enigma.gui.dialog; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.BorderLayout; |
| 4 | import java.awt.Component; | ||
| 5 | import java.awt.Container; | ||
| 6 | import java.awt.FlowLayout; | ||
| 7 | import java.awt.Frame; | ||
| 8 | import java.awt.GridBagConstraints; | ||
| 9 | import java.awt.GridBagLayout; | ||
| 4 | import java.util.List; | 10 | import java.util.List; |
| 5 | 11 | ||
| 6 | import javax.swing.JButton; | 12 | import javax.swing.JButton; |
| @@ -15,7 +21,6 @@ import cuchaz.enigma.utils.Pair; | |||
| 15 | import cuchaz.enigma.utils.validation.ValidationContext; | 21 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 16 | 22 | ||
| 17 | public abstract class AbstractDialog extends JDialog { | 23 | public abstract class AbstractDialog extends JDialog { |
| 18 | |||
| 19 | protected final ValidationContext vc = new ValidationContext(); | 24 | protected final ValidationContext vc = new ValidationContext(); |
| 20 | 25 | ||
| 21 | private boolean actionConfirm = false; | 26 | private boolean actionConfirm = false; |
| @@ -38,6 +43,7 @@ public abstract class AbstractDialog extends JDialog { | |||
| 38 | inputContainer.add(label, cb.pos(0, i).weightX(0.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.NONE).build()); | 43 | inputContainer.add(label, cb.pos(0, i).weightX(0.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.NONE).build()); |
| 39 | inputContainer.add(component, cb.pos(1, i).weightX(1.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.HORIZONTAL).build()); | 44 | inputContainer.add(component, cb.pos(1, i).weightX(1.0).anchor(GridBagConstraints.LINE_END).fill(GridBagConstraints.HORIZONTAL).build()); |
| 40 | } | 45 | } |
| 46 | |||
| 41 | contentPane.add(inputContainer, BorderLayout.CENTER); | 47 | contentPane.add(inputContainer, BorderLayout.CENTER); |
| 42 | Container buttonContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT, ScaleUtil.scale(4), ScaleUtil.scale(4))); | 48 | Container buttonContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT, ScaleUtil.scale(4), ScaleUtil.scale(4))); |
| 43 | JButton connectButton = new JButton(I18n.translate(confirmAction)); | 49 | JButton connectButton = new JButton(I18n.translate(confirmAction)); |
| @@ -57,6 +63,7 @@ public abstract class AbstractDialog extends JDialog { | |||
| 57 | protected void confirm() { | 63 | protected void confirm() { |
| 58 | vc.reset(); | 64 | vc.reset(); |
| 59 | validateInputs(); | 65 | validateInputs(); |
| 66 | |||
| 60 | if (vc.canProceed()) { | 67 | if (vc.canProceed()) { |
| 61 | actionConfirm = true; | 68 | actionConfirm = true; |
| 62 | setVisible(false); | 69 | setVisible(false); |
| @@ -74,5 +81,4 @@ public abstract class AbstractDialog extends JDialog { | |||
| 74 | 81 | ||
| 75 | public void validateInputs() { | 82 | public void validateInputs() { |
| 76 | } | 83 | } |
| 77 | |||
| 78 | } | 84 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java index df65473c..51948b56 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ChangeDialog.java | |||
| @@ -14,7 +14,6 @@ import javax.swing.JPanel; | |||
| 14 | import cuchaz.enigma.utils.I18n; | 14 | import cuchaz.enigma.utils.I18n; |
| 15 | 15 | ||
| 16 | public class ChangeDialog { | 16 | public class ChangeDialog { |
| 17 | |||
| 18 | public static void show(Window parent) { | 17 | public static void show(Window parent) { |
| 19 | // init frame | 18 | // init frame |
| 20 | JDialog frame = new JDialog(parent, I18n.translate("menu.view.change.title"), Dialog.DEFAULT_MODALITY_TYPE); | 19 | JDialog frame = new JDialog(parent, I18n.translate("menu.view.change.title"), Dialog.DEFAULT_MODALITY_TYPE); |
| @@ -48,5 +47,4 @@ public class ChangeDialog { | |||
| 48 | frame.setLocationRelativeTo(parent); | 47 | frame.setLocationRelativeTo(parent); |
| 49 | frame.setVisible(true); | 48 | frame.setVisible(true); |
| 50 | } | 49 | } |
| 51 | |||
| 52 | } | 50 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java index 2486dfe1..1c2bd4c1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java | |||
| @@ -20,7 +20,6 @@ import cuchaz.enigma.utils.validation.Message; | |||
| 20 | import cuchaz.enigma.utils.validation.StandardValidation; | 20 | import cuchaz.enigma.utils.validation.StandardValidation; |
| 21 | 21 | ||
| 22 | public class ConnectToServerDialog extends AbstractDialog { | 22 | public class ConnectToServerDialog extends AbstractDialog { |
| 23 | |||
| 24 | private JTextField usernameField; | 23 | private JTextField usernameField; |
| 25 | private ValidatableTextField ipField; | 24 | private ValidatableTextField ipField; |
| 26 | private JPasswordField passwordField; | 25 | private JPasswordField passwordField; |
| @@ -45,16 +44,13 @@ public class ConnectToServerDialog extends AbstractDialog { | |||
| 45 | ipField.addActionListener(event -> confirm()); | 44 | ipField.addActionListener(event -> confirm()); |
| 46 | passwordField.addActionListener(event -> confirm()); | 45 | passwordField.addActionListener(event -> confirm()); |
| 47 | 46 | ||
| 48 | return Arrays.asList( | 47 | return Arrays.asList(new Pair<>("prompt.connect.username", usernameField), new Pair<>("prompt.connect.address", ipField), new Pair<>("prompt.password", passwordField)); |
| 49 | new Pair<>("prompt.connect.username", usernameField), | ||
| 50 | new Pair<>("prompt.connect.address", ipField), | ||
| 51 | new Pair<>("prompt.password", passwordField) | ||
| 52 | ); | ||
| 53 | } | 48 | } |
| 54 | 49 | ||
| 55 | @Override | 50 | @Override |
| 56 | public void validateInputs() { | 51 | public void validateInputs() { |
| 57 | vc.setActiveElement(ipField); | 52 | vc.setActiveElement(ipField); |
| 53 | |||
| 58 | if (StandardValidation.notBlank(vc, ipField.getText())) { | 54 | if (StandardValidation.notBlank(vc, ipField.getText())) { |
| 59 | if (ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT) == null) { | 55 | if (ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT) == null) { |
| 60 | vc.raise(Message.INVALID_IP); | 56 | vc.raise(Message.INVALID_IP); |
| @@ -63,16 +59,18 @@ public class ConnectToServerDialog extends AbstractDialog { | |||
| 63 | } | 59 | } |
| 64 | 60 | ||
| 65 | public Result getResult() { | 61 | public Result getResult() { |
| 66 | if (!isActionConfirm()) return null; | 62 | if (!isActionConfirm()) { |
| 63 | return null; | ||
| 64 | } | ||
| 65 | |||
| 67 | vc.reset(); | 66 | vc.reset(); |
| 68 | validateInputs(); | 67 | validateInputs(); |
| 69 | if (!vc.canProceed()) return null; | 68 | |
| 70 | return new Result( | 69 | if (!vc.canProceed()) { |
| 71 | usernameField.getText(), | 70 | return null; |
| 72 | ipField.getText(), | 71 | } |
| 73 | Objects.requireNonNull(ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT)), | 72 | |
| 74 | passwordField.getPassword() | 73 | return new Result(usernameField.getText(), ipField.getText(), Objects.requireNonNull(ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT)), passwordField.getPassword()); |
| 75 | ); | ||
| 76 | } | 74 | } |
| 77 | 75 | ||
| 78 | public static Result show(Frame parent) { | 76 | public static Result show(Frame parent) { |
| @@ -114,5 +112,4 @@ public class ConnectToServerDialog extends AbstractDialog { | |||
| 114 | return password; | 112 | return password; |
| 115 | } | 113 | } |
| 116 | } | 114 | } |
| 117 | |||
| 118 | } | 115 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java index c2a93fa5..a84e9775 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java | |||
| @@ -1,31 +1,42 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.dialog; | 12 | package cuchaz.enigma.gui.dialog; |
| 13 | 13 | ||
| 14 | import java.awt.BorderLayout; | ||
| 15 | import java.awt.Container; | ||
| 16 | import java.io.File; | ||
| 17 | import java.io.FileWriter; | ||
| 18 | import java.io.IOException; | ||
| 19 | import java.io.PrintWriter; | ||
| 20 | import java.io.StringWriter; | ||
| 21 | |||
| 22 | import javax.swing.BorderFactory; | ||
| 23 | import javax.swing.Box; | ||
| 24 | import javax.swing.BoxLayout; | ||
| 25 | import javax.swing.JButton; | ||
| 26 | import javax.swing.JFileChooser; | ||
| 27 | import javax.swing.JFrame; | ||
| 28 | import javax.swing.JLabel; | ||
| 29 | import javax.swing.JPanel; | ||
| 30 | import javax.swing.JScrollPane; | ||
| 31 | import javax.swing.JTextArea; | ||
| 32 | import javax.swing.WindowConstants; | ||
| 33 | |||
| 14 | import cuchaz.enigma.Enigma; | 34 | import cuchaz.enigma.Enigma; |
| 15 | import cuchaz.enigma.gui.util.GuiUtil; | 35 | import cuchaz.enigma.gui.util.GuiUtil; |
| 16 | import cuchaz.enigma.utils.I18n; | ||
| 17 | import cuchaz.enigma.gui.util.ScaleUtil; | 36 | import cuchaz.enigma.gui.util.ScaleUtil; |
| 18 | 37 | import cuchaz.enigma.utils.I18n; | |
| 19 | import javax.swing.*; | ||
| 20 | import java.awt.*; | ||
| 21 | import java.io.PrintWriter; | ||
| 22 | import java.io.StringWriter; | ||
| 23 | import java.io.FileWriter; | ||
| 24 | import java.io.File; | ||
| 25 | import java.io.IOException; | ||
| 26 | 38 | ||
| 27 | public class CrashDialog { | 39 | public class CrashDialog { |
| 28 | |||
| 29 | private static CrashDialog instance = null; | 40 | private static CrashDialog instance = null; |
| 30 | 41 | ||
| 31 | private JFrame frame; | 42 | private JFrame frame; |
| @@ -53,6 +64,7 @@ public class CrashDialog { | |||
| 53 | exportButton.addActionListener(event -> { | 64 | exportButton.addActionListener(event -> { |
| 54 | JFileChooser chooser = new JFileChooser(); | 65 | JFileChooser chooser = new JFileChooser(); |
| 55 | chooser.setSelectedFile(new File("enigma_crash.log")); | 66 | chooser.setSelectedFile(new File("enigma_crash.log")); |
| 67 | |||
| 56 | if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { | 68 | if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { |
| 57 | try { | 69 | try { |
| 58 | File file = chooser.getSelectedFile(); | 70 | File file = chooser.getSelectedFile(); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java index 07daf6dc..35999e28 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java | |||
| @@ -16,7 +16,6 @@ import cuchaz.enigma.utils.validation.Message; | |||
| 16 | import cuchaz.enigma.utils.validation.StandardValidation; | 16 | import cuchaz.enigma.utils.validation.StandardValidation; |
| 17 | 17 | ||
| 18 | public class CreateServerDialog extends AbstractDialog { | 18 | public class CreateServerDialog extends AbstractDialog { |
| 19 | |||
| 20 | private ValidatableTextField portField; | 19 | private ValidatableTextField portField; |
| 21 | private ValidatablePasswordField passwordField; | 20 | private ValidatablePasswordField passwordField; |
| 22 | 21 | ||
| @@ -38,10 +37,7 @@ public class CreateServerDialog extends AbstractDialog { | |||
| 38 | portField.addActionListener(event -> confirm()); | 37 | portField.addActionListener(event -> confirm()); |
| 39 | passwordField.addActionListener(event -> confirm()); | 38 | passwordField.addActionListener(event -> confirm()); |
| 40 | 39 | ||
| 41 | return Arrays.asList( | 40 | return Arrays.asList(new Pair<>("prompt.create_server.port", portField), new Pair<>("prompt.password", passwordField)); |
| 42 | new Pair<>("prompt.create_server.port", portField), | ||
| 43 | new Pair<>("prompt.password", passwordField) | ||
| 44 | ); | ||
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | @Override | 43 | @Override |
| @@ -49,20 +45,25 @@ public class CreateServerDialog extends AbstractDialog { | |||
| 49 | vc.setActiveElement(portField); | 45 | vc.setActiveElement(portField); |
| 50 | StandardValidation.isIntInRange(vc, portField.getText(), 0, 65535); | 46 | StandardValidation.isIntInRange(vc, portField.getText(), 0, 65535); |
| 51 | vc.setActiveElement(passwordField); | 47 | vc.setActiveElement(passwordField); |
| 48 | |||
| 52 | if (passwordField.getPassword().length > EnigmaServer.MAX_PASSWORD_LENGTH) { | 49 | if (passwordField.getPassword().length > EnigmaServer.MAX_PASSWORD_LENGTH) { |
| 53 | vc.raise(Message.FIELD_LENGTH_OUT_OF_RANGE, EnigmaServer.MAX_PASSWORD_LENGTH); | 50 | vc.raise(Message.FIELD_LENGTH_OUT_OF_RANGE, EnigmaServer.MAX_PASSWORD_LENGTH); |
| 54 | } | 51 | } |
| 55 | } | 52 | } |
| 56 | 53 | ||
| 57 | public Result getResult() { | 54 | public Result getResult() { |
| 58 | if (!isActionConfirm()) return null; | 55 | if (!isActionConfirm()) { |
| 56 | return null; | ||
| 57 | } | ||
| 58 | |||
| 59 | vc.reset(); | 59 | vc.reset(); |
| 60 | validateInputs(); | 60 | validateInputs(); |
| 61 | if (!vc.canProceed()) return null; | 61 | |
| 62 | return new Result( | 62 | if (!vc.canProceed()) { |
| 63 | Integer.parseInt(portField.getText()), | 63 | return null; |
| 64 | passwordField.getPassword() | 64 | } |
| 65 | ); | 65 | |
| 66 | return new Result(Integer.parseInt(portField.getText()), passwordField.getPassword()); | ||
| 66 | } | 67 | } |
| 67 | 68 | ||
| 68 | public static Result show(Frame parent) { | 69 | public static Result show(Frame parent) { |
| @@ -92,5 +93,4 @@ public class CreateServerDialog extends AbstractDialog { | |||
| 92 | return password; | 93 | return password; |
| 93 | } | 94 | } |
| 94 | } | 95 | } |
| 95 | |||
| 96 | } | 96 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java index 4e02a666..f0bae17b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/FontDialog.java | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | package cuchaz.enigma.gui.dialog; | 1 | package cuchaz.enigma.gui.dialog; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.Component; |
| 4 | import java.awt.Container; | ||
| 5 | import java.awt.Font; | ||
| 6 | import java.awt.Frame; | ||
| 7 | import java.awt.GridBagConstraints; | ||
| 8 | import java.awt.GridBagLayout; | ||
| 4 | import java.util.List; | 9 | import java.util.List; |
| 5 | 10 | ||
| 6 | import javax.swing.JButton; | 11 | import javax.swing.JButton; |
| @@ -16,20 +21,9 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 16 | import cuchaz.enigma.utils.I18n; | 21 | import cuchaz.enigma.utils.I18n; |
| 17 | 22 | ||
| 18 | public class FontDialog extends JDialog { | 23 | public class FontDialog extends JDialog { |
| 24 | private static final List<String> CATEGORIES = List.of("Default", "Default 2", "Small", "Editor"); | ||
| 19 | 25 | ||
| 20 | private static final List<String> CATEGORIES = List.of( | 26 | private static final List<String> CATEGORY_TEXTS = List.of("fonts.cat.default", "fonts.cat.default2", "fonts.cat.small", "fonts.cat.editor"); |
| 21 | "Default", | ||
| 22 | "Default 2", | ||
| 23 | "Small", | ||
| 24 | "Editor" | ||
| 25 | ); | ||
| 26 | |||
| 27 | private static final List<String> CATEGORY_TEXTS = List.of( | ||
| 28 | "fonts.cat.default", | ||
| 29 | "fonts.cat.default2", | ||
| 30 | "fonts.cat.small", | ||
| 31 | "fonts.cat.editor" | ||
| 32 | ); | ||
| 33 | 27 | ||
| 34 | private final JList<String> entries = new JList<>(CATEGORY_TEXTS.stream().map(I18n::translate).toArray(String[]::new)); | 28 | private final JList<String> entries = new JList<>(CATEGORY_TEXTS.stream().map(I18n::translate).toArray(String[]::new)); |
| 35 | private final FontChooser chooser = new FontChooser(Font.decode(Font.DIALOG)); | 29 | private final FontChooser chooser = new FontChooser(Font.decode(Font.DIALOG)); |
| @@ -55,8 +49,7 @@ public class FontDialog extends JDialog { | |||
| 55 | Container contentPane = this.getContentPane(); | 49 | Container contentPane = this.getContentPane(); |
| 56 | contentPane.setLayout(new GridBagLayout()); | 50 | contentPane.setLayout(new GridBagLayout()); |
| 57 | 51 | ||
| 58 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() | 52 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2); |
| 59 | .insets(2); | ||
| 60 | 53 | ||
| 61 | contentPane.add(this.entries, cb.pos(0, 0).weight(0.0, 1.0).fill(GridBagConstraints.BOTH).build()); | 54 | contentPane.add(this.entries, cb.pos(0, 0).weight(0.0, 1.0).fill(GridBagConstraints.BOTH).build()); |
| 62 | contentPane.add(this.chooser, cb.pos(1, 0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).size(2, 1).build()); | 55 | contentPane.add(this.chooser, cb.pos(1, 0).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).size(2, 1).build()); |
| @@ -77,6 +70,7 @@ public class FontDialog extends JDialog { | |||
| 77 | private void categoryChanged() { | 70 | private void categoryChanged() { |
| 78 | this.updateUiState(); | 71 | this.updateUiState(); |
| 79 | int selectedIndex = this.entries.getSelectedIndex(); | 72 | int selectedIndex = this.entries.getSelectedIndex(); |
| 73 | |||
| 80 | if (selectedIndex != -1) { | 74 | if (selectedIndex != -1) { |
| 81 | this.chooser.setSelectedFont(this.fonts[selectedIndex]); | 75 | this.chooser.setSelectedFont(this.fonts[selectedIndex]); |
| 82 | } | 76 | } |
| @@ -84,6 +78,7 @@ public class FontDialog extends JDialog { | |||
| 84 | 78 | ||
| 85 | private void selectedFontChanged() { | 79 | private void selectedFontChanged() { |
| 86 | int selectedIndex = this.entries.getSelectedIndex(); | 80 | int selectedIndex = this.entries.getSelectedIndex(); |
| 81 | |||
| 87 | if (selectedIndex != -1) { | 82 | if (selectedIndex != -1) { |
| 88 | this.fonts[selectedIndex] = this.chooser.getSelectedFont(); | 83 | this.fonts[selectedIndex] = this.chooser.getSelectedFont(); |
| 89 | } | 84 | } |
| @@ -98,6 +93,7 @@ public class FontDialog extends JDialog { | |||
| 98 | for (int i = 0; i < CATEGORIES.size(); i++) { | 93 | for (int i = 0; i < CATEGORIES.size(); i++) { |
| 99 | UiConfig.setFont(CATEGORIES.get(i), this.fonts[i]); | 94 | UiConfig.setFont(CATEGORIES.get(i), this.fonts[i]); |
| 100 | } | 95 | } |
| 96 | |||
| 101 | UiConfig.setUseCustomFonts(this.customCheckBox.isSelected()); | 97 | UiConfig.setUseCustomFonts(this.customCheckBox.isSelected()); |
| 102 | UiConfig.save(); | 98 | UiConfig.save(); |
| 103 | ChangeDialog.show(this); | 99 | ChangeDialog.show(this); |
| @@ -118,8 +114,8 @@ public class FontDialog extends JDialog { | |||
| 118 | for (Component component : ((Container) self).getComponents()) { | 114 | for (Component component : ((Container) self).getComponents()) { |
| 119 | recursiveSetEnabled(component, enabled); | 115 | recursiveSetEnabled(component, enabled); |
| 120 | } | 116 | } |
| 117 | |||
| 121 | self.setEnabled(enabled); | 118 | self.setEnabled(enabled); |
| 122 | } | 119 | } |
| 123 | } | 120 | } |
| 124 | |||
| 125 | } | 121 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java index 9470e11c..d6e544d0 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/JavadocDialog.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.dialog; | 12 | package cuchaz.enigma.gui.dialog; |
| 13 | 13 | ||
| @@ -18,7 +18,15 @@ import java.awt.FlowLayout; | |||
| 18 | import java.awt.event.KeyAdapter; | 18 | import java.awt.event.KeyAdapter; |
| 19 | import java.awt.event.KeyEvent; | 19 | import java.awt.event.KeyEvent; |
| 20 | 20 | ||
| 21 | import javax.swing.*; | 21 | import javax.swing.JButton; |
| 22 | import javax.swing.JComboBox; | ||
| 23 | import javax.swing.JDialog; | ||
| 24 | import javax.swing.JFrame; | ||
| 25 | import javax.swing.JLabel; | ||
| 26 | import javax.swing.JMenuBar; | ||
| 27 | import javax.swing.JPanel; | ||
| 28 | import javax.swing.JScrollPane; | ||
| 29 | import javax.swing.WindowConstants; | ||
| 22 | import javax.swing.text.html.HTML; | 30 | import javax.swing.text.html.HTML; |
| 23 | 31 | ||
| 24 | import com.google.common.base.Strings; | 32 | import com.google.common.base.Strings; |
| @@ -35,7 +43,6 @@ import cuchaz.enigma.utils.I18n; | |||
| 35 | import cuchaz.enigma.utils.validation.ValidationContext; | 43 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 36 | 44 | ||
| 37 | public class JavadocDialog { | 45 | public class JavadocDialog { |
| 38 | |||
| 39 | private final JDialog ui; | 46 | private final JDialog ui; |
| 40 | private final GuiController controller; | 47 | private final GuiController controller; |
| 41 | private final Entry<?> entry; | 48 | private final Entry<?> entry; |
| @@ -62,19 +69,21 @@ public class JavadocDialog { | |||
| 62 | @Override | 69 | @Override |
| 63 | public void keyPressed(KeyEvent event) { | 70 | public void keyPressed(KeyEvent event) { |
| 64 | switch (event.getKeyCode()) { | 71 | switch (event.getKeyCode()) { |
| 65 | case KeyEvent.VK_ENTER: | 72 | case KeyEvent.VK_ENTER: |
| 66 | if (event.isControlDown()) { | 73 | if (event.isControlDown()) { |
| 67 | doSave(); | 74 | doSave(); |
| 68 | if (vc.canProceed()) { | 75 | |
| 69 | close(); | 76 | if (vc.canProceed()) { |
| 70 | } | 77 | close(); |
| 71 | } | 78 | } |
| 72 | break; | 79 | } |
| 73 | case KeyEvent.VK_ESCAPE: | 80 | |
| 74 | close(); | 81 | break; |
| 75 | break; | 82 | case KeyEvent.VK_ESCAPE: |
| 76 | default: | 83 | close(); |
| 77 | break; | 84 | break; |
| 85 | default: | ||
| 86 | break; | ||
| 78 | } | 87 | } |
| 79 | } | 88 | } |
| 80 | }); | 89 | }); |
| @@ -108,6 +117,7 @@ public class JavadocDialog { | |||
| 108 | } else { | 117 | } else { |
| 109 | tagText = tag.getText() + " " + text.getSelectedText(); | 118 | tagText = tag.getText() + " " + text.getSelectedText(); |
| 110 | } | 119 | } |
| 120 | |||
| 111 | text.replaceSelection(tagText); | 121 | text.replaceSelection(tagText); |
| 112 | } else { | 122 | } else { |
| 113 | text.insert(tagText, text.getCaretPosition()); | 123 | text.insert(tagText, text.getCaretPosition()); |
| @@ -116,6 +126,7 @@ public class JavadocDialog { | |||
| 116 | if (tag.isInline()) { | 126 | if (tag.isInline()) { |
| 117 | text.setCaretPosition(text.getCaretPosition() - 1); | 127 | text.setCaretPosition(text.getCaretPosition() - 1); |
| 118 | } | 128 | } |
| 129 | |||
| 119 | text.grabFocus(); | 130 | text.grabFocus(); |
| 120 | }); | 131 | }); |
| 121 | tagsMenu.add(tagButton); | 132 | tagsMenu.add(tagButton); |
| @@ -124,9 +135,11 @@ public class JavadocDialog { | |||
| 124 | // add html tags | 135 | // add html tags |
| 125 | JComboBox<String> htmlList = new JComboBox<String>(); | 136 | JComboBox<String> htmlList = new JComboBox<String>(); |
| 126 | htmlList.setPreferredSize(new Dimension()); | 137 | htmlList.setPreferredSize(new Dimension()); |
| 138 | |||
| 127 | for (HTML.Tag htmlTag : HTML.getAllTags()) { | 139 | for (HTML.Tag htmlTag : HTML.getAllTags()) { |
| 128 | htmlList.addItem(htmlTag.toString()); | 140 | htmlList.addItem(htmlTag.toString()); |
| 129 | } | 141 | } |
| 142 | |||
| 130 | htmlList.addActionListener(action -> { | 143 | htmlList.addActionListener(action -> { |
| 131 | String tagText = "<" + htmlList.getSelectedItem().toString() + ">"; | 144 | String tagText = "<" + htmlList.getSelectedItem().toString() + ">"; |
| 132 | text.insert(tagText, text.getCaretPosition()); | 145 | text.insert(tagText, text.getCaretPosition()); |
| @@ -146,9 +159,17 @@ public class JavadocDialog { | |||
| 146 | public void doSave() { | 159 | public void doSave() { |
| 147 | vc.reset(); | 160 | vc.reset(); |
| 148 | validate(); | 161 | validate(); |
| 149 | if (!vc.canProceed()) return; | 162 | |
| 163 | if (!vc.canProceed()) { | ||
| 164 | return; | ||
| 165 | } | ||
| 166 | |||
| 150 | save(); | 167 | save(); |
| 151 | if (!vc.canProceed()) return; | 168 | |
| 169 | if (!vc.canProceed()) { | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 152 | close(); | 173 | close(); |
| 153 | } | 174 | } |
| 154 | 175 | ||
| @@ -189,7 +210,7 @@ public class JavadocDialog { | |||
| 189 | 210 | ||
| 190 | private boolean inline; | 211 | private boolean inline; |
| 191 | 212 | ||
| 192 | private JavadocTag(boolean inline) { | 213 | JavadocTag(boolean inline) { |
| 193 | this.inline = inline; | 214 | this.inline = inline; |
| 194 | } | 215 | } |
| 195 | 216 | ||
| @@ -201,5 +222,4 @@ public class JavadocDialog { | |||
| 201 | return this.inline; | 222 | return this.inline; |
| 202 | } | 223 | } |
| 203 | } | 224 | } |
| 204 | |||
| 205 | } | 225 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java index d76ddea9..3beae21c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.dialog; | 12 | package cuchaz.enigma.gui.dialog; |
| 13 | 13 | ||
| @@ -17,7 +17,12 @@ import java.awt.GridBagConstraints; | |||
| 17 | import java.awt.GridBagLayout; | 17 | import java.awt.GridBagLayout; |
| 18 | import java.util.concurrent.CompletableFuture; | 18 | import java.util.concurrent.CompletableFuture; |
| 19 | 19 | ||
| 20 | import javax.swing.*; | 20 | import javax.swing.JDialog; |
| 21 | import javax.swing.JFrame; | ||
| 22 | import javax.swing.JLabel; | ||
| 23 | import javax.swing.JProgressBar; | ||
| 24 | import javax.swing.SwingUtilities; | ||
| 25 | import javax.swing.WindowConstants; | ||
| 21 | 26 | ||
| 22 | import cuchaz.enigma.Enigma; | 27 | import cuchaz.enigma.Enigma; |
| 23 | import cuchaz.enigma.ProgressListener; | 28 | import cuchaz.enigma.ProgressListener; |
| @@ -27,7 +32,6 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 27 | import cuchaz.enigma.utils.I18n; | 32 | import cuchaz.enigma.utils.I18n; |
| 28 | 33 | ||
| 29 | public class ProgressDialog implements ProgressListener, AutoCloseable { | 34 | public class ProgressDialog implements ProgressListener, AutoCloseable { |
| 30 | |||
| 31 | private final JDialog dialog; | 35 | private final JDialog dialog; |
| 32 | private final JLabel labelTitle = new JLabel(); | 36 | private final JLabel labelTitle = new JLabel(); |
| 33 | private final JLabel labelText = GuiUtil.unboldLabel(new JLabel()); | 37 | private final JLabel labelText = GuiUtil.unboldLabel(new JLabel()); |
| @@ -39,11 +43,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable { | |||
| 39 | Container pane = this.dialog.getContentPane(); | 43 | Container pane = this.dialog.getContentPane(); |
| 40 | pane.setLayout(new GridBagLayout()); | 44 | pane.setLayout(new GridBagLayout()); |
| 41 | 45 | ||
| 42 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() | 46 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).anchor(GridBagConstraints.WEST).fill(GridBagConstraints.BOTH).weight(1.0, 0.0); |
| 43 | .insets(2) | ||
| 44 | .anchor(GridBagConstraints.WEST) | ||
| 45 | .fill(GridBagConstraints.BOTH) | ||
| 46 | .weight(1.0, 0.0); | ||
| 47 | 47 | ||
| 48 | pane.add(this.labelTitle, cb.pos(0, 0).build()); | 48 | pane.add(this.labelTitle, cb.pos(0, 0).build()); |
| 49 | pane.add(this.labelText, cb.pos(0, 1).build()); | 49 | pane.add(this.labelText, cb.pos(0, 1).build()); |
| @@ -121,6 +121,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable { | |||
| 121 | public void step(int numDone, String message) { | 121 | public void step(int numDone, String message) { |
| 122 | SwingUtilities.invokeLater(() -> { | 122 | SwingUtilities.invokeLater(() -> { |
| 123 | this.labelText.setText(message); | 123 | this.labelText.setText(message); |
| 124 | |||
| 124 | if (numDone != -1) { | 125 | if (numDone != -1) { |
| 125 | this.progress.setValue(numDone); | 126 | this.progress.setValue(numDone); |
| 126 | this.progress.setIndeterminate(false); | 127 | this.progress.setIndeterminate(false); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java index e65b661b..7814dd81 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.dialog; | 12 | package cuchaz.enigma.gui.dialog; |
| 13 | 13 | ||
| @@ -15,17 +15,36 @@ import java.awt.BorderLayout; | |||
| 15 | import java.awt.Color; | 15 | import java.awt.Color; |
| 16 | import java.awt.FlowLayout; | 16 | import java.awt.FlowLayout; |
| 17 | import java.awt.Font; | 17 | import java.awt.Font; |
| 18 | import java.awt.event.*; | 18 | import java.awt.event.ComponentAdapter; |
| 19 | import java.util.*; | 19 | import java.awt.event.ComponentEvent; |
| 20 | import java.awt.event.KeyAdapter; | ||
| 21 | import java.awt.event.KeyEvent; | ||
| 22 | import java.awt.event.MouseAdapter; | ||
| 23 | import java.awt.event.MouseEvent; | ||
| 24 | import java.util.Arrays; | ||
| 25 | import java.util.Collections; | ||
| 26 | import java.util.List; | ||
| 27 | import java.util.Queue; | ||
| 20 | import java.util.concurrent.ConcurrentLinkedQueue; | 28 | import java.util.concurrent.ConcurrentLinkedQueue; |
| 21 | 29 | ||
| 22 | import javax.swing.*; | 30 | import javax.swing.DefaultListModel; |
| 31 | import javax.swing.JButton; | ||
| 32 | import javax.swing.JDialog; | ||
| 33 | import javax.swing.JLabel; | ||
| 34 | import javax.swing.JList; | ||
| 35 | import javax.swing.JPanel; | ||
| 36 | import javax.swing.JScrollPane; | ||
| 37 | import javax.swing.JTextField; | ||
| 38 | import javax.swing.ListSelectionModel; | ||
| 39 | import javax.swing.SwingUtilities; | ||
| 23 | import javax.swing.event.DocumentEvent; | 40 | import javax.swing.event.DocumentEvent; |
| 24 | import javax.swing.event.DocumentListener; | 41 | import javax.swing.event.DocumentListener; |
| 25 | 42 | ||
| 26 | import cuchaz.enigma.analysis.index.EntryIndex; | 43 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 27 | import cuchaz.enigma.gui.Gui; | 44 | import cuchaz.enigma.gui.Gui; |
| 28 | import cuchaz.enigma.gui.GuiController; | 45 | import cuchaz.enigma.gui.GuiController; |
| 46 | import cuchaz.enigma.gui.search.SearchEntry; | ||
| 47 | import cuchaz.enigma.gui.search.SearchUtil; | ||
| 29 | import cuchaz.enigma.gui.util.AbstractListCellRenderer; | 48 | import cuchaz.enigma.gui.util.AbstractListCellRenderer; |
| 30 | import cuchaz.enigma.gui.util.GuiUtil; | 49 | import cuchaz.enigma.gui.util.GuiUtil; |
| 31 | import cuchaz.enigma.gui.util.ScaleUtil; | 50 | import cuchaz.enigma.gui.util.ScaleUtil; |
| @@ -34,11 +53,8 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 34 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 53 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 35 | import cuchaz.enigma.translation.representation.entry.ParentedEntry; | 54 | import cuchaz.enigma.translation.representation.entry.ParentedEntry; |
| 36 | import cuchaz.enigma.utils.I18n; | 55 | import cuchaz.enigma.utils.I18n; |
| 37 | import cuchaz.enigma.gui.search.SearchEntry; | ||
| 38 | import cuchaz.enigma.gui.search.SearchUtil; | ||
| 39 | 56 | ||
| 40 | public class SearchDialog { | 57 | public class SearchDialog { |
| 41 | |||
| 42 | private final JTextField searchField; | 58 | private final JTextField searchField; |
| 43 | private DefaultListModel<SearchEntryImpl> classListModel; | 59 | private DefaultListModel<SearchEntryImpl> classListModel; |
| 44 | private final JList<SearchEntryImpl> classList; | 60 | private final JList<SearchEntryImpl> classList; |
| @@ -60,7 +76,6 @@ public class SearchDialog { | |||
| 60 | 76 | ||
| 61 | searchField = new JTextField(); | 77 | searchField = new JTextField(); |
| 62 | searchField.getDocument().addDocumentListener(new DocumentListener() { | 78 | searchField.getDocument().addDocumentListener(new DocumentListener() { |
| 63 | |||
| 64 | @Override | 79 | @Override |
| 65 | public void insertUpdate(DocumentEvent e) { | 80 | public void insertUpdate(DocumentEvent e) { |
| 66 | updateList(); | 81 | updateList(); |
| @@ -75,7 +90,6 @@ public class SearchDialog { | |||
| 75 | public void changedUpdate(DocumentEvent e) { | 90 | public void changedUpdate(DocumentEvent e) { |
| 76 | updateList(); | 91 | updateList(); |
| 77 | } | 92 | } |
| 78 | |||
| 79 | }); | 93 | }); |
| 80 | searchField.addKeyListener(new KeyAdapter() { | 94 | searchField.addKeyListener(new KeyAdapter() { |
| 81 | @Override | 95 | @Override |
| @@ -143,23 +157,9 @@ public class SearchDialog { | |||
| 143 | final EntryIndex entryIndex = parent.getController().project.getJarIndex().getEntryIndex(); | 157 | final EntryIndex entryIndex = parent.getController().project.getJarIndex().getEntryIndex(); |
| 144 | 158 | ||
| 145 | switch (type) { | 159 | switch (type) { |
| 146 | case CLASS -> entryIndex.getClasses().parallelStream() | 160 | case CLASS -> entryIndex.getClasses().parallelStream().filter(e -> !e.isInnerClass()).map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add); |
| 147 | .filter(e -> !e.isInnerClass()) | 161 | case METHOD -> entryIndex.getMethods().parallelStream().filter(e -> !e.isConstructor() && !entryIndex.getMethodAccess(e).isSynthetic()).map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add); |
| 148 | .map(e -> SearchEntryImpl.from(e, parent.getController())) | 162 | case FIELD -> entryIndex.getFields().parallelStream().map(e -> SearchEntryImpl.from(e, parent.getController())).map(SearchUtil.Entry::from).sequential().forEach(su::add); |
| 149 | .map(SearchUtil.Entry::from) | ||
| 150 | .sequential() | ||
| 151 | .forEach(su::add); | ||
| 152 | case METHOD -> entryIndex.getMethods().parallelStream() | ||
| 153 | .filter(e -> !e.isConstructor() && !entryIndex.getMethodAccess(e).isSynthetic()) | ||
| 154 | .map(e -> SearchEntryImpl.from(e, parent.getController())) | ||
| 155 | .map(SearchUtil.Entry::from) | ||
| 156 | .sequential() | ||
| 157 | .forEach(su::add); | ||
| 158 | case FIELD -> entryIndex.getFields().parallelStream() | ||
| 159 | .map(e -> SearchEntryImpl.from(e, parent.getController())) | ||
| 160 | .map(SearchUtil.Entry::from) | ||
| 161 | .sequential() | ||
| 162 | .forEach(su::add); | ||
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | updateList(); | 165 | updateList(); |
| @@ -172,6 +172,7 @@ public class SearchDialog { | |||
| 172 | 172 | ||
| 173 | private void openSelected() { | 173 | private void openSelected() { |
| 174 | SearchEntryImpl selectedValue = classList.getSelectedValue(); | 174 | SearchEntryImpl selectedValue = classList.getSelectedValue(); |
| 175 | |||
| 175 | if (selectedValue != null) { | 176 | if (selectedValue != null) { |
| 176 | openEntry(selectedValue); | 177 | openEntry(selectedValue); |
| 177 | } | 178 | } |
| @@ -181,6 +182,7 @@ public class SearchDialog { | |||
| 181 | close(); | 182 | close(); |
| 182 | su.hit(e); | 183 | su.hit(e); |
| 183 | parent.getController().navigateTo(e.obf); | 184 | parent.getController().navigateTo(e.obf); |
| 185 | |||
| 184 | if (e.obf instanceof ClassEntry) { | 186 | if (e.obf instanceof ClassEntry) { |
| 185 | if (e.deobf != null) { | 187 | if (e.deobf != null) { |
| 186 | parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf); | 188 | parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf); |
| @@ -202,7 +204,9 @@ public class SearchDialog { | |||
| 202 | 204 | ||
| 203 | // Updates the list of class names | 205 | // Updates the list of class names |
| 204 | private void updateList() { | 206 | private void updateList() { |
| 205 | if (currentSearch != null) currentSearch.stop(); | 207 | if (currentSearch != null) { |
| 208 | currentSearch.stop(); | ||
| 209 | } | ||
| 206 | 210 | ||
| 207 | DefaultListModel<SearchEntryImpl> classListModel = new DefaultListModel<>(); | 211 | DefaultListModel<SearchEntryImpl> classListModel = new DefaultListModel<>(); |
| 208 | this.classListModel = classListModel; | 212 | this.classListModel = classListModel; |
| @@ -210,7 +214,9 @@ public class SearchDialog { | |||
| 210 | 214 | ||
| 211 | // handle these search result like minecraft scheduled tasks to prevent | 215 | // handle these search result like minecraft scheduled tasks to prevent |
| 212 | // flooding swing buttons inputs etc with tons of (possibly outdated) invocations | 216 | // flooding swing buttons inputs etc with tons of (possibly outdated) invocations |
| 213 | record Order(int idx, SearchEntryImpl e) {} | 217 | record Order(int idx, SearchEntryImpl e) { |
| 218 | } | ||
| 219 | |||
| 214 | Queue<Order> queue = new ConcurrentLinkedQueue<>(); | 220 | Queue<Order> queue = new ConcurrentLinkedQueue<>(); |
| 215 | Runnable updater = new Runnable() { | 221 | Runnable updater = new Runnable() { |
| 216 | @Override | 222 | @Override |
| @@ -221,8 +227,9 @@ public class SearchDialog { | |||
| 221 | 227 | ||
| 222 | // too large count may increase delay for key and input handling, etc. | 228 | // too large count may increase delay for key and input handling, etc. |
| 223 | int count = 100; | 229 | int count = 100; |
| 230 | |||
| 224 | while (count > 0 && !queue.isEmpty()) { | 231 | while (count > 0 && !queue.isEmpty()) { |
| 225 | var o = queue.remove(); | 232 | Order o = queue.remove(); |
| 226 | classListModel.insertElementAt(o.e, o.idx); | 233 | classListModel.insertElementAt(o.e, o.idx); |
| 227 | count--; | 234 | count--; |
| 228 | } | 235 | } |
| @@ -240,7 +247,6 @@ public class SearchDialog { | |||
| 240 | } | 247 | } |
| 241 | 248 | ||
| 242 | private static final class SearchEntryImpl implements SearchEntry { | 249 | private static final class SearchEntryImpl implements SearchEntry { |
| 243 | |||
| 244 | public final ParentedEntry<?> obf; | 250 | public final ParentedEntry<?> obf; |
| 245 | public final ParentedEntry<?> deobf; | 251 | public final ParentedEntry<?> deobf; |
| 246 | 252 | ||
| @@ -270,10 +276,13 @@ public class SearchDialog { | |||
| 270 | 276 | ||
| 271 | public static SearchEntryImpl from(ParentedEntry<?> e, GuiController controller) { | 277 | public static SearchEntryImpl from(ParentedEntry<?> e, GuiController controller) { |
| 272 | ParentedEntry<?> deobf = controller.project.getMapper().deobfuscate(e); | 278 | ParentedEntry<?> deobf = controller.project.getMapper().deobfuscate(e); |
| 273 | if (deobf.equals(e)) deobf = null; | 279 | |
| 280 | if (deobf.equals(e)) { | ||
| 281 | deobf = null; | ||
| 282 | } | ||
| 283 | |||
| 274 | return new SearchEntryImpl(e, deobf); | 284 | return new SearchEntryImpl(e, deobf); |
| 275 | } | 285 | } |
| 276 | |||
| 277 | } | 286 | } |
| 278 | 287 | ||
| 279 | private static final class ListCellRendererImpl extends AbstractListCellRenderer<SearchEntryImpl> { | 288 | private static final class ListCellRendererImpl extends AbstractListCellRenderer<SearchEntryImpl> { |
| @@ -281,7 +290,7 @@ public class SearchDialog { | |||
| 281 | private final JLabel mainName; | 290 | private final JLabel mainName; |
| 282 | private final JLabel secondaryName; | 291 | private final JLabel secondaryName; |
| 283 | 292 | ||
| 284 | public ListCellRendererImpl(Gui gui) { | 293 | ListCellRendererImpl(Gui gui) { |
| 285 | this.setLayout(new BorderLayout()); | 294 | this.setLayout(new BorderLayout()); |
| 286 | this.gui = gui; | 295 | this.gui = gui; |
| 287 | 296 | ||
| @@ -316,7 +325,6 @@ public class SearchDialog { | |||
| 316 | mainName.setIcon(GuiUtil.FIELD_ICON); | 325 | mainName.setIcon(GuiUtil.FIELD_ICON); |
| 317 | } | 326 | } |
| 318 | } | 327 | } |
| 319 | |||
| 320 | } | 328 | } |
| 321 | 329 | ||
| 322 | public enum Type { | 330 | public enum Type { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java index 0398093b..1ab66ef2 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/StatsDialog.java | |||
| @@ -4,10 +4,19 @@ import java.awt.Container; | |||
| 4 | import java.awt.Dimension; | 4 | import java.awt.Dimension; |
| 5 | import java.awt.GridBagConstraints; | 5 | import java.awt.GridBagConstraints; |
| 6 | import java.awt.GridBagLayout; | 6 | import java.awt.GridBagLayout; |
| 7 | import java.util.*; | 7 | import java.util.Collections; |
| 8 | import java.util.HashMap; | ||
| 9 | import java.util.Locale; | ||
| 10 | import java.util.Map; | ||
| 11 | import java.util.Set; | ||
| 8 | import java.util.stream.Collectors; | 12 | import java.util.stream.Collectors; |
| 9 | 13 | ||
| 10 | import javax.swing.*; | 14 | import javax.swing.JButton; |
| 15 | import javax.swing.JCheckBox; | ||
| 16 | import javax.swing.JDialog; | ||
| 17 | import javax.swing.JLabel; | ||
| 18 | import javax.swing.JTextField; | ||
| 19 | import javax.swing.SwingUtilities; | ||
| 11 | 20 | ||
| 12 | import cuchaz.enigma.gui.Gui; | 21 | import cuchaz.enigma.gui.Gui; |
| 13 | import cuchaz.enigma.gui.config.UiConfig; | 22 | import cuchaz.enigma.gui.config.UiConfig; |
| @@ -19,14 +28,15 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 19 | import cuchaz.enigma.utils.I18n; | 28 | import cuchaz.enigma.utils.I18n; |
| 20 | 29 | ||
| 21 | public class StatsDialog { | 30 | public class StatsDialog { |
| 22 | |||
| 23 | public static void show(Gui gui) { | 31 | public static void show(Gui gui) { |
| 24 | ProgressDialog.runOffThread(gui.getFrame(), listener -> { | 32 | ProgressDialog.runOffThread(gui.getFrame(), listener -> { |
| 25 | final StatsGenerator statsGenerator = new StatsGenerator(gui.getController().project); | 33 | final StatsGenerator statsGenerator = new StatsGenerator(gui.getController().project); |
| 26 | final Map<StatsMember, StatsResult> results = new HashMap<>(); | 34 | final Map<StatsMember, StatsResult> results = new HashMap<>(); |
| 35 | |||
| 27 | for (StatsMember member : StatsMember.values()) { | 36 | for (StatsMember member : StatsMember.values()) { |
| 28 | results.put(member, statsGenerator.generate(listener, Collections.singleton(member), "", false)); | 37 | results.put(member, statsGenerator.generate(listener, Collections.singleton(member), "", false)); |
| 29 | } | 38 | } |
| 39 | |||
| 30 | SwingUtilities.invokeLater(() -> show(gui, results)); | 40 | SwingUtilities.invokeLater(() -> show(gui, results)); |
| 31 | }); | 41 | }); |
| 32 | } | 42 | } |
| @@ -111,12 +121,7 @@ public class StatsDialog { | |||
| 111 | 121 | ||
| 112 | private static void generateStats(Gui gui, Map<StatsMember, JCheckBox> checkboxes, String topLevelPackage, boolean includeSynthetic) { | 122 | private static void generateStats(Gui gui, Map<StatsMember, JCheckBox> checkboxes, String topLevelPackage, boolean includeSynthetic) { |
| 113 | // get members from selected checkboxes | 123 | // get members from selected checkboxes |
| 114 | Set<StatsMember> includedMembers = checkboxes | 124 | Set<StatsMember> includedMembers = checkboxes.entrySet().stream().filter(entry -> entry.getValue().isSelected()).map(Map.Entry::getKey).collect(Collectors.toSet()); |
| 115 | .entrySet() | ||
| 116 | .stream() | ||
| 117 | .filter(entry -> entry.getValue().isSelected()) | ||
| 118 | .map(Map.Entry::getKey) | ||
| 119 | .collect(Collectors.toSet()); | ||
| 120 | 125 | ||
| 121 | // checks if a project is open | 126 | // checks if a project is open |
| 122 | if (gui.getController().project != null) { | 127 | if (gui.getController().project != null) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java index 39aa212f..3f1625de 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/AbstractInheritanceTree.java | |||
| @@ -7,7 +7,11 @@ import javax.annotation.Nullable; | |||
| 7 | import javax.swing.JPanel; | 7 | import javax.swing.JPanel; |
| 8 | import javax.swing.JScrollPane; | 8 | import javax.swing.JScrollPane; |
| 9 | import javax.swing.JTree; | 9 | import javax.swing.JTree; |
| 10 | import javax.swing.tree.*; | 10 | import javax.swing.tree.DefaultMutableTreeNode; |
| 11 | import javax.swing.tree.DefaultTreeModel; | ||
| 12 | import javax.swing.tree.TreeCellRenderer; | ||
| 13 | import javax.swing.tree.TreeNode; | ||
| 14 | import javax.swing.tree.TreePath; | ||
| 11 | 15 | ||
| 12 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; | 16 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; |
| 13 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; | 17 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; |
| @@ -40,11 +44,13 @@ public abstract class AbstractInheritanceTree { | |||
| 40 | if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { | 44 | if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { |
| 41 | // get the selected node | 45 | // get the selected node |
| 42 | TreePath path = tree.getSelectionPath(); | 46 | TreePath path = tree.getSelectionPath(); |
| 47 | |||
| 43 | if (path == null) { | 48 | if (path == null) { |
| 44 | return; | 49 | return; |
| 45 | } | 50 | } |
| 46 | 51 | ||
| 47 | Object node = path.getLastPathComponent(); | 52 | Object node = path.getLastPathComponent(); |
| 53 | |||
| 48 | if (node instanceof ClassInheritanceTreeNode classNode) { | 54 | if (node instanceof ClassInheritanceTreeNode classNode) { |
| 49 | gui.getController().navigateTo(new ClassEntry(classNode.getObfClassName())); | 55 | gui.getController().navigateTo(new ClassEntry(classNode.getObfClassName())); |
| 50 | } else if (node instanceof MethodInheritanceTreeNode methodNode) { | 56 | } else if (node instanceof MethodInheritanceTreeNode methodNode) { |
| @@ -72,7 +78,6 @@ public abstract class AbstractInheritanceTree { | |||
| 72 | } | 78 | } |
| 73 | 79 | ||
| 74 | public void retranslateUi() { | 80 | public void retranslateUi() { |
| 75 | |||
| 76 | } | 81 | } |
| 77 | 82 | ||
| 78 | @Nullable | 83 | @Nullable |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java index c92534f0..56711880 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CallsTree.java | |||
| @@ -5,7 +5,12 @@ import java.awt.event.MouseEvent; | |||
| 5 | import java.util.Collection; | 5 | import java.util.Collection; |
| 6 | import java.util.Vector; | 6 | import java.util.Vector; |
| 7 | 7 | ||
| 8 | import javax.swing.*; | 8 | import javax.swing.JList; |
| 9 | import javax.swing.JPanel; | ||
| 10 | import javax.swing.JScrollPane; | ||
| 11 | import javax.swing.JSplitPane; | ||
| 12 | import javax.swing.JTree; | ||
| 13 | import javax.swing.ListSelectionModel; | ||
| 9 | import javax.swing.tree.DefaultTreeModel; | 14 | import javax.swing.tree.DefaultTreeModel; |
| 10 | import javax.swing.tree.TreeNode; | 15 | import javax.swing.tree.TreeNode; |
| 11 | import javax.swing.tree.TreePath; | 16 | import javax.swing.tree.TreePath; |
| @@ -47,12 +52,7 @@ public class CallsTree { | |||
| 47 | this.tokens.setPreferredSize(ScaleUtil.getDimension(0, 200)); | 52 | this.tokens.setPreferredSize(ScaleUtil.getDimension(0, 200)); |
| 48 | this.tokens.setMinimumSize(ScaleUtil.getDimension(0, 200)); | 53 | this.tokens.setMinimumSize(ScaleUtil.getDimension(0, 200)); |
| 49 | 54 | ||
| 50 | JSplitPane contentPane = new JSplitPane( | 55 | JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, new JScrollPane(this.callsTree), new JScrollPane(this.tokens)); |
| 51 | JSplitPane.VERTICAL_SPLIT, | ||
| 52 | true, | ||
| 53 | new JScrollPane(this.callsTree), | ||
| 54 | new JScrollPane(this.tokens) | ||
| 55 | ); | ||
| 56 | 56 | ||
| 57 | contentPane.setResizeWeight(1); // let the top side take all the slack | 57 | contentPane.setResizeWeight(1); // let the top side take all the slack |
| 58 | contentPane.resetToPreferredSizes(); | 58 | contentPane.resetToPreferredSizes(); |
| @@ -109,6 +109,7 @@ public class CallsTree { | |||
| 109 | private void onTokenClicked(MouseEvent event) { | 109 | private void onTokenClicked(MouseEvent event) { |
| 110 | if (event.getClickCount() == 2) { | 110 | if (event.getClickCount() == 2) { |
| 111 | Token selected = this.tokens.getSelectedValue(); | 111 | Token selected = this.tokens.getSelectedValue(); |
| 112 | |||
| 112 | if (selected != null) { | 113 | if (selected != null) { |
| 113 | this.gui.openClass(this.gui.getController().getTokenHandle().getRef()).navigateToToken(selected); | 114 | this.gui.openClass(this.gui.getController().getTokenHandle().getRef()).navigateToToken(selected); |
| 114 | } | 115 | } |
| @@ -116,7 +117,6 @@ public class CallsTree { | |||
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | public void retranslateUi() { | 119 | public void retranslateUi() { |
| 119 | |||
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | public JPanel getPanel() { | 122 | public JPanel getPanel() { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java index fb497b11..e05ab458 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/CollapsibleTabbedPane.java | |||
| @@ -5,7 +5,6 @@ import java.awt.event.MouseEvent; | |||
| 5 | import javax.swing.JTabbedPane; | 5 | import javax.swing.JTabbedPane; |
| 6 | 6 | ||
| 7 | public class CollapsibleTabbedPane extends JTabbedPane { | 7 | public class CollapsibleTabbedPane extends JTabbedPane { |
| 8 | |||
| 9 | public CollapsibleTabbedPane() { | 8 | public CollapsibleTabbedPane() { |
| 10 | } | 9 | } |
| 11 | 10 | ||
| @@ -20,9 +19,14 @@ public class CollapsibleTabbedPane extends JTabbedPane { | |||
| 20 | @Override | 19 | @Override |
| 21 | protected void processMouseEvent(MouseEvent e) { | 20 | protected void processMouseEvent(MouseEvent e) { |
| 22 | int id = e.getID(); | 21 | int id = e.getID(); |
| 22 | |||
| 23 | if (id == MouseEvent.MOUSE_PRESSED) { | 23 | if (id == MouseEvent.MOUSE_PRESSED) { |
| 24 | if (!isEnabled()) return; | 24 | if (!isEnabled()) { |
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 25 | int tabIndex = getUI().tabForCoordinate(this, e.getX(), e.getY()); | 28 | int tabIndex = getUI().tabForCoordinate(this, e.getX(), e.getY()); |
| 29 | |||
| 26 | if (tabIndex >= 0 && isEnabledAt(tabIndex)) { | 30 | if (tabIndex >= 0 && isEnabledAt(tabIndex)) { |
| 27 | if (tabIndex == getSelectedIndex()) { | 31 | if (tabIndex == getSelectedIndex()) { |
| 28 | if (isFocusOwner() && isRequestFocusEnabled()) { | 32 | if (isFocusOwner() && isRequestFocusEnabled()) { |
| @@ -30,11 +34,12 @@ public class CollapsibleTabbedPane extends JTabbedPane { | |||
| 30 | } else { | 34 | } else { |
| 31 | setSelectedIndex(-1); | 35 | setSelectedIndex(-1); |
| 32 | } | 36 | } |
| 37 | |||
| 33 | return; | 38 | return; |
| 34 | } | 39 | } |
| 35 | } | 40 | } |
| 36 | } | 41 | } |
| 42 | |||
| 37 | super.processMouseEvent(e); | 43 | super.processMouseEvent(e); |
| 38 | } | 44 | } |
| 39 | |||
| 40 | } | 45 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java index 9a6ea098..301ae7f1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ConvertingTextField.java | |||
| @@ -1,7 +1,12 @@ | |||
| 1 | package cuchaz.enigma.gui.elements; | 1 | package cuchaz.enigma.gui.elements; |
| 2 | 2 | ||
| 3 | import java.awt.GridLayout; | 3 | import java.awt.GridLayout; |
| 4 | import java.awt.event.*; | 4 | import java.awt.event.FocusAdapter; |
| 5 | import java.awt.event.FocusEvent; | ||
| 6 | import java.awt.event.KeyAdapter; | ||
| 7 | import java.awt.event.KeyEvent; | ||
| 8 | import java.awt.event.MouseAdapter; | ||
| 9 | import java.awt.event.MouseEvent; | ||
| 5 | import java.util.HashSet; | 10 | import java.util.HashSet; |
| 6 | import java.util.Set; | 11 | import java.util.Set; |
| 7 | 12 | ||
| @@ -21,7 +26,6 @@ import cuchaz.enigma.utils.validation.Validatable; | |||
| 21 | * A label that converts into an editable text field when you click it. | 26 | * A label that converts into an editable text field when you click it. |
| 22 | */ | 27 | */ |
| 23 | public class ConvertingTextField implements Validatable { | 28 | public class ConvertingTextField implements Validatable { |
| 24 | |||
| 25 | private final JPanel ui; | 29 | private final JPanel ui; |
| 26 | private final ValidatableTextField textField; | 30 | private final ValidatableTextField textField; |
| 27 | private final JLabel label; | 31 | private final JLabel label; |
| @@ -69,7 +73,9 @@ public class ConvertingTextField implements Validatable { | |||
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | public void startEditing() { | 75 | public void startEditing() { |
| 72 | if (this.editing || !this.editable) return; | 76 | if (this.editing || !this.editable) { |
| 77 | return; | ||
| 78 | } | ||
| 73 | 79 | ||
| 74 | this.ui.removeAll(); | 80 | this.ui.removeAll(); |
| 75 | this.ui.add(this.textField); | 81 | this.ui.add(this.textField); |
| @@ -82,9 +88,13 @@ public class ConvertingTextField implements Validatable { | |||
| 82 | } | 88 | } |
| 83 | 89 | ||
| 84 | public void stopEditing(boolean abort) { | 90 | public void stopEditing(boolean abort) { |
| 85 | if (!editing) return; | 91 | if (!editing) { |
| 92 | return; | ||
| 93 | } | ||
| 86 | 94 | ||
| 87 | if (!listeners.stream().allMatch(l -> l.tryStopEditing(this, abort))) return; | 95 | if (!listeners.stream().allMatch(l -> l.tryStopEditing(this, abort))) { |
| 96 | return; | ||
| 97 | } | ||
| 88 | 98 | ||
| 89 | if (abort) { | 99 | if (abort) { |
| 90 | this.textField.setText(this.label.getText()); | 100 | this.textField.setText(this.label.getText()); |
| @@ -107,7 +117,9 @@ public class ConvertingTextField implements Validatable { | |||
| 107 | } | 117 | } |
| 108 | 118 | ||
| 109 | public void setEditText(String text) { | 119 | public void setEditText(String text) { |
| 110 | if (!editing) return; | 120 | if (!editing) { |
| 121 | return; | ||
| 122 | } | ||
| 111 | 123 | ||
| 112 | this.textField.setText(text); | 124 | this.textField.setText(text); |
| 113 | } | 125 | } |
| @@ -122,22 +134,29 @@ public class ConvertingTextField implements Validatable { | |||
| 122 | } | 134 | } |
| 123 | 135 | ||
| 124 | public void selectAll() { | 136 | public void selectAll() { |
| 125 | if (!editing) return; | 137 | if (!editing) { |
| 138 | return; | ||
| 139 | } | ||
| 126 | 140 | ||
| 127 | this.textField.selectAll(); | 141 | this.textField.selectAll(); |
| 128 | } | 142 | } |
| 129 | 143 | ||
| 130 | public void selectSubstring(int startIndex) { | 144 | public void selectSubstring(int startIndex) { |
| 131 | if (!editing) return; | 145 | if (!editing) { |
| 146 | return; | ||
| 147 | } | ||
| 132 | 148 | ||
| 133 | Document doc = this.textField.getDocument(); | 149 | Document doc = this.textField.getDocument(); |
| 150 | |||
| 134 | if (doc != null) { | 151 | if (doc != null) { |
| 135 | this.selectSubstring(startIndex, doc.getLength()); | 152 | this.selectSubstring(startIndex, doc.getLength()); |
| 136 | } | 153 | } |
| 137 | } | 154 | } |
| 138 | 155 | ||
| 139 | public void selectSubstring(int startIndex, int endIndex) { | 156 | public void selectSubstring(int startIndex, int endIndex) { |
| 140 | if (!editing) return; | 157 | if (!editing) { |
| 158 | return; | ||
| 159 | } | ||
| 141 | 160 | ||
| 142 | this.textField.select(startIndex, endIndex); | 161 | this.textField.select(startIndex, endIndex); |
| 143 | } | 162 | } |
| @@ -155,7 +174,10 @@ public class ConvertingTextField implements Validatable { | |||
| 155 | } | 174 | } |
| 156 | 175 | ||
| 157 | public boolean hasChanges() { | 176 | public boolean hasChanges() { |
| 158 | if (!editing) return false; | 177 | if (!editing) { |
| 178 | return false; | ||
| 179 | } | ||
| 180 | |||
| 159 | return !this.textField.getText().equals(this.label.getText()); | 181 | return !this.textField.getText().equals(this.label.getText()); |
| 160 | } | 182 | } |
| 161 | 183 | ||
| @@ -180,5 +202,4 @@ public class ConvertingTextField implements Validatable { | |||
| 180 | public JPanel getUi() { | 202 | public JPanel getUi() { |
| 181 | return ui; | 203 | return ui; |
| 182 | } | 204 | } |
| 183 | |||
| 184 | } | 205 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java index 0b44881f..bcc6dc6f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java | |||
| @@ -9,55 +9,54 @@ import cuchaz.enigma.gui.panels.DeobfPanel; | |||
| 9 | import cuchaz.enigma.utils.I18n; | 9 | import cuchaz.enigma.utils.I18n; |
| 10 | 10 | ||
| 11 | public class DeobfPanelPopupMenu { | 11 | public class DeobfPanelPopupMenu { |
| 12 | 12 | private final JPopupMenu ui; | |
| 13 | private final JPopupMenu ui; | 13 | private final JMenuItem renamePackage = new JMenuItem(); |
| 14 | private final JMenuItem renamePackage = new JMenuItem(); | 14 | private final JMenuItem renameClass = new JMenuItem(); |
| 15 | private final JMenuItem renameClass = new JMenuItem(); | 15 | private final JMenuItem expandAll = new JMenuItem(); |
| 16 | private final JMenuItem expandAll = new JMenuItem(); | 16 | private final JMenuItem collapseAll = new JMenuItem(); |
| 17 | private final JMenuItem collapseAll = new JMenuItem(); | 17 | |
| 18 | 18 | public DeobfPanelPopupMenu(DeobfPanel panel) { | |
| 19 | public DeobfPanelPopupMenu(DeobfPanel panel) { | 19 | this.ui = new JPopupMenu(); |
| 20 | this.ui = new JPopupMenu(); | 20 | |
| 21 | 21 | this.ui.add(this.renamePackage); | |
| 22 | this.ui.add(this.renamePackage); | 22 | this.ui.add(this.renameClass); |
| 23 | this.ui.add(this.renameClass); | 23 | this.ui.addSeparator(); |
| 24 | this.ui.addSeparator(); | 24 | this.ui.add(this.expandAll); |
| 25 | this.ui.add(this.expandAll); | 25 | this.ui.add(this.collapseAll); |
| 26 | this.ui.add(this.collapseAll); | 26 | |
| 27 | 27 | ClassSelector deobfClasses = panel.deobfClasses; | |
| 28 | ClassSelector deobfClasses = panel.deobfClasses; | 28 | |
| 29 | 29 | this.renamePackage.addActionListener(a -> { | |
| 30 | this.renamePackage.addActionListener(a -> { | 30 | TreePath path; |
| 31 | TreePath path; | 31 | |
| 32 | 32 | if (deobfClasses.getSelectedClass() != null) { | |
| 33 | if (deobfClasses.getSelectedClass() != null) { | 33 | // Rename parent package if selected path is a class |
| 34 | // Rename parent package if selected path is a class | 34 | path = deobfClasses.getSelectionPath().getParentPath(); |
| 35 | path = deobfClasses.getSelectionPath().getParentPath(); | 35 | } else { |
| 36 | } else { | 36 | // Rename selected path if it's already a package |
| 37 | // Rename selected path if it's already a package | 37 | path = deobfClasses.getSelectionPath(); |
| 38 | path = deobfClasses.getSelectionPath(); | 38 | } |
| 39 | } | 39 | |
| 40 | 40 | deobfClasses.getUI().startEditingAtPath(deobfClasses, path); | |
| 41 | deobfClasses.getUI().startEditingAtPath(deobfClasses, path); | 41 | }); |
| 42 | }); | 42 | this.renameClass.addActionListener(a -> deobfClasses.getUI().startEditingAtPath(deobfClasses, deobfClasses.getSelectionPath())); |
| 43 | this.renameClass.addActionListener(a -> deobfClasses.getUI().startEditingAtPath(deobfClasses, deobfClasses.getSelectionPath())); | 43 | this.expandAll.addActionListener(a -> deobfClasses.expandAll()); |
| 44 | this.expandAll.addActionListener(a -> deobfClasses.expandAll()); | 44 | this.collapseAll.addActionListener(a -> deobfClasses.collapseAll()); |
| 45 | this.collapseAll.addActionListener(a -> deobfClasses.collapseAll()); | 45 | |
| 46 | 46 | this.retranslateUi(); | |
| 47 | this.retranslateUi(); | 47 | } |
| 48 | } | 48 | |
| 49 | 49 | public void show(ClassSelector deobfClasses, int x, int y) { | |
| 50 | public void show(ClassSelector deobfClasses, int x, int y) { | 50 | // Only enable rename class if selected path is a class |
| 51 | // Only enable rename class if selected path is a class | 51 | this.renameClass.setEnabled(deobfClasses.getSelectedClass() != null); |
| 52 | this.renameClass.setEnabled(deobfClasses.getSelectedClass() != null); | 52 | |
| 53 | 53 | this.ui.show(deobfClasses, x, y); | |
| 54 | this.ui.show(deobfClasses, x, y); | 54 | } |
| 55 | } | 55 | |
| 56 | 56 | public void retranslateUi() { | |
| 57 | public void retranslateUi() { | 57 | this.renamePackage.setText(I18n.translate("popup_menu.deobf_panel.rename_package")); |
| 58 | this.renamePackage.setText(I18n.translate("popup_menu.deobf_panel.rename_package")); | 58 | this.renameClass.setText(I18n.translate("popup_menu.deobf_panel.rename_class")); |
| 59 | this.renameClass.setText(I18n.translate("popup_menu.deobf_panel.rename_class")); | 59 | this.expandAll.setText(I18n.translate("popup_menu.deobf_panel.expand_all")); |
| 60 | this.expandAll.setText(I18n.translate("popup_menu.deobf_panel.expand_all")); | 60 | this.collapseAll.setText(I18n.translate("popup_menu.deobf_panel.collapse_all")); |
| 61 | this.collapseAll.setText(I18n.translate("popup_menu.deobf_panel.collapse_all")); | 61 | } |
| 62 | } | ||
| 63 | } | 62 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java index 2ce6ed93..d128bf5c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorPopupMenu.java | |||
| @@ -19,7 +19,6 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry; | |||
| 19 | import cuchaz.enigma.utils.I18n; | 19 | import cuchaz.enigma.utils.I18n; |
| 20 | 20 | ||
| 21 | public class EditorPopupMenu { | 21 | public class EditorPopupMenu { |
| 22 | |||
| 23 | private final JPopupMenu ui = new JPopupMenu(); | 22 | private final JPopupMenu ui = new JPopupMenu(); |
| 24 | 23 | ||
| 25 | private final JMenuItem renameItem = new JMenuItem(); | 24 | private final JMenuItem renameItem = new JMenuItem(); |
| @@ -105,39 +104,41 @@ public class EditorPopupMenu { | |||
| 105 | public boolean handleKeyEvent(KeyEvent event) { | 104 | public boolean handleKeyEvent(KeyEvent event) { |
| 106 | if (event.isControlDown()) { | 105 | if (event.isControlDown()) { |
| 107 | switch (event.getKeyCode()) { | 106 | switch (event.getKeyCode()) { |
| 108 | case KeyEvent.VK_I: | 107 | case KeyEvent.VK_I: |
| 109 | this.showInheritanceItem.doClick(); | 108 | this.showInheritanceItem.doClick(); |
| 110 | return true; | 109 | return true; |
| 111 | case KeyEvent.VK_M: | 110 | case KeyEvent.VK_M: |
| 112 | this.showImplementationsItem.doClick(); | 111 | this.showImplementationsItem.doClick(); |
| 113 | return true; | 112 | return true; |
| 114 | case KeyEvent.VK_N: | 113 | case KeyEvent.VK_N: |
| 115 | this.openEntryItem.doClick(); | 114 | this.openEntryItem.doClick(); |
| 116 | return true; | 115 | return true; |
| 117 | case KeyEvent.VK_P: | 116 | case KeyEvent.VK_P: |
| 118 | this.openPreviousItem.doClick(); | 117 | this.openPreviousItem.doClick(); |
| 119 | return true; | 118 | return true; |
| 120 | case KeyEvent.VK_E: | 119 | case KeyEvent.VK_E: |
| 121 | this.openNextItem.doClick(); | 120 | this.openNextItem.doClick(); |
| 122 | return true; | 121 | return true; |
| 123 | case KeyEvent.VK_C: | 122 | case KeyEvent.VK_C: |
| 124 | if (event.isShiftDown()) { | 123 | if (event.isShiftDown()) { |
| 125 | this.showCallsSpecificItem.doClick(); | 124 | this.showCallsSpecificItem.doClick(); |
| 126 | } else { | 125 | } else { |
| 127 | this.showCallsItem.doClick(); | 126 | this.showCallsItem.doClick(); |
| 128 | } | 127 | } |
| 129 | return true; | 128 | |
| 130 | case KeyEvent.VK_O: | 129 | return true; |
| 131 | this.toggleMappingItem.doClick(); | 130 | case KeyEvent.VK_O: |
| 132 | return true; | 131 | this.toggleMappingItem.doClick(); |
| 133 | case KeyEvent.VK_R: | 132 | return true; |
| 134 | this.renameItem.doClick(); | 133 | case KeyEvent.VK_R: |
| 135 | return true; | 134 | this.renameItem.doClick(); |
| 136 | case KeyEvent.VK_D: | 135 | return true; |
| 137 | this.editJavadocItem.doClick(); | 136 | case KeyEvent.VK_D: |
| 138 | return true; | 137 | this.editJavadocItem.doClick(); |
| 138 | return true; | ||
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | |||
| 141 | return false; | 142 | return false; |
| 142 | } | 143 | } |
| 143 | 144 | ||
| @@ -191,5 +192,4 @@ public class EditorPopupMenu { | |||
| 191 | public JPopupMenu getUi() { | 192 | public JPopupMenu getUi() { |
| 192 | return ui; | 193 | return ui; |
| 193 | } | 194 | } |
| 194 | |||
| 195 | } | 195 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java index 0b4926eb..93854818 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabPopupMenu.java | |||
| @@ -11,7 +11,6 @@ import cuchaz.enigma.gui.panels.EditorPanel; | |||
| 11 | import cuchaz.enigma.utils.I18n; | 11 | import cuchaz.enigma.utils.I18n; |
| 12 | 12 | ||
| 13 | public class EditorTabPopupMenu { | 13 | public class EditorTabPopupMenu { |
| 14 | |||
| 15 | private final JPopupMenu ui; | 14 | private final JPopupMenu ui; |
| 16 | private final JMenuItem close; | 15 | private final JMenuItem close; |
| 17 | private final JMenuItem closeAll; | 16 | private final JMenuItem closeAll; |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java index ff0bba3f..7a6290ea 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/EditorTabbedPane.java | |||
| @@ -39,7 +39,11 @@ public class EditorTabbedPane { | |||
| 39 | public EditorPanel openClass(ClassEntry entry) { | 39 | public EditorPanel openClass(ClassEntry entry) { |
| 40 | EditorPanel editorPanel = this.editors.computeIfAbsent(entry, e -> { | 40 | EditorPanel editorPanel = this.editors.computeIfAbsent(entry, e -> { |
| 41 | ClassHandle ch = this.gui.getController().getClassHandleProvider().openClass(entry); | 41 | ClassHandle ch = this.gui.getController().getClassHandleProvider().openClass(entry); |
| 42 | if (ch == null) return null; | 42 | |
| 43 | if (ch == null) { | ||
| 44 | return null; | ||
| 45 | } | ||
| 46 | |||
| 43 | EditorPanel ed = new EditorPanel(this.gui); | 47 | EditorPanel ed = new EditorPanel(this.gui); |
| 44 | ed.setup(); | 48 | ed.setup(); |
| 45 | ed.setClassHandle(ch); | 49 | ed.setClassHandle(ch); |
| @@ -125,7 +129,10 @@ public class EditorTabbedPane { | |||
| 125 | int index = this.openFiles.indexOfComponent(ed.getUi()); | 129 | int index = this.openFiles.indexOfComponent(ed.getUi()); |
| 126 | 130 | ||
| 127 | for (int i = this.openFiles.getTabCount() - 1; i >= 0; i--) { | 131 | for (int i = this.openFiles.getTabCount() - 1; i >= 0; i--) { |
| 128 | if (i == index) continue; | 132 | if (i == index) { |
| 133 | continue; | ||
| 134 | } | ||
| 135 | |||
| 129 | closeEditor(EditorPanel.byUi(this.openFiles.getComponentAt(i))); | 136 | closeEditor(EditorPanel.byUi(this.openFiles.getComponentAt(i))); |
| 130 | } | 137 | } |
| 131 | } | 138 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java index 533d1b30..9e632d9d 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/JMultiLineToolTip.java | |||
| @@ -12,13 +12,12 @@ import javax.swing.plaf.ComponentUI; | |||
| 12 | import javax.swing.plaf.basic.BasicToolTipUI; | 12 | import javax.swing.plaf.basic.BasicToolTipUI; |
| 13 | 13 | ||
| 14 | /** | 14 | /** |
| 15 | * Implements a multi line tooltip for GUI components | 15 | * Implements a multi line tooltip for GUI components. |
| 16 | * Copied from http://www.codeguru.com/java/articles/122.shtml | 16 | * Copied from http://www.codeguru.com/java/articles/122.shtml |
| 17 | * | 17 | * |
| 18 | * @author Zafir Anjum | 18 | * @author Zafir Anjum |
| 19 | */ | 19 | */ |
| 20 | public class JMultiLineToolTip extends JToolTip { | 20 | public class JMultiLineToolTip extends JToolTip { |
| 21 | |||
| 22 | private static final long serialVersionUID = 7813662474312183098L; | 21 | private static final long serialVersionUID = 7813662474312183098L; |
| 23 | 22 | ||
| 24 | public JMultiLineToolTip() { | 23 | public JMultiLineToolTip() { |
| @@ -52,10 +51,9 @@ public class JMultiLineToolTip extends JToolTip { | |||
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | /** | 53 | /** |
| 55 | * UI for multi line tool tip | 54 | * UI for multi line tool tip. |
| 56 | */ | 55 | */ |
| 57 | class MultiLineToolTipUI extends BasicToolTipUI { | 56 | class MultiLineToolTipUI extends BasicToolTipUI { |
| 58 | |||
| 59 | static MultiLineToolTipUI sharedInstance = new MultiLineToolTipUI(); | 57 | static MultiLineToolTipUI sharedInstance = new MultiLineToolTipUI(); |
| 60 | Font smallFont; | 58 | Font smallFont; |
| 61 | static JToolTip tip; | 59 | static JToolTip tip; |
| @@ -67,7 +65,7 @@ class MultiLineToolTipUI extends BasicToolTipUI { | |||
| 67 | return sharedInstance; | 65 | return sharedInstance; |
| 68 | } | 66 | } |
| 69 | 67 | ||
| 70 | public MultiLineToolTipUI() { | 68 | MultiLineToolTipUI() { |
| 71 | super(); | 69 | super(); |
| 72 | } | 70 | } |
| 73 | 71 | ||
| @@ -93,7 +91,11 @@ class MultiLineToolTipUI extends BasicToolTipUI { | |||
| 93 | 91 | ||
| 94 | public Dimension getPreferredSize(JComponent c) { | 92 | public Dimension getPreferredSize(JComponent c) { |
| 95 | String tipText = ((JToolTip) c).getTipText(); | 93 | String tipText = ((JToolTip) c).getTipText(); |
| 96 | if (tipText == null) return new Dimension(0, 0); | 94 | |
| 95 | if (tipText == null) { | ||
| 96 | return new Dimension(0, 0); | ||
| 97 | } | ||
| 98 | |||
| 97 | textArea = new JTextArea(tipText); | 99 | textArea = new JTextArea(tipText); |
| 98 | rendererPane.removeAll(); | 100 | rendererPane.removeAll(); |
| 99 | rendererPane.add(textArea); | 101 | rendererPane.add(textArea); |
| @@ -112,8 +114,9 @@ class MultiLineToolTipUI extends BasicToolTipUI { | |||
| 112 | d.width = width; | 114 | d.width = width; |
| 113 | d.height++; | 115 | d.height++; |
| 114 | textArea.setSize(d); | 116 | textArea.setSize(d); |
| 115 | } else | 117 | } else { |
| 116 | textArea.setLineWrap(false); | 118 | textArea.setLineWrap(false); |
| 119 | } | ||
| 117 | 120 | ||
| 118 | Dimension dim = textArea.getPreferredSize(); | 121 | Dimension dim = textArea.getPreferredSize(); |
| 119 | 122 | ||
| @@ -129,4 +132,4 @@ class MultiLineToolTipUI extends BasicToolTipUI { | |||
| 129 | public Dimension getMaximumSize(JComponent c) { | 132 | public Dimension getMaximumSize(JComponent c) { |
| 130 | return getPreferredSize(c); | 133 | return getPreferredSize(c); |
| 131 | } | 134 | } |
| 132 | } \ No newline at end of file | 135 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java index eeb52ccf..24a69b65 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java | |||
| @@ -12,7 +12,14 @@ import java.util.Map; | |||
| 12 | import java.util.stream.Collectors; | 12 | import java.util.stream.Collectors; |
| 13 | import java.util.stream.IntStream; | 13 | import java.util.stream.IntStream; |
| 14 | 14 | ||
| 15 | import javax.swing.*; | 15 | import javax.swing.ButtonGroup; |
| 16 | import javax.swing.JFileChooser; | ||
| 17 | import javax.swing.JMenu; | ||
| 18 | import javax.swing.JMenuBar; | ||
| 19 | import javax.swing.JMenuItem; | ||
| 20 | import javax.swing.JOptionPane; | ||
| 21 | import javax.swing.JRadioButtonMenuItem; | ||
| 22 | import javax.swing.KeyStroke; | ||
| 16 | 23 | ||
| 17 | import cuchaz.enigma.gui.ConnectionState; | 24 | import cuchaz.enigma.gui.ConnectionState; |
| 18 | import cuchaz.enigma.gui.Gui; | 25 | import cuchaz.enigma.gui.Gui; |
| @@ -20,7 +27,13 @@ import cuchaz.enigma.gui.config.Decompiler; | |||
| 20 | import cuchaz.enigma.gui.config.LookAndFeel; | 27 | import cuchaz.enigma.gui.config.LookAndFeel; |
| 21 | import cuchaz.enigma.gui.config.NetConfig; | 28 | import cuchaz.enigma.gui.config.NetConfig; |
| 22 | import cuchaz.enigma.gui.config.UiConfig; | 29 | import cuchaz.enigma.gui.config.UiConfig; |
| 23 | import cuchaz.enigma.gui.dialog.*; | 30 | import cuchaz.enigma.gui.dialog.AboutDialog; |
| 31 | import cuchaz.enigma.gui.dialog.ChangeDialog; | ||
| 32 | import cuchaz.enigma.gui.dialog.ConnectToServerDialog; | ||
| 33 | import cuchaz.enigma.gui.dialog.CreateServerDialog; | ||
| 34 | import cuchaz.enigma.gui.dialog.FontDialog; | ||
| 35 | import cuchaz.enigma.gui.dialog.SearchDialog; | ||
| 36 | import cuchaz.enigma.gui.dialog.StatsDialog; | ||
| 24 | import cuchaz.enigma.gui.util.GuiUtil; | 37 | import cuchaz.enigma.gui.util.GuiUtil; |
| 25 | import cuchaz.enigma.gui.util.LanguageUtil; | 38 | import cuchaz.enigma.gui.util.LanguageUtil; |
| 26 | import cuchaz.enigma.gui.util.ScaleUtil; | 39 | import cuchaz.enigma.gui.util.ScaleUtil; |
| @@ -29,7 +42,6 @@ import cuchaz.enigma.utils.I18n; | |||
| 29 | import cuchaz.enigma.utils.Pair; | 42 | import cuchaz.enigma.utils.Pair; |
| 30 | 43 | ||
| 31 | public class MenuBar { | 44 | public class MenuBar { |
| 32 | |||
| 33 | private final JMenu fileMenu = new JMenu(); | 45 | private final JMenu fileMenu = new JMenu(); |
| 34 | private final JMenuItem jarOpenItem = new JMenuItem(); | 46 | private final JMenuItem jarOpenItem = new JMenuItem(); |
| 35 | private final JMenuItem jarCloseItem = new JMenuItem(); | 47 | private final JMenuItem jarCloseItem = new JMenuItem(); |
| @@ -221,13 +233,16 @@ public class MenuBar { | |||
| 221 | } | 233 | } |
| 222 | 234 | ||
| 223 | File file = d.getSelectedFile(); | 235 | File file = d.getSelectedFile(); |
| 236 | |||
| 224 | // checks if the file name is not empty | 237 | // checks if the file name is not empty |
| 225 | if (file != null) { | 238 | if (file != null) { |
| 226 | Path path = file.toPath(); | 239 | Path path = file.toPath(); |
| 240 | |||
| 227 | // checks if the file name corresponds to an existing file | 241 | // checks if the file name corresponds to an existing file |
| 228 | if (Files.exists(path)) { | 242 | if (Files.exists(path)) { |
| 229 | this.gui.getController().openJar(path); | 243 | this.gui.getController().openJar(path); |
| 230 | } | 244 | } |
| 245 | |||
| 231 | UiConfig.setLastSelectedDir(d.getCurrentDirectory().getAbsolutePath()); | 246 | UiConfig.setLastSelectedDir(d.getCurrentDirectory().getAbsolutePath()); |
| 232 | } | 247 | } |
| 233 | } | 248 | } |
| @@ -241,8 +256,10 @@ public class MenuBar { | |||
| 241 | this.gui.showDiscardDiag((response -> { | 256 | this.gui.showDiscardDiag((response -> { |
| 242 | if (response == JOptionPane.YES_OPTION) { | 257 | if (response == JOptionPane.YES_OPTION) { |
| 243 | this.gui.saveMapping().thenRun(then); | 258 | this.gui.saveMapping().thenRun(then); |
| 244 | } else if (response == JOptionPane.NO_OPTION) | 259 | } else if (response == JOptionPane.NO_OPTION) { |
| 245 | then.run(); | 260 | then.run(); |
| 261 | } | ||
| 262 | |||
| 246 | return null; | 263 | return null; |
| 247 | }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.cancel")); | 264 | }), I18n.translate("prompt.close.save"), I18n.translate("prompt.close.discard"), I18n.translate("prompt.cancel")); |
| 248 | } else { | 265 | } else { |
| @@ -264,6 +281,7 @@ public class MenuBar { | |||
| 264 | 281 | ||
| 265 | private void onExportSourceClicked() { | 282 | private void onExportSourceClicked() { |
| 266 | this.gui.exportSourceFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); | 283 | this.gui.exportSourceFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); |
| 284 | |||
| 267 | if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { | 285 | if (this.gui.exportSourceFileChooser.showSaveDialog(this.gui.getFrame()) == JFileChooser.APPROVE_OPTION) { |
| 268 | UiConfig.setLastSelectedDir(this.gui.exportSourceFileChooser.getCurrentDirectory().toString()); | 286 | UiConfig.setLastSelectedDir(this.gui.exportSourceFileChooser.getCurrentDirectory().toString()); |
| 269 | this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath()); | 287 | this.gui.getController().exportSource(this.gui.exportSourceFileChooser.getSelectedFile().toPath()); |
| @@ -287,29 +305,35 @@ public class MenuBar { | |||
| 287 | } | 305 | } |
| 288 | 306 | ||
| 289 | private void onCustomScaleClicked() { | 307 | private void onCustomScaleClicked() { |
| 290 | String answer = (String) JOptionPane.showInputDialog(this.gui.getFrame(), I18n.translate("menu.view.scale.custom.title"), I18n.translate("menu.view.scale.custom.title"), | 308 | String answer = (String) JOptionPane.showInputDialog(this.gui.getFrame(), I18n.translate("menu.view.scale.custom.title"), I18n.translate("menu.view.scale.custom.title"), JOptionPane.QUESTION_MESSAGE, null, null, Float.toString(UiConfig.getScaleFactor() * 100)); |
| 291 | JOptionPane.QUESTION_MESSAGE, null, null, Float.toString(UiConfig.getScaleFactor() * 100)); | 309 | |
| 292 | if (answer == null) return; | 310 | if (answer == null) { |
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 293 | float newScale = 1.0f; | 314 | float newScale = 1.0f; |
| 315 | |||
| 294 | try { | 316 | try { |
| 295 | newScale = Float.parseFloat(answer) / 100f; | 317 | newScale = Float.parseFloat(answer) / 100f; |
| 296 | } catch (NumberFormatException ignored) { | 318 | } catch (NumberFormatException ignored) { |
| 319 | // ignored | ||
| 297 | } | 320 | } |
| 321 | |||
| 298 | ScaleUtil.setScaleFactor(newScale); | 322 | ScaleUtil.setScaleFactor(newScale); |
| 299 | ChangeDialog.show(this.gui.getFrame()); | 323 | ChangeDialog.show(this.gui.getFrame()); |
| 300 | } | 324 | } |
| 301 | 325 | ||
| 302 | private void onFontClicked(Gui gui) { | 326 | private void onFontClicked(Gui gui) { |
| 303 | // FontDialog fd = new FontDialog(gui.getFrame(), "Choose Font", true); | 327 | // FontDialog fd = new FontDialog(gui.getFrame(), "Choose Font", true); |
| 304 | // fd.setLocationRelativeTo(gui.getFrame()); | 328 | // fd.setLocationRelativeTo(gui.getFrame()); |
| 305 | // fd.setSelectedFont(UiConfig.getEditorFont()); | 329 | // fd.setSelectedFont(UiConfig.getEditorFont()); |
| 306 | // fd.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); | 330 | // fd.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); |
| 307 | // fd.setVisible(true); | 331 | // fd.setVisible(true); |
| 308 | // | 332 | // |
| 309 | // if (!fd.isCancelSelected()) { | 333 | // if (!fd.isCancelSelected()) { |
| 310 | // UiConfig.setEditorFont(fd.getSelectedFont()); | 334 | // UiConfig.setEditorFont(fd.getSelectedFont()); |
| 311 | // UiConfig.save(); | 335 | // UiConfig.save(); |
| 312 | // } | 336 | // } |
| 313 | FontDialog.display(gui.getFrame()); | 337 | FontDialog.display(gui.getFrame()); |
| 314 | } | 338 | } |
| 315 | 339 | ||
| @@ -324,11 +348,15 @@ public class MenuBar { | |||
| 324 | this.gui.getController().disconnectIfConnected(null); | 348 | this.gui.getController().disconnectIfConnected(null); |
| 325 | return; | 349 | return; |
| 326 | } | 350 | } |
| 351 | |||
| 327 | ConnectToServerDialog.Result result = ConnectToServerDialog.show(this.gui.getFrame()); | 352 | ConnectToServerDialog.Result result = ConnectToServerDialog.show(this.gui.getFrame()); |
| 353 | |||
| 328 | if (result == null) { | 354 | if (result == null) { |
| 329 | return; | 355 | return; |
| 330 | } | 356 | } |
| 357 | |||
| 331 | this.gui.getController().disconnectIfConnected(null); | 358 | this.gui.getController().disconnectIfConnected(null); |
| 359 | |||
| 332 | try { | 360 | try { |
| 333 | this.gui.getController().createClient(result.getUsername(), result.getAddress().address, result.getAddress().port, result.getPassword()); | 361 | this.gui.getController().createClient(result.getUsername(), result.getAddress().address, result.getAddress().port, result.getPassword()); |
| 334 | NetConfig.setUsername(result.getUsername()); | 362 | NetConfig.setUsername(result.getUsername()); |
| @@ -339,6 +367,7 @@ public class MenuBar { | |||
| 339 | JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE); | 367 | JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE); |
| 340 | this.gui.getController().disconnectIfConnected(null); | 368 | this.gui.getController().disconnectIfConnected(null); |
| 341 | } | 369 | } |
| 370 | |||
| 342 | Arrays.fill(result.getPassword(), (char) 0); | 371 | Arrays.fill(result.getPassword(), (char) 0); |
| 343 | } | 372 | } |
| 344 | 373 | ||
| @@ -347,11 +376,15 @@ public class MenuBar { | |||
| 347 | this.gui.getController().disconnectIfConnected(null); | 376 | this.gui.getController().disconnectIfConnected(null); |
| 348 | return; | 377 | return; |
| 349 | } | 378 | } |
| 379 | |||
| 350 | CreateServerDialog.Result result = CreateServerDialog.show(this.gui.getFrame()); | 380 | CreateServerDialog.Result result = CreateServerDialog.show(this.gui.getFrame()); |
| 381 | |||
| 351 | if (result == null) { | 382 | if (result == null) { |
| 352 | return; | 383 | return; |
| 353 | } | 384 | } |
| 385 | |||
| 354 | this.gui.getController().disconnectIfConnected(null); | 386 | this.gui.getController().disconnectIfConnected(null); |
| 387 | |||
| 355 | try { | 388 | try { |
| 356 | this.gui.getController().createServer(result.getPort(), result.getPassword()); | 389 | this.gui.getController().createServer(result.getPort(), result.getPassword()); |
| 357 | NetConfig.setServerPort(result.getPort()); | 390 | NetConfig.setServerPort(result.getPort()); |
| @@ -373,6 +406,7 @@ public class MenuBar { | |||
| 373 | JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT))); | 406 | JMenuItem item = new JMenuItem(I18n.translate("mapping_format." + format.name().toLowerCase(Locale.ROOT))); |
| 374 | item.addActionListener(event -> { | 407 | item.addActionListener(event -> { |
| 375 | gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); | 408 | gui.enigmaMappingsFileChooser.setCurrentDirectory(new File(UiConfig.getLastSelectedDir())); |
| 409 | |||
| 376 | if (gui.enigmaMappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) { | 410 | if (gui.enigmaMappingsFileChooser.showOpenDialog(gui.getFrame()) == JFileChooser.APPROVE_OPTION) { |
| 377 | File selectedFile = gui.enigmaMappingsFileChooser.getSelectedFile(); | 411 | File selectedFile = gui.enigmaMappingsFileChooser.getSelectedFile(); |
| 378 | gui.getController().openMappings(format, selectedFile.toPath()); | 412 | gui.getController().openMappings(format, selectedFile.toPath()); |
| @@ -411,9 +445,11 @@ public class MenuBar { | |||
| 411 | for (Decompiler decompiler : Decompiler.values()) { | 445 | for (Decompiler decompiler : Decompiler.values()) { |
| 412 | JRadioButtonMenuItem decompilerButton = new JRadioButtonMenuItem(decompiler.name); | 446 | JRadioButtonMenuItem decompilerButton = new JRadioButtonMenuItem(decompiler.name); |
| 413 | decompilerGroup.add(decompilerButton); | 447 | decompilerGroup.add(decompilerButton); |
| 448 | |||
| 414 | if (decompiler.equals(UiConfig.getDecompiler())) { | 449 | if (decompiler.equals(UiConfig.getDecompiler())) { |
| 415 | decompilerButton.setSelected(true); | 450 | decompilerButton.setSelected(true); |
| 416 | } | 451 | } |
| 452 | |||
| 417 | decompilerButton.addActionListener(event -> { | 453 | decompilerButton.addActionListener(event -> { |
| 418 | gui.getController().setDecompiler(decompiler.service); | 454 | gui.getController().setDecompiler(decompiler.service); |
| 419 | 455 | ||
| @@ -426,12 +462,15 @@ public class MenuBar { | |||
| 426 | 462 | ||
| 427 | private static void prepareThemesMenu(JMenu themesMenu, Gui gui) { | 463 | private static void prepareThemesMenu(JMenu themesMenu, Gui gui) { |
| 428 | ButtonGroup themeGroup = new ButtonGroup(); | 464 | ButtonGroup themeGroup = new ButtonGroup(); |
| 465 | |||
| 429 | for (LookAndFeel lookAndFeel : LookAndFeel.values()) { | 466 | for (LookAndFeel lookAndFeel : LookAndFeel.values()) { |
| 430 | JRadioButtonMenuItem themeButton = new JRadioButtonMenuItem(I18n.translate("menu.view.themes." + lookAndFeel.name().toLowerCase(Locale.ROOT))); | 467 | JRadioButtonMenuItem themeButton = new JRadioButtonMenuItem(I18n.translate("menu.view.themes." + lookAndFeel.name().toLowerCase(Locale.ROOT))); |
| 431 | themeGroup.add(themeButton); | 468 | themeGroup.add(themeButton); |
| 469 | |||
| 432 | if (lookAndFeel.equals(UiConfig.getLookAndFeel())) { | 470 | if (lookAndFeel.equals(UiConfig.getLookAndFeel())) { |
| 433 | themeButton.setSelected(true); | 471 | themeButton.setSelected(true); |
| 434 | } | 472 | } |
| 473 | |||
| 435 | themeButton.addActionListener(_e -> { | 474 | themeButton.addActionListener(_e -> { |
| 436 | UiConfig.setLookAndFeel(lookAndFeel); | 475 | UiConfig.setLookAndFeel(lookAndFeel); |
| 437 | UiConfig.save(); | 476 | UiConfig.save(); |
| @@ -443,12 +482,15 @@ public class MenuBar { | |||
| 443 | 482 | ||
| 444 | private static void prepareLanguagesMenu(JMenu languagesMenu) { | 483 | private static void prepareLanguagesMenu(JMenu languagesMenu) { |
| 445 | ButtonGroup languageGroup = new ButtonGroup(); | 484 | ButtonGroup languageGroup = new ButtonGroup(); |
| 485 | |||
| 446 | for (String lang : I18n.getAvailableLanguages()) { | 486 | for (String lang : I18n.getAvailableLanguages()) { |
| 447 | JRadioButtonMenuItem languageButton = new JRadioButtonMenuItem(I18n.getLanguageName(lang)); | 487 | JRadioButtonMenuItem languageButton = new JRadioButtonMenuItem(I18n.getLanguageName(lang)); |
| 448 | languageGroup.add(languageButton); | 488 | languageGroup.add(languageButton); |
| 489 | |||
| 449 | if (lang.equals(UiConfig.getLanguage())) { | 490 | if (lang.equals(UiConfig.getLanguage())) { |
| 450 | languageButton.setSelected(true); | 491 | languageButton.setSelected(true); |
| 451 | } | 492 | } |
| 493 | |||
| 452 | languageButton.addActionListener(event -> { | 494 | languageButton.addActionListener(event -> { |
| 453 | UiConfig.setLanguage(lang); | 495 | UiConfig.setLanguage(lang); |
| 454 | I18n.setLanguage(lang); | 496 | I18n.setLanguage(lang); |
| @@ -461,25 +503,25 @@ public class MenuBar { | |||
| 461 | 503 | ||
| 462 | private static void prepareScaleMenu(JMenu scaleMenu, Gui gui) { | 504 | private static void prepareScaleMenu(JMenu scaleMenu, Gui gui) { |
| 463 | ButtonGroup scaleGroup = new ButtonGroup(); | 505 | ButtonGroup scaleGroup = new ButtonGroup(); |
| 464 | Map<Float, JRadioButtonMenuItem> scaleButtons = IntStream.of(100, 125, 150, 175, 200) | 506 | Map<Float, JRadioButtonMenuItem> scaleButtons = IntStream.of(100, 125, 150, 175, 200).mapToObj(scaleFactor -> { |
| 465 | .mapToObj(scaleFactor -> { | 507 | float realScaleFactor = scaleFactor / 100f; |
| 466 | float realScaleFactor = scaleFactor / 100f; | 508 | JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(String.format("%d%%", scaleFactor)); |
| 467 | JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(String.format("%d%%", scaleFactor)); | 509 | menuItem.addActionListener(event -> ScaleUtil.setScaleFactor(realScaleFactor)); |
| 468 | menuItem.addActionListener(event -> ScaleUtil.setScaleFactor(realScaleFactor)); | 510 | menuItem.addActionListener(event -> ChangeDialog.show(gui.getFrame())); |
| 469 | menuItem.addActionListener(event -> ChangeDialog.show(gui.getFrame())); | 511 | scaleGroup.add(menuItem); |
| 470 | scaleGroup.add(menuItem); | 512 | scaleMenu.add(menuItem); |
| 471 | scaleMenu.add(menuItem); | 513 | return new Pair<>(realScaleFactor, menuItem); |
| 472 | return new Pair<>(realScaleFactor, menuItem); | 514 | }).collect(Collectors.toMap(x -> x.a, x -> x.b)); |
| 473 | }) | ||
| 474 | .collect(Collectors.toMap(x -> x.a, x -> x.b)); | ||
| 475 | 515 | ||
| 476 | JRadioButtonMenuItem currentScaleButton = scaleButtons.get(UiConfig.getScaleFactor()); | 516 | JRadioButtonMenuItem currentScaleButton = scaleButtons.get(UiConfig.getScaleFactor()); |
| 517 | |||
| 477 | if (currentScaleButton != null) { | 518 | if (currentScaleButton != null) { |
| 478 | currentScaleButton.setSelected(true); | 519 | currentScaleButton.setSelected(true); |
| 479 | } | 520 | } |
| 480 | 521 | ||
| 481 | ScaleUtil.addListener((newScale, _oldScale) -> { | 522 | ScaleUtil.addListener((newScale, _oldScale) -> { |
| 482 | JRadioButtonMenuItem mi = scaleButtons.get(newScale); | 523 | JRadioButtonMenuItem mi = scaleButtons.get(newScale); |
| 524 | |||
| 483 | if (mi != null) { | 525 | if (mi != null) { |
| 484 | mi.setSelected(true); | 526 | mi.setSelected(true); |
| 485 | } else { | 527 | } else { |
| @@ -487,5 +529,4 @@ public class MenuBar { | |||
| 487 | } | 529 | } |
| 488 | }); | 530 | }); |
| 489 | } | 531 | } |
| 490 | |||
| 491 | } | 532 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java index 0c667c00..48404a1c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/StatusBar.java | |||
| @@ -54,7 +54,7 @@ public class StatusBar { | |||
| 54 | * | 54 | * |
| 55 | * @param message the message to display | 55 | * @param message the message to display |
| 56 | * @param timeout the timeout in milliseconds to wait until clearing the | 56 | * @param timeout the timeout in milliseconds to wait until clearing the |
| 57 | * message; if 0, the message is not automatically cleared | 57 | * message; if 0, the message is not automatically cleared |
| 58 | */ | 58 | */ |
| 59 | public void showMessage(String message, int timeout) { | 59 | public void showMessage(String message, int timeout) { |
| 60 | this.timer.stop(); | 60 | this.timer.stop(); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java index 02e1bc39..4329cae0 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatablePasswordField.java | |||
| @@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage; | |||
| 14 | import cuchaz.enigma.utils.validation.Validatable; | 14 | import cuchaz.enigma.utils.validation.Validatable; |
| 15 | 15 | ||
| 16 | public class ValidatablePasswordField extends JPasswordField implements Validatable { | 16 | public class ValidatablePasswordField extends JPasswordField implements Validatable { |
| 17 | |||
| 18 | private List<ParameterizedMessage> messages = new ArrayList<>(); | 17 | private List<ParameterizedMessage> messages = new ArrayList<>(); |
| 19 | private String tooltipText = null; | 18 | private String tooltipText = null; |
| 20 | 19 | ||
| @@ -92,5 +91,4 @@ public class ValidatablePasswordField extends JPasswordField implements Validata | |||
| 92 | super.paint(g); | 91 | super.paint(g); |
| 93 | ValidatableUi.drawMarker(this, g, messages); | 92 | ValidatableUi.drawMarker(this, g, messages); |
| 94 | } | 93 | } |
| 95 | |||
| 96 | } | 94 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java index 7d1f8665..2d5e2295 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextArea.java | |||
| @@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage; | |||
| 14 | import cuchaz.enigma.utils.validation.Validatable; | 14 | import cuchaz.enigma.utils.validation.Validatable; |
| 15 | 15 | ||
| 16 | public class ValidatableTextArea extends JTextArea implements Validatable { | 16 | public class ValidatableTextArea extends JTextArea implements Validatable { |
| 17 | |||
| 18 | private List<ParameterizedMessage> messages = new ArrayList<>(); | 17 | private List<ParameterizedMessage> messages = new ArrayList<>(); |
| 19 | private String tooltipText = null; | 18 | private String tooltipText = null; |
| 20 | 19 | ||
| @@ -96,5 +95,4 @@ public class ValidatableTextArea extends JTextArea implements Validatable { | |||
| 96 | super.paint(g); | 95 | super.paint(g); |
| 97 | ValidatableUi.drawMarker(this, g, messages); | 96 | ValidatableUi.drawMarker(this, g, messages); |
| 98 | } | 97 | } |
| 99 | |||
| 100 | } | 98 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java index c114dc17..be658d59 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableTextField.java | |||
| @@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.ParameterizedMessage; | |||
| 14 | import cuchaz.enigma.utils.validation.Validatable; | 14 | import cuchaz.enigma.utils.validation.Validatable; |
| 15 | 15 | ||
| 16 | public class ValidatableTextField extends JTextField implements Validatable { | 16 | public class ValidatableTextField extends JTextField implements Validatable { |
| 17 | |||
| 18 | private List<ParameterizedMessage> messages = new ArrayList<>(); | 17 | private List<ParameterizedMessage> messages = new ArrayList<>(); |
| 19 | private String tooltipText = null; | 18 | private String tooltipText = null; |
| 20 | 19 | ||
| @@ -92,5 +91,4 @@ public class ValidatableTextField extends JTextField implements Validatable { | |||
| 92 | super.paint(g); | 91 | super.paint(g); |
| 93 | ValidatableUi.drawMarker(this, g, messages); | 92 | ValidatableUi.drawMarker(this, g, messages); |
| 94 | } | 93 | } |
| 95 | |||
| 96 | } | 94 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java index 5df63486..b8b8431b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ValidatableUi.java | |||
| @@ -13,26 +13,29 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 13 | import cuchaz.enigma.utils.validation.ParameterizedMessage; | 13 | import cuchaz.enigma.utils.validation.ParameterizedMessage; |
| 14 | 14 | ||
| 15 | public final class ValidatableUi { | 15 | public final class ValidatableUi { |
| 16 | |||
| 17 | private ValidatableUi() { | 16 | private ValidatableUi() { |
| 18 | } | 17 | } |
| 19 | 18 | ||
| 20 | public static String getTooltipText(String tooltipText, List<ParameterizedMessage> messages) { | 19 | public static String getTooltipText(String tooltipText, List<ParameterizedMessage> messages) { |
| 21 | List<String> strings = new ArrayList<>(); | 20 | List<String> strings = new ArrayList<>(); |
| 21 | |||
| 22 | if (tooltipText != null) { | 22 | if (tooltipText != null) { |
| 23 | strings.add(tooltipText); | 23 | strings.add(tooltipText); |
| 24 | } | 24 | } |
| 25 | |||
| 25 | if (!messages.isEmpty()) { | 26 | if (!messages.isEmpty()) { |
| 26 | strings.add("Error(s): "); | 27 | strings.add("Error(s): "); |
| 27 | 28 | ||
| 28 | messages.forEach(msg -> { | 29 | messages.forEach(msg -> { |
| 29 | strings.add(String.format(" - %s", msg.getText())); | 30 | strings.add(String.format(" - %s", msg.getText())); |
| 30 | String longDesc = msg.getLongText(); | 31 | String longDesc = msg.getLongText(); |
| 32 | |||
| 31 | if (!longDesc.isEmpty()) { | 33 | if (!longDesc.isEmpty()) { |
| 32 | Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); | 34 | Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); |
| 33 | } | 35 | } |
| 34 | }); | 36 | }); |
| 35 | } | 37 | } |
| 38 | |||
| 36 | if (strings.isEmpty()) { | 39 | if (strings.isEmpty()) { |
| 37 | return null; | 40 | return null; |
| 38 | } else { | 41 | } else { |
| @@ -49,11 +52,13 @@ public final class ValidatableUi { | |||
| 49 | messages.forEach(msg -> { | 52 | messages.forEach(msg -> { |
| 50 | strings.add(String.format(" - %s", msg.getText())); | 53 | strings.add(String.format(" - %s", msg.getText())); |
| 51 | String longDesc = msg.getLongText(); | 54 | String longDesc = msg.getLongText(); |
| 55 | |||
| 52 | if (!longDesc.isEmpty()) { | 56 | if (!longDesc.isEmpty()) { |
| 53 | Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); | 57 | Arrays.stream(longDesc.split("\n")).map(s -> String.format(" %s", s)).forEach(strings::add); |
| 54 | } | 58 | } |
| 55 | }); | 59 | }); |
| 56 | } | 60 | } |
| 61 | |||
| 57 | if (strings.isEmpty()) { | 62 | if (strings.isEmpty()) { |
| 58 | return null; | 63 | return null; |
| 59 | } else { | 64 | } else { |
| @@ -63,6 +68,7 @@ public final class ValidatableUi { | |||
| 63 | 68 | ||
| 64 | public static void drawMarker(Component self, Graphics g, List<ParameterizedMessage> messages) { | 69 | public static void drawMarker(Component self, Graphics g, List<ParameterizedMessage> messages) { |
| 65 | Color color = ValidatableUi.getMarkerColor(messages); | 70 | Color color = ValidatableUi.getMarkerColor(messages); |
| 71 | |||
| 66 | if (color != null) { | 72 | if (color != null) { |
| 67 | g.setColor(color); | 73 | g.setColor(color); |
| 68 | int x1 = self.getWidth() - ScaleUtil.scale(8) - 1; | 74 | int x1 = self.getWidth() - ScaleUtil.scale(8) - 1; |
| @@ -75,33 +81,32 @@ public final class ValidatableUi { | |||
| 75 | 81 | ||
| 76 | @Nullable | 82 | @Nullable |
| 77 | public static Color getMarkerColor(List<ParameterizedMessage> messages) { | 83 | public static Color getMarkerColor(List<ParameterizedMessage> messages) { |
| 78 | int level = messages.stream() | 84 | int level = messages.stream().mapToInt(ValidatableUi::getMessageLevel).max().orElse(0); |
| 79 | .mapToInt(ValidatableUi::getMessageLevel) | ||
| 80 | .max().orElse(0); | ||
| 81 | 85 | ||
| 82 | switch (level) { | 86 | switch (level) { |
| 83 | case 0: | 87 | case 0: |
| 84 | return null; | 88 | return null; |
| 85 | case 1: | 89 | case 1: |
| 86 | return Color.BLUE; | 90 | return Color.BLUE; |
| 87 | case 2: | 91 | case 2: |
| 88 | return Color.ORANGE; | 92 | return Color.ORANGE; |
| 89 | case 3: | 93 | case 3: |
| 90 | return Color.RED; | 94 | return Color.RED; |
| 91 | } | 95 | } |
| 96 | |||
| 92 | throw new IllegalStateException("unreachable"); | 97 | throw new IllegalStateException("unreachable"); |
| 93 | } | 98 | } |
| 94 | 99 | ||
| 95 | private static int getMessageLevel(ParameterizedMessage message) { | 100 | private static int getMessageLevel(ParameterizedMessage message) { |
| 96 | switch (message.message.type) { | 101 | switch (message.message.type) { |
| 97 | case INFO: | 102 | case INFO: |
| 98 | return 1; | 103 | return 1; |
| 99 | case WARNING: | 104 | case WARNING: |
| 100 | return 2; | 105 | return 2; |
| 101 | case ERROR: | 106 | case ERROR: |
| 102 | return 3; | 107 | return 3; |
| 103 | } | 108 | } |
| 109 | |||
| 104 | throw new IllegalStateException("unreachable"); | 110 | throw new IllegalStateException("unreachable"); |
| 105 | } | 111 | } |
| 106 | |||
| 107 | } | 112 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java index 6e17fec1..d9ec95c2 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ConvertingTextFieldListener.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.gui.events; | |||
| 3 | import cuchaz.enigma.gui.elements.ConvertingTextField; | 3 | import cuchaz.enigma.gui.elements.ConvertingTextField; |
| 4 | 4 | ||
| 5 | public interface ConvertingTextFieldListener { | 5 | public interface ConvertingTextFieldListener { |
| 6 | |||
| 7 | default void onStartEditing(ConvertingTextField field) { | 6 | default void onStartEditing(ConvertingTextField field) { |
| 8 | } | 7 | } |
| 9 | 8 | ||
| @@ -13,5 +12,4 @@ public interface ConvertingTextFieldListener { | |||
| 13 | 12 | ||
| 14 | default void onStopEditing(ConvertingTextField field, boolean abort) { | 13 | default void onStopEditing(ConvertingTextField field, boolean abort) { |
| 15 | } | 14 | } |
| 16 | |||
| 17 | } | 15 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java index 48c9ec4b..1651abf0 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/EditorActionListener.java | |||
| @@ -7,7 +7,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | 7 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 8 | 8 | ||
| 9 | public interface EditorActionListener { | 9 | public interface EditorActionListener { |
| 10 | |||
| 11 | default void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) { | 10 | default void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) { |
| 12 | } | 11 | } |
| 13 | 12 | ||
| @@ -16,5 +15,4 @@ public interface EditorActionListener { | |||
| 16 | 15 | ||
| 17 | default void onTitleChanged(EditorPanel editor, String title) { | 16 | default void onTitleChanged(EditorPanel editor, String title) { |
| 18 | } | 17 | } |
| 19 | |||
| 20 | } | 18 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java index 10d7ce1c..e2054b29 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/events/ThemeChangeListener.java | |||
| @@ -7,7 +7,5 @@ import cuchaz.enigma.gui.highlight.BoxHighlightPainter; | |||
| 7 | import cuchaz.enigma.source.RenamableTokenType; | 7 | import cuchaz.enigma.source.RenamableTokenType; |
| 8 | 8 | ||
| 9 | public interface ThemeChangeListener { | 9 | public interface ThemeChangeListener { |
| 10 | |||
| 11 | void onThemeChanged(LookAndFeel lookAndFeel, Map<RenamableTokenType, BoxHighlightPainter> boxHighlightPainters); | 10 | void onThemeChanged(LookAndFeel lookAndFeel, Map<RenamableTokenType, BoxHighlightPainter> boxHighlightPainters); |
| 12 | |||
| 13 | } | 11 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java index 2d8d76a7..a97b3779 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.highlight; | 12 | package cuchaz.enigma.gui.highlight; |
| 13 | 13 | ||
| @@ -67,5 +67,4 @@ public class BoxHighlightPainter implements Highlighter.HighlightPainter { | |||
| 67 | g.setColor(this.borderColor); | 67 | g.setColor(this.borderColor); |
| 68 | g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); | 68 | g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); |
| 69 | } | 69 | } |
| 70 | |||
| 71 | } | 70 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java index 22d64201..a807802d 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java | |||
| @@ -1,17 +1,21 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.highlight; | 12 | package cuchaz.enigma.gui.highlight; |
| 13 | 13 | ||
| 14 | import java.awt.*; | 14 | import java.awt.BasicStroke; |
| 15 | import java.awt.Graphics; | ||
| 16 | import java.awt.Graphics2D; | ||
| 17 | import java.awt.Rectangle; | ||
| 18 | import java.awt.Shape; | ||
| 15 | 19 | ||
| 16 | import javax.swing.text.Highlighter; | 20 | import javax.swing.text.Highlighter; |
| 17 | import javax.swing.text.JTextComponent; | 21 | import javax.swing.text.JTextComponent; |
| @@ -19,7 +23,6 @@ import javax.swing.text.JTextComponent; | |||
| 19 | import cuchaz.enigma.gui.config.UiConfig; | 23 | import cuchaz.enigma.gui.config.UiConfig; |
| 20 | 24 | ||
| 21 | public class SelectionHighlightPainter implements Highlighter.HighlightPainter { | 25 | public class SelectionHighlightPainter implements Highlighter.HighlightPainter { |
| 22 | |||
| 23 | public static final SelectionHighlightPainter INSTANCE = new SelectionHighlightPainter(); | 26 | public static final SelectionHighlightPainter INSTANCE = new SelectionHighlightPainter(); |
| 24 | 27 | ||
| 25 | @Override | 28 | @Override |
| @@ -31,5 +34,4 @@ public class SelectionHighlightPainter implements Highlighter.HighlightPainter { | |||
| 31 | g2d.setStroke(new BasicStroke(2.0f)); | 34 | g2d.setStroke(new BasicStroke(2.0f)); |
| 32 | g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); | 35 | g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); |
| 33 | } | 36 | } |
| 34 | |||
| 35 | } | 37 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java index 898529a4..1dcdeabf 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/newabstraction/EntryValidation.java | |||
| @@ -6,17 +6,16 @@ import cuchaz.enigma.utils.validation.Message; | |||
| 6 | import cuchaz.enigma.utils.validation.ValidationContext; | 6 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 7 | 7 | ||
| 8 | public class EntryValidation { | 8 | public class EntryValidation { |
| 9 | |||
| 10 | public static boolean validateJavadoc(ValidationContext vc, String javadoc) { | 9 | public static boolean validateJavadoc(ValidationContext vc, String javadoc) { |
| 11 | if (javadoc.contains("*/")) { | 10 | if (javadoc.contains("*/")) { |
| 12 | vc.raise(Message.ILLEGAL_DOC_COMMENT_END); | 11 | vc.raise(Message.ILLEGAL_DOC_COMMENT_END); |
| 13 | return false; | 12 | return false; |
| 14 | } | 13 | } |
| 14 | |||
| 15 | return true; | 15 | return true; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry<?> entry, String newName) { | 18 | public static boolean validateRename(ValidationContext vc, EnigmaProject p, Entry<?> entry, String newName) { |
| 19 | return p.getMapper().getValidator().validateRename(vc, entry, newName); | 19 | return p.getMapper().getValidator().validateRename(vc, entry, newName); |
| 20 | } | 20 | } |
| 21 | |||
| 22 | } | 21 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java index 922f8f24..f931a93f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java | |||
| @@ -1,22 +1,21 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.node; | 12 | package cuchaz.enigma.gui.node; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 15 | |||
| 16 | import javax.swing.tree.DefaultMutableTreeNode; | 14 | import javax.swing.tree.DefaultMutableTreeNode; |
| 17 | 15 | ||
| 18 | public class ClassSelectorClassNode extends DefaultMutableTreeNode { | 16 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | 17 | ||
| 18 | public class ClassSelectorClassNode extends DefaultMutableTreeNode { | ||
| 20 | private final ClassEntry obfEntry; | 19 | private final ClassEntry obfEntry; |
| 21 | private ClassEntry classEntry; | 20 | private ClassEntry classEntry; |
| 22 | 21 | ||
| @@ -57,12 +56,17 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode { | |||
| 57 | @Override | 56 | @Override |
| 58 | public void setUserObject(Object userObject) { | 57 | public void setUserObject(Object userObject) { |
| 59 | String packageName = ""; | 58 | String packageName = ""; |
| 60 | if (classEntry.getPackageName() != null) | 59 | |
| 60 | if (classEntry.getPackageName() != null) { | ||
| 61 | packageName = classEntry.getPackageName() + "/"; | 61 | packageName = classEntry.getPackageName() + "/"; |
| 62 | if (userObject instanceof String) | 62 | } |
| 63 | |||
| 64 | if (userObject instanceof String) { | ||
| 63 | this.classEntry = new ClassEntry(packageName + userObject); | 65 | this.classEntry = new ClassEntry(packageName + userObject); |
| 64 | else if (userObject instanceof ClassEntry) | 66 | } else if (userObject instanceof ClassEntry) { |
| 65 | this.classEntry = (ClassEntry) userObject; | 67 | this.classEntry = (ClassEntry) userObject; |
| 68 | } | ||
| 69 | |||
| 66 | super.setUserObject(classEntry); | 70 | super.setUserObject(classEntry); |
| 67 | } | 71 | } |
| 68 | 72 | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java index c1c7d387..dfcbd8c1 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java | |||
| @@ -1,22 +1,21 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.node; | 12 | package cuchaz.enigma.gui.node; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 15 | |||
| 16 | import javax.swing.tree.DefaultMutableTreeNode; | 14 | import javax.swing.tree.DefaultMutableTreeNode; |
| 17 | 15 | ||
| 18 | public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | 16 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | 17 | ||
| 18 | public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | ||
| 20 | private String packageName; | 19 | private String packageName; |
| 21 | 20 | ||
| 22 | public ClassSelectorPackageNode(String packageName) { | 21 | public ClassSelectorPackageNode(String packageName) { |
| @@ -34,8 +33,10 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | |||
| 34 | 33 | ||
| 35 | @Override | 34 | @Override |
| 36 | public void setUserObject(Object userObject) { | 35 | public void setUserObject(Object userObject) { |
| 37 | if (userObject instanceof String) | 36 | if (userObject instanceof String) { |
| 38 | this.packageName = (String) userObject; | 37 | this.packageName = (String) userObject; |
| 38 | } | ||
| 39 | |||
| 39 | super.setUserObject(userObject); | 40 | super.setUserObject(userObject); |
| 40 | } | 41 | } |
| 41 | 42 | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java index fe5c8578..dca714dd 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ClosableTabTitlePane.java | |||
| @@ -9,12 +9,17 @@ import java.awt.event.MouseEvent; | |||
| 9 | 9 | ||
| 10 | import javax.accessibility.AccessibleContext; | 10 | import javax.accessibility.AccessibleContext; |
| 11 | import javax.annotation.Nullable; | 11 | import javax.annotation.Nullable; |
| 12 | import javax.swing.*; | 12 | import javax.swing.JButton; |
| 13 | import javax.swing.JComponent; | ||
| 14 | import javax.swing.JLabel; | ||
| 15 | import javax.swing.JPanel; | ||
| 16 | import javax.swing.JTabbedPane; | ||
| 17 | import javax.swing.SwingUtilities; | ||
| 18 | import javax.swing.UIManager; | ||
| 13 | import javax.swing.border.EmptyBorder; | 19 | import javax.swing.border.EmptyBorder; |
| 14 | import javax.swing.event.ChangeListener; | 20 | import javax.swing.event.ChangeListener; |
| 15 | 21 | ||
| 16 | public class ClosableTabTitlePane { | 22 | public class ClosableTabTitlePane { |
| 17 | |||
| 18 | private final JPanel ui; | 23 | private final JPanel ui; |
| 19 | private final JButton closeButton; | 24 | private final JButton closeButton; |
| 20 | private final JLabel label; | 25 | private final JLabel label; |
| @@ -66,19 +71,7 @@ public class ClosableTabTitlePane { | |||
| 66 | if (parent != null) { | 71 | if (parent != null) { |
| 67 | Point pt = new Point(e.getXOnScreen(), e.getYOnScreen()); | 72 | Point pt = new Point(e.getXOnScreen(), e.getYOnScreen()); |
| 68 | SwingUtilities.convertPointFromScreen(pt, parent); | 73 | SwingUtilities.convertPointFromScreen(pt, parent); |
| 69 | MouseEvent e1 = new MouseEvent( | 74 | MouseEvent e1 = new MouseEvent(parent, e.getID(), e.getWhen(), e.getModifiersEx(), (int) pt.getX(), (int) pt.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); |
| 70 | parent, | ||
| 71 | e.getID(), | ||
| 72 | e.getWhen(), | ||
| 73 | e.getModifiersEx(), | ||
| 74 | (int) pt.getX(), | ||
| 75 | (int) pt.getY(), | ||
| 76 | e.getXOnScreen(), | ||
| 77 | e.getYOnScreen(), | ||
| 78 | e.getClickCount(), | ||
| 79 | e.isPopupTrigger(), | ||
| 80 | e.getButton() | ||
| 81 | ); | ||
| 82 | parent.dispatchEvent(e1); | 75 | parent.dispatchEvent(e1); |
| 83 | } | 76 | } |
| 84 | } | 77 | } |
| @@ -91,11 +84,13 @@ public class ClosableTabTitlePane { | |||
| 91 | if (this.parent != null) { | 84 | if (this.parent != null) { |
| 92 | pane.removeChangeListener(cachedChangeListener); | 85 | pane.removeChangeListener(cachedChangeListener); |
| 93 | } | 86 | } |
| 87 | |||
| 94 | if (pane != null) { | 88 | if (pane != null) { |
| 95 | updateState(pane); | 89 | updateState(pane); |
| 96 | cachedChangeListener = e -> updateState(pane); | 90 | cachedChangeListener = e -> updateState(pane); |
| 97 | pane.addChangeListener(cachedChangeListener); | 91 | pane.addChangeListener(cachedChangeListener); |
| 98 | } | 92 | } |
| 93 | |||
| 99 | this.parent = pane; | 94 | this.parent = pane; |
| 100 | } | 95 | } |
| 101 | 96 | ||
| @@ -123,11 +118,12 @@ public class ClosableTabTitlePane { | |||
| 123 | public static ClosableTabTitlePane byUi(Component c) { | 118 | public static ClosableTabTitlePane byUi(Component c) { |
| 124 | if (c instanceof JComponent) { | 119 | if (c instanceof JComponent) { |
| 125 | Object prop = ((JComponent) c).getClientProperty(ClosableTabTitlePane.class); | 120 | Object prop = ((JComponent) c).getClientProperty(ClosableTabTitlePane.class); |
| 121 | |||
| 126 | if (prop instanceof ClosableTabTitlePane) { | 122 | if (prop instanceof ClosableTabTitlePane) { |
| 127 | return (ClosableTabTitlePane) prop; | 123 | return (ClosableTabTitlePane) prop; |
| 128 | } | 124 | } |
| 129 | } | 125 | } |
| 126 | |||
| 130 | return null; | 127 | return null; |
| 131 | } | 128 | } |
| 132 | |||
| 133 | } | 129 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java index 10fc5e1a..5d1d0f2b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java | |||
| @@ -15,7 +15,6 @@ import cuchaz.enigma.gui.util.GuiUtil; | |||
| 15 | import cuchaz.enigma.utils.I18n; | 15 | import cuchaz.enigma.utils.I18n; |
| 16 | 16 | ||
| 17 | public class DeobfPanel extends JPanel { | 17 | public class DeobfPanel extends JPanel { |
| 18 | |||
| 19 | public final ClassSelector deobfClasses; | 18 | public final ClassSelector deobfClasses; |
| 20 | private final JLabel title = new JLabel(); | 19 | private final JLabel title = new JLabel(); |
| 21 | 20 | ||
| @@ -44,6 +43,7 @@ public class DeobfPanel extends JPanel { | |||
| 44 | if (SwingUtilities.isRightMouseButton(e)) { | 43 | if (SwingUtilities.isRightMouseButton(e)) { |
| 45 | deobfClasses.setSelectionRow(deobfClasses.getClosestRowForLocation(e.getX(), e.getY())); | 44 | deobfClasses.setSelectionRow(deobfClasses.getClosestRowForLocation(e.getX(), e.getY())); |
| 46 | int i = deobfClasses.getRowForPath(deobfClasses.getSelectionPath()); | 45 | int i = deobfClasses.getRowForPath(deobfClasses.getSelectionPath()); |
| 46 | |||
| 47 | if (i != -1) { | 47 | if (i != -1) { |
| 48 | deobfPanelPopupMenu.show(deobfClasses, e.getX(), e.getY()); | 48 | deobfPanelPopupMenu.show(deobfClasses, e.getX(), e.getY()); |
| 49 | } | 49 | } |
| @@ -54,5 +54,4 @@ public class DeobfPanel extends JPanel { | |||
| 54 | this.title.setText(I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.deobfuscated")); | 54 | this.title.setText(I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.deobfuscated")); |
| 55 | this.deobfPanelPopupMenu.retranslateUi(); | 55 | this.deobfPanelPopupMenu.retranslateUi(); |
| 56 | } | 56 | } |
| 57 | |||
| 58 | } | 57 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java index f4b190bc..cb74ceca 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/EditorPanel.java | |||
| @@ -1,14 +1,35 @@ | |||
| 1 | package cuchaz.enigma.gui.panels; | 1 | package cuchaz.enigma.gui.panels; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.Color; |
| 4 | import java.awt.event.*; | 4 | import java.awt.Component; |
| 5 | import java.awt.Font; | ||
| 6 | import java.awt.GridBagConstraints; | ||
| 7 | import java.awt.GridBagLayout; | ||
| 8 | import java.awt.GridLayout; | ||
| 9 | import java.awt.Rectangle; | ||
| 10 | import java.awt.event.ActionEvent; | ||
| 11 | import java.awt.event.ActionListener; | ||
| 12 | import java.awt.event.KeyAdapter; | ||
| 13 | import java.awt.event.KeyEvent; | ||
| 14 | import java.awt.event.MouseAdapter; | ||
| 15 | import java.awt.event.MouseEvent; | ||
| 5 | import java.util.ArrayList; | 16 | import java.util.ArrayList; |
| 6 | import java.util.Collection; | 17 | import java.util.Collection; |
| 7 | import java.util.List; | 18 | import java.util.List; |
| 8 | import java.util.Map; | 19 | import java.util.Map; |
| 9 | 20 | ||
| 10 | import javax.annotation.Nullable; | 21 | import javax.annotation.Nullable; |
| 11 | import javax.swing.*; | 22 | import javax.swing.JButton; |
| 23 | import javax.swing.JComponent; | ||
| 24 | import javax.swing.JEditorPane; | ||
| 25 | import javax.swing.JLabel; | ||
| 26 | import javax.swing.JPanel; | ||
| 27 | import javax.swing.JProgressBar; | ||
| 28 | import javax.swing.JScrollPane; | ||
| 29 | import javax.swing.JSeparator; | ||
| 30 | import javax.swing.JTextArea; | ||
| 31 | import javax.swing.SwingUtilities; | ||
| 32 | import javax.swing.Timer; | ||
| 12 | import javax.swing.text.BadLocationException; | 33 | import javax.swing.text.BadLocationException; |
| 13 | import javax.swing.text.Document; | 34 | import javax.swing.text.Document; |
| 14 | import javax.swing.text.Highlighter.HighlightPainter; | 35 | import javax.swing.text.Highlighter.HighlightPainter; |
| @@ -46,7 +67,6 @@ import cuchaz.enigma.utils.I18n; | |||
| 46 | import cuchaz.enigma.utils.Result; | 67 | import cuchaz.enigma.utils.Result; |
| 47 | 68 | ||
| 48 | public class EditorPanel { | 69 | public class EditorPanel { |
| 49 | |||
| 50 | private final JPanel ui = new JPanel(); | 70 | private final JPanel ui = new JPanel(); |
| 51 | private final JEditorPane editor = new JEditorPane(); | 71 | private final JEditorPane editor = new JEditorPane(); |
| 52 | private final JScrollPane editorScrollPane = new JScrollPane(this.editor); | 72 | private final JScrollPane editorScrollPane = new JScrollPane(this.editor); |
| @@ -123,18 +143,19 @@ public class EditorPanel { | |||
| 123 | @Override | 143 | @Override |
| 124 | public void mouseReleased(MouseEvent e) { | 144 | public void mouseReleased(MouseEvent e) { |
| 125 | switch (e.getButton()) { | 145 | switch (e.getButton()) { |
| 126 | case MouseEvent.BUTTON3: // Right click | 146 | case MouseEvent.BUTTON3: // Right click |
| 127 | EditorPanel.this.editor.setCaretPosition(EditorPanel.this.editor.viewToModel(e.getPoint())); | 147 | EditorPanel.this.editor.setCaretPosition(EditorPanel.this.editor.viewToModel(e.getPoint())); |
| 128 | break; | 148 | break; |
| 129 | 149 | ||
| 130 | case 4: // Back navigation | 150 | case 4: // Back navigation |
| 131 | gui.getController().openPreviousReference(); | 151 | gui.getController().openPreviousReference(); |
| 132 | break; | 152 | break; |
| 133 | 153 | ||
| 134 | case 5: // Forward navigation | 154 | case 5: // Forward navigation |
| 135 | gui.getController().openNextReference(); | 155 | gui.getController().openNextReference(); |
| 136 | break; | 156 | break; |
| 137 | } | 157 | } |
| 158 | |||
| 138 | EditorPanel.this.mouseIsPressed = false; | 159 | EditorPanel.this.mouseIsPressed = false; |
| 139 | } | 160 | } |
| 140 | }); | 161 | }); |
| @@ -143,31 +164,36 @@ public class EditorPanel { | |||
| 143 | public void keyPressed(KeyEvent event) { | 164 | public void keyPressed(KeyEvent event) { |
| 144 | if (event.isControlDown()) { | 165 | if (event.isControlDown()) { |
| 145 | EditorPanel.this.shouldNavigateOnClick = false; | 166 | EditorPanel.this.shouldNavigateOnClick = false; |
| 146 | if (EditorPanel.this.popupMenu.handleKeyEvent(event)) return; | 167 | |
| 168 | if (EditorPanel.this.popupMenu.handleKeyEvent(event)) { | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 147 | switch (event.getKeyCode()) { | 172 | switch (event.getKeyCode()) { |
| 148 | case KeyEvent.VK_F5: | 173 | case KeyEvent.VK_F5: |
| 149 | if (EditorPanel.this.classHandle != null) { | 174 | if (EditorPanel.this.classHandle != null) { |
| 150 | EditorPanel.this.classHandle.invalidate(); | 175 | EditorPanel.this.classHandle.invalidate(); |
| 151 | } | 176 | } |
| 152 | break; | 177 | |
| 153 | 178 | break; | |
| 154 | case KeyEvent.VK_F: | 179 | |
| 155 | // prevent navigating on click when quick find activated | 180 | case KeyEvent.VK_F: |
| 156 | break; | 181 | // prevent navigating on click when quick find activated |
| 157 | 182 | break; | |
| 158 | case KeyEvent.VK_ADD: | 183 | |
| 159 | case KeyEvent.VK_EQUALS: | 184 | case KeyEvent.VK_ADD: |
| 160 | case KeyEvent.VK_PLUS: | 185 | case KeyEvent.VK_EQUALS: |
| 161 | offsetEditorZoom(2); | 186 | case KeyEvent.VK_PLUS: |
| 162 | break; | 187 | offsetEditorZoom(2); |
| 163 | case KeyEvent.VK_SUBTRACT: | 188 | break; |
| 164 | case KeyEvent.VK_MINUS: | 189 | case KeyEvent.VK_SUBTRACT: |
| 165 | offsetEditorZoom(-2); | 190 | case KeyEvent.VK_MINUS: |
| 166 | break; | 191 | offsetEditorZoom(-2); |
| 167 | 192 | break; | |
| 168 | default: | 193 | |
| 169 | EditorPanel.this.shouldNavigateOnClick = true; // CTRL | 194 | default: |
| 170 | break; | 195 | EditorPanel.this.shouldNavigateOnClick = true; // CTRL |
| 196 | break; | ||
| 171 | } | 197 | } |
| 172 | } | 198 | } |
| 173 | } | 199 | } |
| @@ -175,8 +201,14 @@ public class EditorPanel { | |||
| 175 | @Override | 201 | @Override |
| 176 | public void keyTyped(KeyEvent event) { | 202 | public void keyTyped(KeyEvent event) { |
| 177 | EntryReference<Entry<?>, Entry<?>> ref = EditorPanel.this.getCursorReference(); | 203 | EntryReference<Entry<?>, Entry<?>> ref = EditorPanel.this.getCursorReference(); |
| 178 | if (ref == null) return; | 204 | |
| 179 | if (!EditorPanel.this.controller.project.isRenamable(ref)) return; | 205 | if (ref == null) { |
| 206 | return; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (!EditorPanel.this.controller.project.isRenamable(ref)) { | ||
| 210 | return; | ||
| 211 | } | ||
| 180 | 212 | ||
| 181 | if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) { | 213 | if (!event.isControlDown() && !event.isAltDown() && Character.isJavaIdentifierPart(event.getKeyChar())) { |
| 182 | EnigmaProject project = gui.getController().project; | 214 | EnigmaProject project = gui.getController().project; |
| @@ -184,8 +216,10 @@ public class EditorPanel { | |||
| 184 | Entry<?> entry = reference.getNameableEntry(); | 216 | Entry<?> entry = reference.getNameableEntry(); |
| 185 | 217 | ||
| 186 | String name = String.valueOf(event.getKeyChar()); | 218 | String name = String.valueOf(event.getKeyChar()); |
| 219 | |||
| 187 | if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) { | 220 | if (entry instanceof ClassEntry && ((ClassEntry) entry).getParent() == null) { |
| 188 | String packageName = ((ClassEntry) entry).getPackageName(); | 221 | String packageName = ((ClassEntry) entry).getPackageName(); |
| 222 | |||
| 189 | if (packageName != null) { | 223 | if (packageName != null) { |
| 190 | name = packageName + "/" + name; | 224 | name = packageName + "/" + name; |
| 191 | } | 225 | } |
| @@ -207,12 +241,14 @@ public class EditorPanel { | |||
| 207 | if ((this.editorLaf == null || this.editorLaf != laf)) { | 241 | if ((this.editorLaf == null || this.editorLaf != laf)) { |
| 208 | this.editor.updateUI(); | 242 | this.editor.updateUI(); |
| 209 | this.editor.setBackground(UiConfig.getEditorBackgroundColor()); | 243 | this.editor.setBackground(UiConfig.getEditorBackgroundColor()); |
| 244 | |||
| 210 | if (this.editorLaf != null) { | 245 | if (this.editorLaf != null) { |
| 211 | this.classHandle.invalidateMapped(); | 246 | this.classHandle.invalidateMapped(); |
| 212 | } | 247 | } |
| 213 | 248 | ||
| 214 | this.editorLaf = laf; | 249 | this.editorLaf = laf; |
| 215 | } | 250 | } |
| 251 | |||
| 216 | this.boxHighlightPainters = boxHighlightPainters; | 252 | this.boxHighlightPainters = boxHighlightPainters; |
| 217 | }; | 253 | }; |
| 218 | 254 | ||
| @@ -223,19 +259,23 @@ public class EditorPanel { | |||
| 223 | public static EditorPanel byUi(Component ui) { | 259 | public static EditorPanel byUi(Component ui) { |
| 224 | if (ui instanceof JComponent) { | 260 | if (ui instanceof JComponent) { |
| 225 | Object prop = ((JComponent) ui).getClientProperty(EditorPanel.class); | 261 | Object prop = ((JComponent) ui).getClientProperty(EditorPanel.class); |
| 262 | |||
| 226 | if (prop instanceof EditorPanel) { | 263 | if (prop instanceof EditorPanel) { |
| 227 | return (EditorPanel) prop; | 264 | return (EditorPanel) prop; |
| 228 | } | 265 | } |
| 229 | } | 266 | } |
| 267 | |||
| 230 | return null; | 268 | return null; |
| 231 | } | 269 | } |
| 232 | 270 | ||
| 233 | public void setClassHandle(ClassHandle handle) { | 271 | public void setClassHandle(ClassHandle handle) { |
| 234 | ClassEntry old = null; | 272 | ClassEntry old = null; |
| 273 | |||
| 235 | if (this.classHandle != null) { | 274 | if (this.classHandle != null) { |
| 236 | old = this.classHandle.getRef(); | 275 | old = this.classHandle.getRef(); |
| 237 | this.classHandle.close(); | 276 | this.classHandle.close(); |
| 238 | } | 277 | } |
| 278 | |||
| 239 | setClassHandle0(old, handle); | 279 | setClassHandle0(old, handle); |
| 240 | } | 280 | } |
| 241 | 281 | ||
| @@ -299,53 +339,61 @@ public class EditorPanel { | |||
| 299 | } else { | 339 | } else { |
| 300 | this.displayError(res.unwrapErr()); | 340 | this.displayError(res.unwrapErr()); |
| 301 | } | 341 | } |
| 342 | |||
| 302 | this.nextReference = null; | 343 | this.nextReference = null; |
| 303 | }); | 344 | }); |
| 304 | } | 345 | } |
| 305 | 346 | ||
| 306 | public void displayError(ClassHandleError t) { | 347 | public void displayError(ClassHandleError t) { |
| 307 | this.setDisplayMode(DisplayMode.ERRORED); | 348 | this.setDisplayMode(DisplayMode.ERRORED); |
| 349 | |||
| 308 | String str = switch (t.type) { | 350 | String str = switch (t.type) { |
| 309 | case DECOMPILE -> "editor.decompile_error"; | 351 | case DECOMPILE -> "editor.decompile_error"; |
| 310 | case REMAP -> "editor.remap_error"; | 352 | case REMAP -> "editor.remap_error"; |
| 311 | }; | 353 | }; |
| 354 | |||
| 312 | this.errorLabel.setText(I18n.translate(str)); | 355 | this.errorLabel.setText(I18n.translate(str)); |
| 313 | this.errorTextArea.setText(t.getStackTrace()); | 356 | this.errorTextArea.setText(t.getStackTrace()); |
| 314 | this.errorTextArea.setCaretPosition(0); | 357 | this.errorTextArea.setCaretPosition(0); |
| 315 | } | 358 | } |
| 316 | 359 | ||
| 317 | public void setDisplayMode(DisplayMode mode) { | 360 | public void setDisplayMode(DisplayMode mode) { |
| 318 | if (this.mode == mode) return; | 361 | if (this.mode == mode) { |
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 319 | this.ui.removeAll(); | 365 | this.ui.removeAll(); |
| 366 | |||
| 320 | switch (mode) { | 367 | switch (mode) { |
| 321 | case INACTIVE: | 368 | case INACTIVE: |
| 322 | break; | 369 | break; |
| 323 | case IN_PROGRESS: { | 370 | case IN_PROGRESS: { |
| 324 | // make progress bar start from the left every time | 371 | // make progress bar start from the left every time |
| 325 | this.decompilingProgressBar.setIndeterminate(false); | 372 | this.decompilingProgressBar.setIndeterminate(false); |
| 326 | this.decompilingProgressBar.setIndeterminate(true); | 373 | this.decompilingProgressBar.setIndeterminate(true); |
| 327 | 374 | ||
| 328 | this.ui.setLayout(new GridBagLayout()); | 375 | this.ui.setLayout(new GridBagLayout()); |
| 329 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2); | 376 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2); |
| 330 | this.ui.add(this.decompilingLabel, cb.pos(0, 0).anchor(GridBagConstraints.SOUTH).build()); | 377 | this.ui.add(this.decompilingLabel, cb.pos(0, 0).anchor(GridBagConstraints.SOUTH).build()); |
| 331 | this.ui.add(this.decompilingProgressBar, cb.pos(0, 1).anchor(GridBagConstraints.NORTH).build()); | 378 | this.ui.add(this.decompilingProgressBar, cb.pos(0, 1).anchor(GridBagConstraints.NORTH).build()); |
| 332 | break; | 379 | break; |
| 333 | } | 380 | } |
| 334 | case SUCCESS: { | 381 | case SUCCESS: { |
| 335 | this.ui.setLayout(new GridLayout(1, 1, 0, 0)); | 382 | this.ui.setLayout(new GridLayout(1, 1, 0, 0)); |
| 336 | this.ui.add(this.editorScrollPane); | 383 | this.ui.add(this.editorScrollPane); |
| 337 | break; | 384 | break; |
| 338 | } | 385 | } |
| 339 | case ERRORED: { | 386 | case ERRORED: { |
| 340 | this.ui.setLayout(new GridBagLayout()); | 387 | this.ui.setLayout(new GridBagLayout()); |
| 341 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST); | 388 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).weight(1.0, 0.0).anchor(GridBagConstraints.WEST); |
| 342 | this.ui.add(this.errorLabel, cb.pos(0, 0).build()); | 389 | this.ui.add(this.errorLabel, cb.pos(0, 0).build()); |
| 343 | this.ui.add(new JSeparator(JSeparator.HORIZONTAL), cb.pos(0, 1).fill(GridBagConstraints.HORIZONTAL).build()); | 390 | this.ui.add(new JSeparator(JSeparator.HORIZONTAL), cb.pos(0, 1).fill(GridBagConstraints.HORIZONTAL).build()); |
| 344 | this.ui.add(this.errorScrollPane, cb.pos(0, 2).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).build()); | 391 | this.ui.add(this.errorScrollPane, cb.pos(0, 2).weight(1.0, 1.0).fill(GridBagConstraints.BOTH).build()); |
| 345 | this.ui.add(this.retryButton, cb.pos(0, 3).weight(0.0, 0.0).anchor(GridBagConstraints.EAST).build()); | 392 | this.ui.add(this.retryButton, cb.pos(0, 3).weight(0.0, 0.0).anchor(GridBagConstraints.EAST).build()); |
| 346 | break; | 393 | break; |
| 347 | } | 394 | } |
| 348 | } | 395 | } |
| 396 | |||
| 349 | this.ui.validate(); | 397 | this.ui.validate(); |
| 350 | this.ui.repaint(); | 398 | this.ui.repaint(); |
| 351 | this.mode = mode; | 399 | this.mode = mode; |
| @@ -353,6 +401,7 @@ public class EditorPanel { | |||
| 353 | 401 | ||
| 354 | public void offsetEditorZoom(int zoomAmount) { | 402 | public void offsetEditorZoom(int zoomAmount) { |
| 355 | int newResult = this.fontSize + zoomAmount; | 403 | int newResult = this.fontSize + zoomAmount; |
| 404 | |||
| 356 | if (newResult > 8 && newResult < 72) { | 405 | if (newResult > 8 && newResult < 72) { |
| 357 | this.fontSize = newResult; | 406 | this.fontSize = newResult; |
| 358 | this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); | 407 | this.editor.setFont(ScaleUtil.getFont(this.editor.getFont().getFontName(), Font.PLAIN, this.fontSize)); |
| @@ -365,8 +414,13 @@ public class EditorPanel { | |||
| 365 | } | 414 | } |
| 366 | 415 | ||
| 367 | public void onCaretMove(int pos, boolean fromClick) { | 416 | public void onCaretMove(int pos, boolean fromClick) { |
| 368 | if (this.settingSource) return; | 417 | if (this.settingSource) { |
| 369 | if (this.controller.project == null) return; | 418 | return; |
| 419 | } | ||
| 420 | |||
| 421 | if (this.controller.project == null) { | ||
| 422 | return; | ||
| 423 | } | ||
| 370 | 424 | ||
| 371 | EntryRemapper mapper = this.controller.project.getMapper(); | 425 | EntryRemapper mapper = this.controller.project.getMapper(); |
| 372 | Token token = getToken(pos); | 426 | Token token = getToken(pos); |
| @@ -378,10 +432,12 @@ public class EditorPanel { | |||
| 378 | if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) { | 432 | if (referenceEntry != null && this.shouldNavigateOnClick && fromClick) { |
| 379 | this.shouldNavigateOnClick = false; | 433 | this.shouldNavigateOnClick = false; |
| 380 | Entry<?> navigationEntry = referenceEntry; | 434 | Entry<?> navigationEntry = referenceEntry; |
| 435 | |||
| 381 | if (this.cursorReference.context == null) { | 436 | if (this.cursorReference.context == null) { |
| 382 | EntryResolver resolver = mapper.getObfResolver(); | 437 | EntryResolver resolver = mapper.getObfResolver(); |
| 383 | navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT); | 438 | navigationEntry = resolver.resolveFirstEntry(referenceEntry, ResolutionStrategy.RESOLVE_ROOT); |
| 384 | } | 439 | } |
| 440 | |||
| 385 | this.controller.navigateTo(navigationEntry); | 441 | this.controller.navigateTo(navigationEntry); |
| 386 | } | 442 | } |
| 387 | } | 443 | } |
| @@ -398,6 +454,7 @@ public class EditorPanel { | |||
| 398 | if (this.source == null) { | 454 | if (this.source == null) { |
| 399 | return null; | 455 | return null; |
| 400 | } | 456 | } |
| 457 | |||
| 401 | return this.source.getIndex().getReferenceToken(pos); | 458 | return this.source.getIndex().getReferenceToken(pos); |
| 402 | } | 459 | } |
| 403 | 460 | ||
| @@ -406,16 +463,22 @@ public class EditorPanel { | |||
| 406 | if (this.source == null) { | 463 | if (this.source == null) { |
| 407 | return null; | 464 | return null; |
| 408 | } | 465 | } |
| 466 | |||
| 409 | return this.source.getIndex().getReference(token); | 467 | return this.source.getIndex().getReference(token); |
| 410 | } | 468 | } |
| 411 | 469 | ||
| 412 | public void setSource(DecompiledClassSource source) { | 470 | public void setSource(DecompiledClassSource source) { |
| 413 | this.setDisplayMode(DisplayMode.SUCCESS); | 471 | this.setDisplayMode(DisplayMode.SUCCESS); |
| 414 | if (source == null) return; | 472 | |
| 473 | if (source == null) { | ||
| 474 | return; | ||
| 475 | } | ||
| 476 | |||
| 415 | try { | 477 | try { |
| 416 | this.settingSource = true; | 478 | this.settingSource = true; |
| 417 | 479 | ||
| 418 | int newCaretPos = 0; | 480 | int newCaretPos = 0; |
| 481 | |||
| 419 | if (this.source != null && this.source.getEntry().equals(source.getEntry())) { | 482 | if (this.source != null && this.source.getEntry().equals(source.getEntry())) { |
| 420 | int caretPos = this.editor.getCaretPosition(); | 483 | int caretPos = this.editor.getCaretPosition(); |
| 421 | 484 | ||
| @@ -441,9 +504,11 @@ public class EditorPanel { | |||
| 441 | this.source = source; | 504 | this.source = source; |
| 442 | this.editor.getHighlighter().removeAllHighlights(); | 505 | this.editor.getHighlighter().removeAllHighlights(); |
| 443 | this.editor.setText(source.toString()); | 506 | this.editor.setText(source.toString()); |
| 507 | |||
| 444 | if (this.source != null) { | 508 | if (this.source != null) { |
| 445 | this.editor.setCaretPosition(newCaretPos); | 509 | this.editor.setCaretPosition(newCaretPos); |
| 446 | } | 510 | } |
| 511 | |||
| 447 | setHighlightedTokens(source.getHighlightedTokens()); | 512 | setHighlightedTokens(source.getHighlightedTokens()); |
| 448 | setCursorReference(getReference(getToken(this.editor.getCaretPosition()))); | 513 | setCursorReference(getReference(getToken(this.editor.getCaretPosition()))); |
| 449 | } finally { | 514 | } finally { |
| @@ -515,10 +580,16 @@ public class EditorPanel { | |||
| 515 | * @param reference | 580 | * @param reference |
| 516 | */ | 581 | */ |
| 517 | private void showReference0(EntryReference<Entry<?>, Entry<?>> reference) { | 582 | private void showReference0(EntryReference<Entry<?>, Entry<?>> reference) { |
| 518 | if (this.source == null) return; | 583 | if (this.source == null) { |
| 519 | if (reference == null) return; | 584 | return; |
| 585 | } | ||
| 586 | |||
| 587 | if (reference == null) { | ||
| 588 | return; | ||
| 589 | } | ||
| 520 | 590 | ||
| 521 | List<Token> tokens = this.controller.getTokensForReference(this.source, reference); | 591 | List<Token> tokens = this.controller.getTokensForReference(this.source, reference); |
| 592 | |||
| 522 | if (tokens.isEmpty()) { | 593 | if (tokens.isEmpty()) { |
| 523 | // DEBUG | 594 | // DEBUG |
| 524 | System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef())); | 595 | System.err.println(String.format("WARNING: no tokens found for %s in %s", reference, this.classHandle.getRef())); |
| @@ -531,6 +602,7 @@ public class EditorPanel { | |||
| 531 | if (token == null) { | 602 | if (token == null) { |
| 532 | throw new IllegalArgumentException("Token cannot be null!"); | 603 | throw new IllegalArgumentException("Token cannot be null!"); |
| 533 | } | 604 | } |
| 605 | |||
| 534 | navigateToToken(token, SelectionHighlightPainter.INSTANCE); | 606 | navigateToToken(token, SelectionHighlightPainter.INSTANCE); |
| 535 | } | 607 | } |
| 536 | 608 | ||
| @@ -546,9 +618,11 @@ public class EditorPanel { | |||
| 546 | // make sure the token is visible in the scroll window | 618 | // make sure the token is visible in the scroll window |
| 547 | Rectangle start = this.editor.modelToView(token.start); | 619 | Rectangle start = this.editor.modelToView(token.start); |
| 548 | Rectangle end = this.editor.modelToView(token.end); | 620 | Rectangle end = this.editor.modelToView(token.end); |
| 621 | |||
| 549 | if (start == null || end == null) { | 622 | if (start == null || end == null) { |
| 550 | return; | 623 | return; |
| 551 | } | 624 | } |
| 625 | |||
| 552 | Rectangle show = start.union(end); | 626 | Rectangle show = start.union(end); |
| 553 | show.grow(start.width * 10, start.height * 6); | 627 | show.grow(start.width * 10, start.height * 6); |
| 554 | SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show)); | 628 | SwingUtilities.invokeLater(() -> this.editor.scrollRectToVisible(show)); |
| @@ -625,5 +699,4 @@ public class EditorPanel { | |||
| 625 | SUCCESS, | 699 | SUCCESS, |
| 626 | ERRORED, | 700 | ERRORED, |
| 627 | } | 701 | } |
| 628 | |||
| 629 | } | 702 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java index e71894db..7b75f1a8 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/IdentifierPanel.java | |||
| @@ -25,12 +25,15 @@ import cuchaz.enigma.gui.util.ScaleUtil; | |||
| 25 | import cuchaz.enigma.translation.mapping.AccessModifier; | 25 | import cuchaz.enigma.translation.mapping.AccessModifier; |
| 26 | import cuchaz.enigma.translation.mapping.EntryChange; | 26 | import cuchaz.enigma.translation.mapping.EntryChange; |
| 27 | import cuchaz.enigma.translation.mapping.EntryMapping; | 27 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 28 | import cuchaz.enigma.translation.representation.entry.*; | 28 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 29 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 30 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 31 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 32 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 29 | import cuchaz.enigma.utils.I18n; | 33 | import cuchaz.enigma.utils.I18n; |
| 30 | import cuchaz.enigma.utils.validation.ValidationContext; | 34 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 31 | 35 | ||
| 32 | public class IdentifierPanel { | 36 | public class IdentifierPanel { |
| 33 | |||
| 34 | private final Gui gui; | 37 | private final Gui gui; |
| 35 | 38 | ||
| 36 | private final JPanel ui = new JPanel(); | 39 | private final JPanel ui = new JPanel(); |
| @@ -57,7 +60,9 @@ public class IdentifierPanel { | |||
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | public boolean startRenaming() { | 62 | public boolean startRenaming() { |
| 60 | if (this.nameField == null) return false; | 63 | if (this.nameField == null) { |
| 64 | return false; | ||
| 65 | } | ||
| 61 | 66 | ||
| 62 | this.nameField.startEditing(); | 67 | this.nameField.startEditing(); |
| 63 | 68 | ||
| @@ -65,7 +70,9 @@ public class IdentifierPanel { | |||
| 65 | } | 70 | } |
| 66 | 71 | ||
| 67 | public boolean startRenaming(String text) { | 72 | public boolean startRenaming(String text) { |
| 68 | if (this.nameField == null) return false; | 73 | if (this.nameField == null) { |
| 74 | return false; | ||
| 75 | } | ||
| 69 | 76 | ||
| 70 | this.nameField.startEditing(); | 77 | this.nameField.startEditing(); |
| 71 | this.nameField.setEditText(text); | 78 | this.nameField.setEditText(text); |
| @@ -84,6 +91,7 @@ public class IdentifierPanel { | |||
| 84 | 91 | ||
| 85 | TableHelper th = new TableHelper(this.ui, this.entry, this.gui); | 92 | TableHelper th = new TableHelper(this.ui, this.entry, this.gui); |
| 86 | th.begin(); | 93 | th.begin(); |
| 94 | |||
| 87 | if (this.entry == null) { | 95 | if (this.entry == null) { |
| 88 | this.ui.setEnabled(false); | 96 | this.ui.setEnabled(false); |
| 89 | } else { | 97 | } else { |
| @@ -102,8 +110,10 @@ public class IdentifierPanel { | |||
| 102 | th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.FIELD, this::onModifierChanged); | 110 | th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.FIELD, this::onModifierChanged); |
| 103 | } else if (deobfEntry instanceof MethodEntry) { | 111 | } else if (deobfEntry instanceof MethodEntry) { |
| 104 | MethodEntry me = (MethodEntry) deobfEntry; | 112 | MethodEntry me = (MethodEntry) deobfEntry; |
| 113 | |||
| 105 | if (me.isConstructor()) { | 114 | if (me.isConstructor()) { |
| 106 | ClassEntry ce = me.getParent(); | 115 | ClassEntry ce = me.getParent(); |
| 116 | |||
| 107 | if (ce != null) { | 117 | if (ce != null) { |
| 108 | String name = ce.isInnerClass() ? ce.getName() : ce.getFullName(); | 118 | String name = ce.isInnerClass() ? ce.getName() : ce.getFullName(); |
| 109 | this.nameField = th.addRenameTextField(EditableType.CLASS, name); | 119 | this.nameField = th.addRenameTextField(EditableType.CLASS, name); |
| @@ -112,6 +122,7 @@ public class IdentifierPanel { | |||
| 112 | this.nameField = th.addRenameTextField(EditableType.METHOD, me.getName()); | 122 | this.nameField = th.addRenameTextField(EditableType.METHOD, me.getName()); |
| 113 | th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName()); | 123 | th.addStringRow(I18n.translate("info_panel.identifier.class"), me.getParent().getFullName()); |
| 114 | } | 124 | } |
| 125 | |||
| 115 | th.addCopiableStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString()); | 126 | th.addCopiableStringRow(I18n.translate("info_panel.identifier.method_descriptor"), me.getDesc().toString()); |
| 116 | th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.METHOD, this::onModifierChanged); | 127 | th.addModifierRow(I18n.translate("info_panel.identifier.modifier"), EditableType.METHOD, this::onModifierChanged); |
| 117 | } else if (deobfEntry instanceof LocalVariableEntry) { | 128 | } else if (deobfEntry instanceof LocalVariableEntry) { |
| @@ -132,6 +143,7 @@ public class IdentifierPanel { | |||
| 132 | throw new IllegalStateException("unreachable"); | 143 | throw new IllegalStateException("unreachable"); |
| 133 | } | 144 | } |
| 134 | } | 145 | } |
| 146 | |||
| 135 | th.end(); | 147 | th.end(); |
| 136 | 148 | ||
| 137 | if (this.nameField != null) { | 149 | if (this.nameField != null) { |
| @@ -139,6 +151,7 @@ public class IdentifierPanel { | |||
| 139 | @Override | 151 | @Override |
| 140 | public void onStartEditing(ConvertingTextField field) { | 152 | public void onStartEditing(ConvertingTextField field) { |
| 141 | int i = field.getText().lastIndexOf('/'); | 153 | int i = field.getText().lastIndexOf('/'); |
| 154 | |||
| 142 | if (i != -1) { | 155 | if (i != -1) { |
| 143 | field.selectSubstring(i + 1); | 156 | field.selectSubstring(i + 1); |
| 144 | } | 157 | } |
| @@ -146,7 +159,10 @@ public class IdentifierPanel { | |||
| 146 | 159 | ||
| 147 | @Override | 160 | @Override |
| 148 | public boolean tryStopEditing(ConvertingTextField field, boolean abort) { | 161 | public boolean tryStopEditing(ConvertingTextField field, boolean abort) { |
| 149 | if (abort) return true; | 162 | if (abort) { |
| 163 | return true; | ||
| 164 | } | ||
| 165 | |||
| 150 | vc.reset(); | 166 | vc.reset(); |
| 151 | vc.setActiveElement(field); | 167 | vc.setActiveElement(field); |
| 152 | validateRename(field.getText()); | 168 | validateRename(field.getText()); |
| @@ -162,6 +178,7 @@ public class IdentifierPanel { | |||
| 162 | } | 178 | } |
| 163 | 179 | ||
| 164 | EditorPanel e = gui.getActiveEditor(); | 180 | EditorPanel e = gui.getActiveEditor(); |
| 181 | |||
| 165 | if (e != null) { | 182 | if (e != null) { |
| 166 | e.getEditor().requestFocusInWindow(); | 183 | e.getEditor().requestFocusInWindow(); |
| 167 | } | 184 | } |
| @@ -192,13 +209,12 @@ public class IdentifierPanel { | |||
| 192 | } | 209 | } |
| 193 | 210 | ||
| 194 | private static final class TableHelper { | 211 | private static final class TableHelper { |
| 195 | |||
| 196 | private final Container c; | 212 | private final Container c; |
| 197 | private final Entry<?> e; | 213 | private final Entry<?> e; |
| 198 | private final Gui gui; | 214 | private final Gui gui; |
| 199 | private int row; | 215 | private int row; |
| 200 | 216 | ||
| 201 | public TableHelper(Container c, Entry<?> e, Gui gui) { | 217 | TableHelper(Container c, Entry<?> e, Gui gui) { |
| 202 | this.c = c; | 218 | this.c = c; |
| 203 | this.e = e; | 219 | this.e = e; |
| 204 | this.gui = gui; | 220 | this.gui = gui; |
| @@ -210,9 +226,7 @@ public class IdentifierPanel { | |||
| 210 | } | 226 | } |
| 211 | 227 | ||
| 212 | public void addRow(Component c1, Component c2) { | 228 | public void addRow(Component c1, Component c2) { |
| 213 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create() | 229 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(2).anchor(GridBagConstraints.WEST); |
| 214 | .insets(2) | ||
| 215 | .anchor(GridBagConstraints.WEST); | ||
| 216 | c.add(c1, cb.pos(0, this.row).build()); | 230 | c.add(c1, cb.pos(0, this.row).build()); |
| 217 | c.add(c2, cb.pos(1, this.row).weightX(1.0).fill(GridBagConstraints.HORIZONTAL).build()); | 231 | c.add(c2, cb.pos(1, this.row).weightX(1.0).fill(GridBagConstraints.HORIZONTAL).build()); |
| 218 | 232 | ||
| @@ -239,12 +253,12 @@ public class IdentifierPanel { | |||
| 239 | } | 253 | } |
| 240 | 254 | ||
| 241 | public ConvertingTextField addRenameTextField(EditableType type, String c2) { | 255 | public ConvertingTextField addRenameTextField(EditableType type, String c2) { |
| 242 | String description = switch(type) { | 256 | String description = switch (type) { |
| 243 | case CLASS -> I18n.translate("info_panel.identifier.class"); | 257 | case CLASS -> I18n.translate("info_panel.identifier.class"); |
| 244 | case METHOD -> I18n.translate("info_panel.identifier.method"); | 258 | case METHOD -> I18n.translate("info_panel.identifier.method"); |
| 245 | case FIELD -> I18n.translate("info_panel.identifier.field"); | 259 | case FIELD -> I18n.translate("info_panel.identifier.field"); |
| 246 | case PARAMETER, LOCAL_VARIABLE -> I18n.translate("info_panel.identifier.variable"); | 260 | case PARAMETER, LOCAL_VARIABLE -> I18n.translate("info_panel.identifier.variable"); |
| 247 | default -> throw new IllegalStateException("Unexpected value: " + type); | 261 | default -> throw new IllegalStateException("Unexpected value: " + type); |
| 248 | }; | 262 | }; |
| 249 | 263 | ||
| 250 | if (this.gui.getController().project.isRenamable(e)) { | 264 | if (this.gui.getController().project.isRenamable(e)) { |
| @@ -296,7 +310,5 @@ public class IdentifierPanel { | |||
| 296 | // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge | 310 | // Add an empty panel with y-weight=1 so that all the other elements get placed at the top edge |
| 297 | c.add(new JPanel(), GridBagConstraintsBuilder.create().pos(0, row).weight(0.0, 1.0).build()); | 311 | c.add(new JPanel(), GridBagConstraintsBuilder.create().pos(0, row).weight(0.0, 1.0).build()); |
| 298 | } | 312 | } |
| 299 | |||
| 300 | } | 313 | } |
| 301 | |||
| 302 | } | 314 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java index 7783843d..f82e6663 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java | |||
| @@ -13,7 +13,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 13 | import cuchaz.enigma.utils.I18n; | 13 | import cuchaz.enigma.utils.I18n; |
| 14 | 14 | ||
| 15 | public class ObfPanel extends JPanel { | 15 | public class ObfPanel extends JPanel { |
| 16 | |||
| 17 | public final ClassSelector obfClasses; | 16 | public final ClassSelector obfClasses; |
| 18 | private final JLabel title = new JLabel(); | 17 | private final JLabel title = new JLabel(); |
| 19 | 18 | ||
| @@ -25,9 +24,11 @@ public class ObfPanel extends JPanel { | |||
| 25 | Comparator<ClassEntry> obfClassComparator = (a, b) -> { | 24 | Comparator<ClassEntry> obfClassComparator = (a, b) -> { |
| 26 | String aname = a.getFullName(); | 25 | String aname = a.getFullName(); |
| 27 | String bname = b.getFullName(); | 26 | String bname = b.getFullName(); |
| 27 | |||
| 28 | if (aname.length() != bname.length()) { | 28 | if (aname.length() != bname.length()) { |
| 29 | return aname.length() - bname.length(); | 29 | return aname.length() - bname.length(); |
| 30 | } | 30 | } |
| 31 | |||
| 31 | return aname.compareTo(bname); | 32 | return aname.compareTo(bname); |
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| @@ -45,5 +46,4 @@ public class ObfPanel extends JPanel { | |||
| 45 | public void retranslateUi() { | 46 | public void retranslateUi() { |
| 46 | this.title.setText(I18n.translate("info_panel.classes.obfuscated")); | 47 | this.title.setText(I18n.translate("info_panel.classes.obfuscated")); |
| 47 | } | 48 | } |
| 48 | |||
| 49 | } | 49 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java index ccded45c..571c638f 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/StructurePanel.java | |||
| @@ -1,9 +1,16 @@ | |||
| 1 | package cuchaz.enigma.gui.panels; | 1 | package cuchaz.enigma.gui.panels; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.BorderLayout; |
| 4 | import java.awt.Component; | ||
| 5 | import java.awt.GridBagConstraints; | ||
| 6 | import java.awt.GridBagLayout; | ||
| 4 | import java.awt.event.MouseEvent; | 7 | import java.awt.event.MouseEvent; |
| 5 | 8 | ||
| 6 | import javax.swing.*; | 9 | import javax.swing.JComboBox; |
| 10 | import javax.swing.JLabel; | ||
| 11 | import javax.swing.JPanel; | ||
| 12 | import javax.swing.JScrollPane; | ||
| 13 | import javax.swing.JTree; | ||
| 7 | import javax.swing.tree.DefaultTreeCellRenderer; | 14 | import javax.swing.tree.DefaultTreeCellRenderer; |
| 8 | import javax.swing.tree.DefaultTreeModel; | 15 | import javax.swing.tree.DefaultTreeModel; |
| 9 | import javax.swing.tree.TreeNode; | 16 | import javax.swing.tree.TreeNode; |
| @@ -23,144 +30,144 @@ import cuchaz.enigma.translation.representation.entry.ParentedEntry; | |||
| 23 | import cuchaz.enigma.utils.I18n; | 30 | import cuchaz.enigma.utils.I18n; |
| 24 | 31 | ||
| 25 | public class StructurePanel { | 32 | public class StructurePanel { |
| 26 | private final Gui gui; | 33 | private final Gui gui; |
| 27 | 34 | ||
| 28 | private final JPanel panel = new JPanel(new BorderLayout()); | 35 | private final JPanel panel = new JPanel(new BorderLayout()); |
| 29 | 36 | ||
| 30 | private final JPanel optionsPanel; | 37 | private final JPanel optionsPanel; |
| 31 | 38 | ||
| 32 | private final JLabel obfuscationVisibilityLabel = new JLabel(); | 39 | private final JLabel obfuscationVisibilityLabel = new JLabel(); |
| 33 | private final JLabel documentationVisibilityLabel = new JLabel(); | 40 | private final JLabel documentationVisibilityLabel = new JLabel(); |
| 34 | private final JLabel sortingOrderLabel = new JLabel(); | 41 | private final JLabel sortingOrderLabel = new JLabel(); |
| 35 | 42 | ||
| 36 | private final JComboBox<StructureTreeOptions.ObfuscationVisibility> obfuscationVisibility; | 43 | private final JComboBox<StructureTreeOptions.ObfuscationVisibility> obfuscationVisibility; |
| 37 | private final JComboBox<StructureTreeOptions.DocumentationVisibility> documentationVisibility; | 44 | private final JComboBox<StructureTreeOptions.DocumentationVisibility> documentationVisibility; |
| 38 | private final JComboBox<StructureTreeOptions.SortingOrder> sortingOrder; | 45 | private final JComboBox<StructureTreeOptions.SortingOrder> sortingOrder; |
| 39 | 46 | ||
| 40 | private final JTree structureTree; | 47 | private final JTree structureTree; |
| 41 | 48 | ||
| 42 | public StructurePanel(Gui gui) { | 49 | public StructurePanel(Gui gui) { |
| 43 | this.gui = gui; | 50 | this.gui = gui; |
| 44 | 51 | ||
| 45 | this.optionsPanel = new JPanel(new GridBagLayout()); | 52 | this.optionsPanel = new JPanel(new GridBagLayout()); |
| 46 | this.optionsPanel.setVisible(false); | 53 | this.optionsPanel.setVisible(false); |
| 47 | 54 | ||
| 48 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(5).fill(GridBagConstraints.HORIZONTAL); | 55 | GridBagConstraintsBuilder cb = GridBagConstraintsBuilder.create().insets(5).fill(GridBagConstraints.HORIZONTAL); |
| 49 | 56 | ||
| 50 | this.optionsPanel.add(this.obfuscationVisibilityLabel, cb.pos(0, 0).build()); | 57 | this.optionsPanel.add(this.obfuscationVisibilityLabel, cb.pos(0, 0).build()); |
| 51 | this.obfuscationVisibility = new JComboBox<>(StructureTreeOptions.ObfuscationVisibility.values()); | 58 | this.obfuscationVisibility = new JComboBox<>(StructureTreeOptions.ObfuscationVisibility.values()); |
| 52 | this.obfuscationVisibility.setRenderer(new StructureOptionListCellRenderer()); | 59 | this.obfuscationVisibility.setRenderer(new StructureOptionListCellRenderer()); |
| 53 | this.obfuscationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); | 60 | this.obfuscationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); |
| 54 | this.optionsPanel.add(this.obfuscationVisibility, cb.pos(1, 0).build()); | 61 | this.optionsPanel.add(this.obfuscationVisibility, cb.pos(1, 0).build()); |
| 55 | 62 | ||
| 56 | this.optionsPanel.add(this.documentationVisibilityLabel, cb.pos(0, 1).build()); | 63 | this.optionsPanel.add(this.documentationVisibilityLabel, cb.pos(0, 1).build()); |
| 57 | this.documentationVisibility = new JComboBox<>(StructureTreeOptions.DocumentationVisibility.values()); | 64 | this.documentationVisibility = new JComboBox<>(StructureTreeOptions.DocumentationVisibility.values()); |
| 58 | this.documentationVisibility.setRenderer(new StructureOptionListCellRenderer()); | 65 | this.documentationVisibility.setRenderer(new StructureOptionListCellRenderer()); |
| 59 | this.documentationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); | 66 | this.documentationVisibility.addActionListener(event -> this.showStructure(gui.getActiveEditor())); |
| 60 | this.optionsPanel.add(this.documentationVisibility, cb.pos(1, 1).build()); | 67 | this.optionsPanel.add(this.documentationVisibility, cb.pos(1, 1).build()); |
| 61 | 68 | ||
| 62 | this.optionsPanel.add(this.sortingOrderLabel, cb.pos(0, 2).build()); | 69 | this.optionsPanel.add(this.sortingOrderLabel, cb.pos(0, 2).build()); |
| 63 | this.sortingOrder = new JComboBox<>(StructureTreeOptions.SortingOrder.values()); | 70 | this.sortingOrder = new JComboBox<>(StructureTreeOptions.SortingOrder.values()); |
| 64 | this.sortingOrder.setRenderer(new StructureOptionListCellRenderer()); | 71 | this.sortingOrder.setRenderer(new StructureOptionListCellRenderer()); |
| 65 | this.sortingOrder.addActionListener(event -> this.showStructure(gui.getActiveEditor())); | 72 | this.sortingOrder.addActionListener(event -> this.showStructure(gui.getActiveEditor())); |
| 66 | this.optionsPanel.add(this.sortingOrder, cb.pos(1, 2).build()); | 73 | this.optionsPanel.add(this.sortingOrder, cb.pos(1, 2).build()); |
| 67 | 74 | ||
| 68 | this.structureTree = new JTree(); | 75 | this.structureTree = new JTree(); |
| 69 | this.structureTree.setModel(null); | 76 | this.structureTree.setModel(null); |
| 70 | this.structureTree.setCellRenderer(new StructureTreeCellRenderer(gui)); | 77 | this.structureTree.setCellRenderer(new StructureTreeCellRenderer(gui)); |
| 71 | this.structureTree.setSelectionModel(new SingleTreeSelectionModel()); | 78 | this.structureTree.setSelectionModel(new SingleTreeSelectionModel()); |
| 72 | this.structureTree.setShowsRootHandles(true); | 79 | this.structureTree.setShowsRootHandles(true); |
| 73 | this.structureTree.addMouseListener(GuiUtil.onMouseClick(this::onClick)); | 80 | this.structureTree.addMouseListener(GuiUtil.onMouseClick(this::onClick)); |
| 74 | 81 | ||
| 75 | this.retranslateUi(); | 82 | this.retranslateUi(); |
| 76 | 83 | ||
| 77 | this.panel.add(this.optionsPanel, BorderLayout.NORTH); | 84 | this.panel.add(this.optionsPanel, BorderLayout.NORTH); |
| 78 | this.panel.add(new JScrollPane(this.structureTree)); | 85 | this.panel.add(new JScrollPane(this.structureTree)); |
| 79 | } | 86 | } |
| 80 | 87 | ||
| 81 | public void showStructure(EditorPanel editor) { | 88 | public void showStructure(EditorPanel editor) { |
| 82 | structureTree.setModel(null); | 89 | structureTree.setModel(null); |
| 83 | 90 | ||
| 84 | if (editor == null) { | 91 | if (editor == null) { |
| 85 | this.optionsPanel.setVisible(false); | 92 | this.optionsPanel.setVisible(false); |
| 86 | return; | 93 | return; |
| 87 | } | 94 | } |
| 88 | 95 | ||
| 89 | ClassEntry classEntry = editor.getClassHandle().getRef(); | 96 | ClassEntry classEntry = editor.getClassHandle().getRef(); |
| 90 | if (classEntry == null) return; | 97 | |
| 91 | 98 | if (classEntry == null) { | |
| 92 | this.optionsPanel.setVisible(true); | 99 | return; |
| 93 | 100 | } | |
| 94 | // get the class structure | 101 | |
| 95 | StructureTreeNode node = this.gui.getController().getClassStructure(classEntry, this.getOptions()); | 102 | this.optionsPanel.setVisible(true); |
| 96 | 103 | ||
| 97 | // show the tree at the root | 104 | // get the class structure |
| 98 | TreePath path = GuiUtil.getPathToRoot(node); | 105 | StructureTreeNode node = this.gui.getController().getClassStructure(classEntry, this.getOptions()); |
| 99 | structureTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); | 106 | |
| 100 | structureTree.expandPath(path); | 107 | // show the tree at the root |
| 101 | structureTree.setSelectionRow(structureTree.getRowForPath(path)); | 108 | TreePath path = GuiUtil.getPathToRoot(node); |
| 102 | } | 109 | structureTree.setModel(new DefaultTreeModel((TreeNode) path.getPathComponent(0))); |
| 103 | 110 | structureTree.expandPath(path); | |
| 104 | private void onClick(MouseEvent event) { | 111 | structureTree.setSelectionRow(structureTree.getRowForPath(path)); |
| 105 | if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { | 112 | } |
| 106 | // get the selected node | 113 | |
| 107 | TreePath path = structureTree.getSelectionPath(); | 114 | private void onClick(MouseEvent event) { |
| 108 | if (path == null) { | 115 | if (event.getClickCount() >= 2 && event.getButton() == MouseEvent.BUTTON1) { |
| 109 | return; | 116 | // get the selected node |
| 110 | } | 117 | TreePath path = structureTree.getSelectionPath(); |
| 111 | 118 | ||
| 112 | Object node = path.getLastPathComponent(); | 119 | if (path == null) { |
| 113 | 120 | return; | |
| 114 | if (node instanceof StructureTreeNode) { | 121 | } |
| 115 | this.gui.getController().navigateTo(((StructureTreeNode) node).getEntry()); | 122 | |
| 116 | } | 123 | Object node = path.getLastPathComponent(); |
| 117 | } | 124 | |
| 118 | } | 125 | if (node instanceof StructureTreeNode) { |
| 119 | 126 | this.gui.getController().navigateTo(((StructureTreeNode) node).getEntry()); | |
| 120 | /** | 127 | } |
| 121 | * Creates and returns the options of this structure panel. | 128 | } |
| 122 | */ | 129 | } |
| 123 | private StructureTreeOptions getOptions() { | 130 | |
| 124 | return new StructureTreeOptions( | 131 | /** |
| 125 | (StructureTreeOptions.ObfuscationVisibility) this.obfuscationVisibility.getSelectedItem(), | 132 | * Creates and returns the options of this structure panel. |
| 126 | (StructureTreeOptions.DocumentationVisibility) this.documentationVisibility.getSelectedItem(), | 133 | */ |
| 127 | (StructureTreeOptions.SortingOrder) this.sortingOrder.getSelectedItem() | 134 | private StructureTreeOptions getOptions() { |
| 128 | ); | 135 | return new StructureTreeOptions((StructureTreeOptions.ObfuscationVisibility) this.obfuscationVisibility.getSelectedItem(), (StructureTreeOptions.DocumentationVisibility) this.documentationVisibility.getSelectedItem(), (StructureTreeOptions.SortingOrder) this.sortingOrder.getSelectedItem()); |
| 129 | } | 136 | } |
| 130 | 137 | ||
| 131 | public void retranslateUi() { | 138 | public void retranslateUi() { |
| 132 | this.obfuscationVisibilityLabel.setText(I18n.translate("structure.options.obfuscation")); | 139 | this.obfuscationVisibilityLabel.setText(I18n.translate("structure.options.obfuscation")); |
| 133 | this.documentationVisibilityLabel.setText(I18n.translate("structure.options.documentation")); | 140 | this.documentationVisibilityLabel.setText(I18n.translate("structure.options.documentation")); |
| 134 | this.sortingOrderLabel.setText(I18n.translate("structure.options.sorting")); | 141 | this.sortingOrderLabel.setText(I18n.translate("structure.options.sorting")); |
| 135 | } | 142 | } |
| 136 | 143 | ||
| 137 | public JPanel getPanel() { | 144 | public JPanel getPanel() { |
| 138 | return this.panel; | 145 | return this.panel; |
| 139 | } | 146 | } |
| 140 | 147 | ||
| 141 | private static class StructureTreeCellRenderer extends DefaultTreeCellRenderer { | 148 | private static class StructureTreeCellRenderer extends DefaultTreeCellRenderer { |
| 142 | private final Gui gui; | 149 | private final Gui gui; |
| 143 | 150 | ||
| 144 | StructureTreeCellRenderer(Gui gui) { | 151 | StructureTreeCellRenderer(Gui gui) { |
| 145 | this.gui = gui; | 152 | this.gui = gui; |
| 146 | } | 153 | } |
| 147 | 154 | ||
| 148 | @Override | 155 | @Override |
| 149 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { | 156 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
| 150 | Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); | 157 | Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); |
| 151 | ParentedEntry<?> entry = ((StructureTreeNode) value).getEntry(); | 158 | ParentedEntry<?> entry = ((StructureTreeNode) value).getEntry(); |
| 152 | 159 | ||
| 153 | if (entry instanceof ClassEntry classEntry) { | 160 | if (entry instanceof ClassEntry classEntry) { |
| 154 | this.setIcon(GuiUtil.getClassIcon(gui, classEntry)); | 161 | this.setIcon(GuiUtil.getClassIcon(gui, classEntry)); |
| 155 | } else if (entry instanceof MethodEntry methodEntry) { | 162 | } else if (entry instanceof MethodEntry methodEntry) { |
| 156 | this.setIcon(GuiUtil.getMethodIcon(methodEntry)); | 163 | this.setIcon(GuiUtil.getMethodIcon(methodEntry)); |
| 157 | } else if (entry instanceof FieldEntry) { | 164 | } else if (entry instanceof FieldEntry) { |
| 158 | this.setIcon(GuiUtil.FIELD_ICON); | 165 | this.setIcon(GuiUtil.FIELD_ICON); |
| 159 | } | 166 | } |
| 160 | 167 | ||
| 161 | this.setText("<html>" + ((StructureTreeNode) value).toHtml()); | 168 | this.setText("<html>" + ((StructureTreeNode) value).toHtml()); |
| 162 | 169 | ||
| 163 | return c; | 170 | return c; |
| 164 | } | 171 | } |
| 165 | } | 172 | } |
| 166 | } | 173 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java index 0aa6510c..3791a1ec 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/CallsTreeCellRenderer.java | |||
| @@ -1,45 +1,51 @@ | |||
| 1 | package cuchaz.enigma.gui.renderer; | 1 | package cuchaz.enigma.gui.renderer; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.*; | 3 | import java.awt.Component; |
| 4 | |||
| 5 | import javax.swing.JTree; | ||
| 6 | import javax.swing.tree.DefaultTreeCellRenderer; | ||
| 7 | |||
| 8 | import cuchaz.enigma.analysis.ClassReferenceTreeNode; | ||
| 9 | import cuchaz.enigma.analysis.EntryReference; | ||
| 10 | import cuchaz.enigma.analysis.FieldReferenceTreeNode; | ||
| 11 | import cuchaz.enigma.analysis.MethodReferenceTreeNode; | ||
| 12 | import cuchaz.enigma.analysis.ReferenceTreeNode; | ||
| 4 | import cuchaz.enigma.gui.Gui; | 13 | import cuchaz.enigma.gui.Gui; |
| 5 | import cuchaz.enigma.gui.config.UiConfig; | 14 | import cuchaz.enigma.gui.config.UiConfig; |
| 6 | import cuchaz.enigma.gui.util.GuiUtil; | 15 | import cuchaz.enigma.gui.util.GuiUtil; |
| 7 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 16 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 8 | 17 | ||
| 9 | import javax.swing.*; | ||
| 10 | import javax.swing.tree.DefaultTreeCellRenderer; | ||
| 11 | import java.awt.*; | ||
| 12 | |||
| 13 | public class CallsTreeCellRenderer extends DefaultTreeCellRenderer { | 18 | public class CallsTreeCellRenderer extends DefaultTreeCellRenderer { |
| 14 | private final Gui gui; | 19 | private final Gui gui; |
| 15 | 20 | ||
| 16 | public CallsTreeCellRenderer(Gui gui) { | 21 | public CallsTreeCellRenderer(Gui gui) { |
| 17 | this.gui = gui; | 22 | this.gui = gui; |
| 18 | } | 23 | } |
| 19 | 24 | ||
| 20 | @Override | 25 | @Override |
| 21 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { | 26 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
| 22 | Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); | 27 | Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); |
| 23 | EntryReference<?, ?> reference = ((ReferenceTreeNode<?, ?>) value).getReference(); | 28 | EntryReference<?, ?> reference = ((ReferenceTreeNode<?, ?>) value).getReference(); |
| 24 | 29 | ||
| 25 | this.setForeground(UiConfig.getTextColor()); | 30 | this.setForeground(UiConfig.getTextColor()); |
| 26 | 31 | ||
| 27 | // if the node represents the method calling the entry | 32 | // if the node represents the method calling the entry |
| 28 | if (reference != null) { | 33 | if (reference != null) { |
| 29 | if (reference.context instanceof MethodEntry) { | 34 | if (reference.context instanceof MethodEntry) { |
| 30 | this.setIcon(GuiUtil.getMethodIcon((MethodEntry) reference.context)); | 35 | this.setIcon(GuiUtil.getMethodIcon((MethodEntry) reference.context)); |
| 31 | } | 36 | } |
| 32 | // if the node represents the called entry | 37 | |
| 33 | } else { | 38 | // if the node represents the called entry |
| 34 | if (value instanceof ClassReferenceTreeNode node) { | 39 | } else { |
| 35 | this.setIcon(GuiUtil.getClassIcon(this.gui, node.getEntry())); | 40 | if (value instanceof ClassReferenceTreeNode node) { |
| 36 | } else if (value instanceof MethodReferenceTreeNode node) { | 41 | this.setIcon(GuiUtil.getClassIcon(this.gui, node.getEntry())); |
| 37 | this.setIcon(GuiUtil.getMethodIcon(node.getEntry())); | 42 | } else if (value instanceof MethodReferenceTreeNode node) { |
| 38 | } else if (value instanceof FieldReferenceTreeNode) { | 43 | this.setIcon(GuiUtil.getMethodIcon(node.getEntry())); |
| 39 | this.setIcon(GuiUtil.FIELD_ICON); | 44 | } else if (value instanceof FieldReferenceTreeNode) { |
| 40 | } | 45 | this.setIcon(GuiUtil.FIELD_ICON); |
| 41 | } | 46 | } |
| 42 | 47 | } | |
| 43 | return c; | 48 | |
| 44 | } | 49 | return c; |
| 50 | } | ||
| 45 | } | 51 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java index 7bf39005..b4126c02 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/ImplementationsTreeCellRenderer.java | |||
| @@ -1,34 +1,35 @@ | |||
| 1 | package cuchaz.enigma.gui.renderer; | 1 | package cuchaz.enigma.gui.renderer; |
| 2 | 2 | ||
| 3 | import java.awt.Component; | ||
| 4 | |||
| 5 | import javax.swing.JTree; | ||
| 6 | import javax.swing.tree.DefaultTreeCellRenderer; | ||
| 7 | |||
| 3 | import cuchaz.enigma.analysis.ClassImplementationsTreeNode; | 8 | import cuchaz.enigma.analysis.ClassImplementationsTreeNode; |
| 4 | import cuchaz.enigma.analysis.MethodImplementationsTreeNode; | 9 | import cuchaz.enigma.analysis.MethodImplementationsTreeNode; |
| 5 | import cuchaz.enigma.gui.Gui; | 10 | import cuchaz.enigma.gui.Gui; |
| 6 | import cuchaz.enigma.gui.config.UiConfig; | 11 | import cuchaz.enigma.gui.config.UiConfig; |
| 7 | import cuchaz.enigma.gui.util.GuiUtil; | 12 | import cuchaz.enigma.gui.util.GuiUtil; |
| 8 | 13 | ||
| 9 | import javax.swing.*; | ||
| 10 | import javax.swing.tree.DefaultTreeCellRenderer; | ||
| 11 | import java.awt.*; | ||
| 12 | |||
| 13 | public class ImplementationsTreeCellRenderer extends DefaultTreeCellRenderer { | 14 | public class ImplementationsTreeCellRenderer extends DefaultTreeCellRenderer { |
| 14 | private final Gui gui; | 15 | private final Gui gui; |
| 15 | 16 | ||
| 16 | public ImplementationsTreeCellRenderer(Gui gui) { | 17 | public ImplementationsTreeCellRenderer(Gui gui) { |
| 17 | this.gui = gui; | 18 | this.gui = gui; |
| 18 | } | 19 | } |
| 19 | 20 | ||
| 20 | @Override | 21 | @Override |
| 21 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { | 22 | public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
| 22 | Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); | 23 | Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); |
| 23 | 24 | ||
| 24 | this.setForeground(UiConfig.getTextColor()); | 25 | this.setForeground(UiConfig.getTextColor()); |
| 25 | 26 | ||
| 26 | if (value instanceof ClassImplementationsTreeNode node) { | 27 | if (value instanceof ClassImplementationsTreeNode node) { |
| 27 | this.setIcon(GuiUtil.getClassIcon(this.gui, node.getClassEntry())); | 28 | this.setIcon(GuiUtil.getClassIcon(this.gui, node.getClassEntry())); |
| 28 | } else if (value instanceof MethodImplementationsTreeNode node) { | 29 | } else if (value instanceof MethodImplementationsTreeNode node) { |
| 29 | this.setIcon(GuiUtil.getMethodIcon(node.getMethodEntry())); | 30 | this.setIcon(GuiUtil.getMethodIcon(node.getMethodEntry())); |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | return c; | 33 | return c; |
| 33 | } | 34 | } |
| 34 | } | 35 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java index a1025531..04bf0f93 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/InheritanceTreeCellRenderer.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.gui.renderer; | 12 | package cuchaz.enigma.gui.renderer; |
| 13 | 13 | ||
| @@ -37,6 +37,7 @@ public class InheritanceTreeCellRenderer extends DefaultTreeCellRenderer { | |||
| 37 | if (!(value instanceof MethodInheritanceTreeNode node) || node.isImplemented()) { | 37 | if (!(value instanceof MethodInheritanceTreeNode node) || node.isImplemented()) { |
| 38 | ret.setForeground(UiConfig.getTextColor()); | 38 | ret.setForeground(UiConfig.getTextColor()); |
| 39 | ret.setFont(ret.getFont().deriveFont(Font.PLAIN)); | 39 | ret.setFont(ret.getFont().deriveFont(Font.PLAIN)); |
| 40 | |||
| 40 | if (value instanceof ClassInheritanceTreeNode) { | 41 | if (value instanceof ClassInheritanceTreeNode) { |
| 41 | this.setIcon(GuiUtil.getClassIcon(this.gui, ((ClassInheritanceTreeNode) value).getClassEntry())); | 42 | this.setIcon(GuiUtil.getClassIcon(this.gui, ((ClassInheritanceTreeNode) value).getClassEntry())); |
| 42 | } else if (value instanceof MethodInheritanceTreeNode) { | 43 | } else if (value instanceof MethodInheritanceTreeNode) { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java index b6ae0c50..123990e4 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/MessageListCellRenderer.java | |||
| @@ -10,15 +10,15 @@ import cuchaz.enigma.network.Message; | |||
| 10 | // For now, just render the translated text. | 10 | // For now, just render the translated text. |
| 11 | // TODO: Icons or something later? | 11 | // TODO: Icons or something later? |
| 12 | public class MessageListCellRenderer extends DefaultListCellRenderer { | 12 | public class MessageListCellRenderer extends DefaultListCellRenderer { |
| 13 | |||
| 14 | @Override | 13 | @Override |
| 15 | public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { | 14 | public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
| 16 | super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | 15 | super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); |
| 17 | Message message = (Message) value; | 16 | Message message = (Message) value; |
| 17 | |||
| 18 | if (message != null) { | 18 | if (message != null) { |
| 19 | setText(message.translate()); | 19 | setText(message.translate()); |
| 20 | } | 20 | } |
| 21 | |||
| 21 | return this; | 22 | return this; |
| 22 | } | 23 | } |
| 23 | |||
| 24 | } | 24 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java index f9a1cae6..09cdc9bd 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/renderer/StructureOptionListCellRenderer.java | |||
| @@ -1,21 +1,22 @@ | |||
| 1 | package cuchaz.enigma.gui.renderer; | 1 | package cuchaz.enigma.gui.renderer; |
| 2 | 2 | ||
| 3 | import java.awt.Component; | ||
| 4 | |||
| 5 | import javax.swing.DefaultListCellRenderer; | ||
| 6 | import javax.swing.JList; | ||
| 7 | |||
| 3 | import cuchaz.enigma.analysis.StructureTreeOptions; | 8 | import cuchaz.enigma.analysis.StructureTreeOptions; |
| 4 | import cuchaz.enigma.utils.I18n; | 9 | import cuchaz.enigma.utils.I18n; |
| 5 | 10 | ||
| 6 | import javax.swing.*; | ||
| 7 | import java.awt.*; | ||
| 8 | |||
| 9 | public class StructureOptionListCellRenderer extends DefaultListCellRenderer { | 11 | public class StructureOptionListCellRenderer extends DefaultListCellRenderer { |
| 12 | @Override | ||
| 13 | public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { | ||
| 14 | Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | ||
| 10 | 15 | ||
| 11 | @Override | 16 | if (value instanceof StructureTreeOptions.Option option) { |
| 12 | public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { | 17 | this.setText(I18n.translate(option.getTranslationKey())); |
| 13 | Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | 18 | } |
| 14 | |||
| 15 | if (value instanceof StructureTreeOptions.Option option) { | ||
| 16 | this.setText(I18n.translate(option.getTranslationKey())); | ||
| 17 | } | ||
| 18 | 19 | ||
| 19 | return c; | 20 | return c; |
| 20 | } | 21 | } |
| 21 | } | 22 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java index 91727c38..93507bcd 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchEntry.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.gui.search; | |||
| 3 | import java.util.List; | 3 | import java.util.List; |
| 4 | 4 | ||
| 5 | public interface SearchEntry { | 5 | public interface SearchEntry { |
| 6 | |||
| 7 | List<String> getSearchableNames(); | 6 | List<String> getSearchableNames(); |
| 8 | 7 | ||
| 9 | /** | 8 | /** |
| @@ -13,5 +12,4 @@ public interface SearchEntry { | |||
| 13 | * @return a unique identifier for this search entry | 12 | * @return a unique identifier for this search entry |
| 14 | */ | 13 | */ |
| 15 | String getIdentifier(); | 14 | String getIdentifier(); |
| 16 | |||
| 17 | } | 15 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java index a3b35faa..c8212ce5 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/search/SearchUtil.java | |||
| @@ -1,6 +1,14 @@ | |||
| 1 | package cuchaz.enigma.gui.search; | 1 | package cuchaz.enigma.gui.search; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.ArrayList; |
| 4 | import java.util.Arrays; | ||
| 5 | import java.util.Collection; | ||
| 6 | import java.util.Collections; | ||
| 7 | import java.util.Comparator; | ||
| 8 | import java.util.HashMap; | ||
| 9 | import java.util.List; | ||
| 10 | import java.util.Locale; | ||
| 11 | import java.util.Map; | ||
| 4 | import java.util.concurrent.Executor; | 12 | import java.util.concurrent.Executor; |
| 5 | import java.util.concurrent.Executors; | 13 | import java.util.concurrent.Executors; |
| 6 | import java.util.concurrent.atomic.AtomicBoolean; | 14 | import java.util.concurrent.atomic.AtomicBoolean; |
| @@ -14,7 +22,6 @@ import java.util.stream.Stream; | |||
| 14 | import cuchaz.enigma.utils.Pair; | 22 | import cuchaz.enigma.utils.Pair; |
| 15 | 23 | ||
| 16 | public class SearchUtil<T extends SearchEntry> { | 24 | public class SearchUtil<T extends SearchEntry> { |
| 17 | |||
| 18 | private final Map<T, Entry<T>> entries = new HashMap<>(); | 25 | private final Map<T, Entry<T>> entries = new HashMap<>(); |
| 19 | private final Map<String, Integer> hitCount = new HashMap<>(); | 26 | private final Map<String, Integer> hitCount = new HashMap<>(); |
| 20 | private final Executor searchExecutor = Executors.newWorkStealingPool(); | 27 | private final Executor searchExecutor = Executors.newWorkStealingPool(); |
| @@ -45,12 +52,7 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 45 | } | 52 | } |
| 46 | 53 | ||
| 47 | public Stream<T> search(String term) { | 54 | public Stream<T> search(String term) { |
| 48 | return entries.values().parallelStream() | 55 | return entries.values().parallelStream().map(e -> new Pair<>(e, e.getScore(term, hitCount.getOrDefault(e.searchEntry.getIdentifier(), 0)))).filter(e -> e.b > 0).sorted(Comparator.comparingDouble(o -> -o.b)).map(e -> e.a.searchEntry).sequential(); |
| 49 | .map(e -> new Pair<>(e, e.getScore(term, hitCount.getOrDefault(e.searchEntry.getIdentifier(), 0)))) | ||
| 50 | .filter(e -> e.b > 0) | ||
| 51 | .sorted(Comparator.comparingDouble(o -> -o.b)) | ||
| 52 | .map(e -> e.a.searchEntry) | ||
| 53 | .sequential(); | ||
| 54 | } | 56 | } |
| 55 | 57 | ||
| 56 | public SearchControl asyncSearch(String term, SearchResultConsumer<T> consumer) { | 58 | public SearchControl asyncSearch(String term, SearchResultConsumer<T> consumer) { |
| @@ -61,21 +63,36 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 61 | AtomicInteger size = new AtomicInteger(); | 63 | AtomicInteger size = new AtomicInteger(); |
| 62 | AtomicBoolean control = new AtomicBoolean(false); | 64 | AtomicBoolean control = new AtomicBoolean(false); |
| 63 | AtomicInteger elapsed = new AtomicInteger(); | 65 | AtomicInteger elapsed = new AtomicInteger(); |
| 66 | |||
| 64 | for (Entry<T> value : entries.values()) { | 67 | for (Entry<T> value : entries.values()) { |
| 65 | searchExecutor.execute(() -> { | 68 | searchExecutor.execute(() -> { |
| 66 | try { | 69 | try { |
| 67 | if (control.get()) return; | 70 | if (control.get()) { |
| 71 | return; | ||
| 72 | } | ||
| 73 | |||
| 68 | float score = value.getScore(term, hitCount.getOrDefault(value.searchEntry.getIdentifier(), 0)); | 74 | float score = value.getScore(term, hitCount.getOrDefault(value.searchEntry.getIdentifier(), 0)); |
| 69 | if (score <= 0) return; | 75 | |
| 76 | if (score <= 0) { | ||
| 77 | return; | ||
| 78 | } | ||
| 79 | |||
| 70 | score = -score; // sort descending | 80 | score = -score; // sort descending |
| 81 | |||
| 71 | try { | 82 | try { |
| 72 | scoresLock.lock(); | 83 | scoresLock.lock(); |
| 73 | if (control.get()) return; | 84 | |
| 85 | if (control.get()) { | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 74 | int dataSize = size.getAndIncrement(); | 89 | int dataSize = size.getAndIncrement(); |
| 75 | int index = Arrays.binarySearch(scores, 0, dataSize, score); | 90 | int index = Arrays.binarySearch(scores, 0, dataSize, score); |
| 91 | |||
| 76 | if (index < 0) { | 92 | if (index < 0) { |
| 77 | index = ~index; | 93 | index = ~index; |
| 78 | } | 94 | } |
| 95 | |||
| 79 | System.arraycopy(scores, index, scores, index + 1, dataSize - index); | 96 | System.arraycopy(scores, index, scores, index + 1, dataSize - index); |
| 80 | scores[index] = score; | 97 | scores[index] = score; |
| 81 | consumer.add(index, value.searchEntry); | 98 | consumer.add(index, value.searchEntry); |
| @@ -113,7 +130,6 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 113 | } | 130 | } |
| 114 | 131 | ||
| 115 | public static final class Entry<T extends SearchEntry> { | 132 | public static final class Entry<T extends SearchEntry> { |
| 116 | |||
| 117 | public final T searchEntry; | 133 | public final T searchEntry; |
| 118 | private final String[][] components; | 134 | private final String[][] components; |
| 119 | 135 | ||
| @@ -124,9 +140,7 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 124 | 140 | ||
| 125 | public float getScore(String term, int hits) { | 141 | public float getScore(String term, int hits) { |
| 126 | String ucTerm = term.toUpperCase(Locale.ROOT); | 142 | String ucTerm = term.toUpperCase(Locale.ROOT); |
| 127 | float maxScore = (float) Arrays.stream(components) | 143 | float maxScore = (float) Arrays.stream(components).mapToDouble(name -> getScoreFor(ucTerm, name)).max().orElse(0.0); |
| 128 | .mapToDouble(name -> getScoreFor(ucTerm, name)) | ||
| 129 | .max().orElse(0.0); | ||
| 130 | return maxScore * (hits + 1); | 144 | return maxScore * (hits + 1); |
| 131 | } | 145 | } |
| 132 | 146 | ||
| @@ -156,17 +170,20 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 156 | String component = name[componentIndex]; | 170 | String component = name[componentIndex]; |
| 157 | float posMultiplier = (name.length - componentIndex) * 0.3f; | 171 | float posMultiplier = (name.length - componentIndex) * 0.3f; |
| 158 | Map<String, Float> newSnapshots = new HashMap<>(); | 172 | Map<String, Float> newSnapshots = new HashMap<>(); |
| 173 | |||
| 159 | for (Map.Entry<String, Float> snapshot : snapshots.entrySet()) { | 174 | for (Map.Entry<String, Float> snapshot : snapshots.entrySet()) { |
| 160 | String remaining = snapshot.getKey(); | 175 | String remaining = snapshot.getKey(); |
| 161 | float score = snapshot.getValue(); | 176 | float score = snapshot.getValue(); |
| 162 | component = component.toUpperCase(Locale.ROOT); | 177 | component = component.toUpperCase(Locale.ROOT); |
| 163 | int l = compareEqualLength(remaining, component); | 178 | int l = compareEqualLength(remaining, component); |
| 179 | |||
| 164 | for (int i = 1; i <= l; i++) { | 180 | for (int i = 1; i <= l; i++) { |
| 165 | float baseScore = scorePerChar * i; | 181 | float baseScore = scorePerChar * i; |
| 166 | float chainBonus = (i - 1) * 0.5f; | 182 | float chainBonus = (i - 1) * 0.5f; |
| 167 | merge(newSnapshots, Collections.singletonMap(remaining.substring(i), score + baseScore * posMultiplier + chainBonus), Math::max); | 183 | merge(newSnapshots, Collections.singletonMap(remaining.substring(i), score + baseScore * posMultiplier + chainBonus), Math::max); |
| 168 | } | 184 | } |
| 169 | } | 185 | } |
| 186 | |||
| 170 | merge(snapshots, newSnapshots, Math::max); | 187 | merge(snapshots, newSnapshots, Math::max); |
| 171 | } | 188 | } |
| 172 | 189 | ||
| @@ -180,24 +197,24 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 180 | } | 197 | } |
| 181 | 198 | ||
| 182 | public static <T extends SearchEntry> Entry<T> from(T e) { | 199 | public static <T extends SearchEntry> Entry<T> from(T e) { |
| 183 | String[][] components = e.getSearchableNames().parallelStream() | 200 | String[][] components = e.getSearchableNames().parallelStream().map(Entry::wordwiseSplit).toArray(String[][]::new); |
| 184 | .map(Entry::wordwiseSplit) | ||
| 185 | .toArray(String[][]::new); | ||
| 186 | return new Entry<>(e, components); | 201 | return new Entry<>(e, components); |
| 187 | } | 202 | } |
| 188 | 203 | ||
| 189 | private static int compareEqualLength(String s1, String s2) { | 204 | private static int compareEqualLength(String s1, String s2) { |
| 190 | int len = 0; | 205 | int len = 0; |
| 206 | |||
| 191 | while (len < s1.length() && len < s2.length() && s1.charAt(len) == s2.charAt(len)) { | 207 | while (len < s1.length() && len < s2.length() && s1.charAt(len) == s2.charAt(len)) { |
| 192 | len += 1; | 208 | len += 1; |
| 193 | } | 209 | } |
| 210 | |||
| 194 | return len; | 211 | return len; |
| 195 | } | 212 | } |
| 196 | 213 | ||
| 197 | /** | 214 | /** |
| 198 | * Splits the given input into components, trying to detect word parts. | 215 | * Splits the given input into components, trying to detect word parts. |
| 199 | * <p> | 216 | * |
| 200 | * Example of how words get split (using <code>|</code> as seperator): | 217 | * <p>Example of how words get split (using <code>|</code> as seperator): |
| 201 | * <p><code>MinecraftClientGame -> Minecraft|Client|Game</code></p> | 218 | * <p><code>MinecraftClientGame -> Minecraft|Client|Game</code></p> |
| 202 | * <p><code>HTTPInputStream -> HTTP|Input|Stream</code></p> | 219 | * <p><code>HTTPInputStream -> HTTP|Input|Stream</code></p> |
| 203 | * <p><code>class_932 -> class|_|932</code></p> | 220 | * <p><code>class_932 -> class|_|932</code></p> |
| @@ -210,46 +227,57 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 210 | */ | 227 | */ |
| 211 | private static String[] wordwiseSplit(String input) { | 228 | private static String[] wordwiseSplit(String input) { |
| 212 | List<String> list = new ArrayList<>(); | 229 | List<String> list = new ArrayList<>(); |
| 230 | |||
| 213 | while (!input.isEmpty()) { | 231 | while (!input.isEmpty()) { |
| 214 | int take; | 232 | int take; |
| 233 | |||
| 215 | if (Character.isLetter(input.charAt(0))) { | 234 | if (Character.isLetter(input.charAt(0))) { |
| 216 | if (input.length() == 1) { | 235 | if (input.length() == 1) { |
| 217 | take = 1; | 236 | take = 1; |
| 218 | } else { | 237 | } else { |
| 219 | boolean nextSegmentIsUppercase = Character.isUpperCase(input.charAt(0)) && Character.isUpperCase(input.charAt(1)); | 238 | boolean nextSegmentIsUppercase = Character.isUpperCase(input.charAt(0)) && Character.isUpperCase(input.charAt(1)); |
| 239 | |||
| 220 | if (nextSegmentIsUppercase) { | 240 | if (nextSegmentIsUppercase) { |
| 221 | int nextLowercase = 1; | 241 | int nextLowercase = 1; |
| 242 | |||
| 222 | while (Character.isUpperCase(input.charAt(nextLowercase))) { | 243 | while (Character.isUpperCase(input.charAt(nextLowercase))) { |
| 223 | nextLowercase += 1; | 244 | nextLowercase += 1; |
| 245 | |||
| 224 | if (nextLowercase == input.length()) { | 246 | if (nextLowercase == input.length()) { |
| 225 | nextLowercase += 1; | 247 | nextLowercase += 1; |
| 226 | break; | 248 | break; |
| 227 | } | 249 | } |
| 228 | } | 250 | } |
| 251 | |||
| 229 | take = nextLowercase - 1; | 252 | take = nextLowercase - 1; |
| 230 | } else { | 253 | } else { |
| 231 | int nextUppercase = 1; | 254 | int nextUppercase = 1; |
| 255 | |||
| 232 | while (nextUppercase < input.length() && Character.isLowerCase(input.charAt(nextUppercase))) { | 256 | while (nextUppercase < input.length() && Character.isLowerCase(input.charAt(nextUppercase))) { |
| 233 | nextUppercase += 1; | 257 | nextUppercase += 1; |
| 234 | } | 258 | } |
| 259 | |||
| 235 | take = nextUppercase; | 260 | take = nextUppercase; |
| 236 | } | 261 | } |
| 237 | } | 262 | } |
| 238 | } else if (Character.isDigit(input.charAt(0))) { | 263 | } else if (Character.isDigit(input.charAt(0))) { |
| 239 | int nextNonNum = 1; | 264 | int nextNonNum = 1; |
| 265 | |||
| 240 | while (nextNonNum < input.length() && Character.isLetter(input.charAt(nextNonNum)) && !Character.isLowerCase(input.charAt(nextNonNum))) { | 266 | while (nextNonNum < input.length() && Character.isLetter(input.charAt(nextNonNum)) && !Character.isLowerCase(input.charAt(nextNonNum))) { |
| 241 | nextNonNum += 1; | 267 | nextNonNum += 1; |
| 242 | } | 268 | } |
| 269 | |||
| 243 | take = nextNonNum; | 270 | take = nextNonNum; |
| 244 | } else { | 271 | } else { |
| 245 | take = 1; | 272 | take = 1; |
| 246 | } | 273 | } |
| 274 | |||
| 247 | list.add(input.substring(0, take)); | 275 | list.add(input.substring(0, take)); |
| 248 | input = input.substring(take); | 276 | input = input.substring(take); |
| 249 | } | 277 | } |
| 278 | |||
| 250 | return list.toArray(new String[0]); | 279 | return list.toArray(new String[0]); |
| 251 | } | 280 | } |
| 252 | |||
| 253 | } | 281 | } |
| 254 | 282 | ||
| 255 | @FunctionalInterface | 283 | @FunctionalInterface |
| @@ -264,5 +292,4 @@ public class SearchUtil<T extends SearchEntry> { | |||
| 264 | 292 | ||
| 265 | float getProgress(); | 293 | float getProgress(); |
| 266 | } | 294 | } |
| 267 | |||
| 268 | } | 295 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java index 20d6a0eb..99b5572b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java | |||
| @@ -1,5 +1,10 @@ | |||
| 1 | package cuchaz.enigma.gui.stats; | 1 | package cuchaz.enigma.gui.stats; |
| 2 | 2 | ||
| 3 | import java.util.EnumSet; | ||
| 4 | import java.util.HashMap; | ||
| 5 | import java.util.Map; | ||
| 6 | import java.util.Set; | ||
| 7 | |||
| 3 | import cuchaz.enigma.EnigmaProject; | 8 | import cuchaz.enigma.EnigmaProject; |
| 4 | import cuchaz.enigma.ProgressListener; | 9 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.analysis.index.EntryIndex; | 10 | import cuchaz.enigma.analysis.index.EntryIndex; |
| @@ -7,109 +12,112 @@ import cuchaz.enigma.translation.mapping.EntryRemapper; | |||
| 7 | import cuchaz.enigma.translation.mapping.EntryResolver; | 12 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 8 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 13 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 9 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 14 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 10 | import cuchaz.enigma.translation.representation.entry.*; | 15 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 16 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 17 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 18 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 19 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 20 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 11 | import cuchaz.enigma.utils.I18n; | 22 | import cuchaz.enigma.utils.I18n; |
| 12 | 23 | ||
| 13 | import java.util.*; | ||
| 14 | |||
| 15 | public class StatsGenerator { | 24 | public class StatsGenerator { |
| 16 | private final EnigmaProject project; | 25 | private final EnigmaProject project; |
| 17 | private final EntryIndex entryIndex; | 26 | private final EntryIndex entryIndex; |
| 18 | private final EntryRemapper mapper; | 27 | private final EntryRemapper mapper; |
| 19 | private final EntryResolver entryResolver; | 28 | private final EntryResolver entryResolver; |
| 20 | 29 | ||
| 21 | public StatsGenerator(EnigmaProject project) { | 30 | public StatsGenerator(EnigmaProject project) { |
| 22 | this.project = project; | 31 | this.project = project; |
| 23 | this.entryIndex = project.getJarIndex().getEntryIndex(); | 32 | this.entryIndex = project.getJarIndex().getEntryIndex(); |
| 24 | this.mapper = project.getMapper(); | 33 | this.mapper = project.getMapper(); |
| 25 | this.entryResolver = project.getJarIndex().getEntryResolver(); | 34 | this.entryResolver = project.getJarIndex().getEntryResolver(); |
| 26 | } | 35 | } |
| 27 | 36 | ||
| 28 | public StatsResult generate(ProgressListener progress, Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) { | 37 | public StatsResult generate(ProgressListener progress, Set<StatsMember> includedMembers, String topLevelPackage, boolean includeSynthetic) { |
| 29 | includedMembers = EnumSet.copyOf(includedMembers); | 38 | includedMembers = EnumSet.copyOf(includedMembers); |
| 30 | int totalWork = 0; | 39 | int totalWork = 0; |
| 31 | int totalMappable = 0; | 40 | int totalMappable = 0; |
| 32 | 41 | ||
| 33 | if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { | 42 | if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { |
| 34 | totalWork += entryIndex.getMethods().size(); | 43 | totalWork += entryIndex.getMethods().size(); |
| 35 | } | 44 | } |
| 36 | 45 | ||
| 37 | if (includedMembers.contains(StatsMember.FIELDS)) { | 46 | if (includedMembers.contains(StatsMember.FIELDS)) { |
| 38 | totalWork += entryIndex.getFields().size(); | 47 | totalWork += entryIndex.getFields().size(); |
| 39 | } | 48 | } |
| 40 | 49 | ||
| 41 | if (includedMembers.contains(StatsMember.CLASSES)) { | 50 | if (includedMembers.contains(StatsMember.CLASSES)) { |
| 42 | totalWork += entryIndex.getClasses().size(); | 51 | totalWork += entryIndex.getClasses().size(); |
| 43 | } | 52 | } |
| 44 | 53 | ||
| 45 | progress.init(totalWork, I18n.translate("progress.stats")); | 54 | progress.init(totalWork, I18n.translate("progress.stats")); |
| 46 | 55 | ||
| 47 | Map<String, Integer> counts = new HashMap<>(); | 56 | Map<String, Integer> counts = new HashMap<>(); |
| 48 | 57 | ||
| 49 | int numDone = 0; | 58 | int numDone = 0; |
| 50 | if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { | 59 | |
| 51 | for (MethodEntry method : entryIndex.getMethods()) { | 60 | if (includedMembers.contains(StatsMember.METHODS) || includedMembers.contains(StatsMember.PARAMETERS)) { |
| 52 | progress.step(numDone++, I18n.translate("type.methods")); | 61 | for (MethodEntry method : entryIndex.getMethods()) { |
| 53 | MethodEntry root = entryResolver | 62 | progress.step(numDone++, I18n.translate("type.methods")); |
| 54 | .resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT) | 63 | MethodEntry root = entryResolver.resolveEntry(method, ResolutionStrategy.RESOLVE_ROOT).stream().findFirst().orElseThrow(AssertionError::new); |
| 55 | .stream() | 64 | |
| 56 | .findFirst() | 65 | if (root == method) { |
| 57 | .orElseThrow(AssertionError::new); | 66 | if (includedMembers.contains(StatsMember.METHODS) && !((MethodDefEntry) method).getAccess().isSynthetic()) { |
| 58 | 67 | update(counts, method); | |
| 59 | if (root == method) { | 68 | totalMappable++; |
| 60 | if (includedMembers.contains(StatsMember.METHODS) && !((MethodDefEntry) method).getAccess().isSynthetic()) { | 69 | } |
| 61 | update(counts, method); | 70 | |
| 62 | totalMappable ++; | 71 | if (includedMembers.contains(StatsMember.PARAMETERS) && (!((MethodDefEntry) method).getAccess().isSynthetic() || includeSynthetic)) { |
| 63 | } | 72 | int index = ((MethodDefEntry) method).getAccess().isStatic() ? 0 : 1; |
| 64 | 73 | ||
| 65 | if (includedMembers.contains(StatsMember.PARAMETERS) && (!((MethodDefEntry) method).getAccess().isSynthetic() || includeSynthetic)) { | 74 | for (TypeDescriptor argument : method.getDesc().getArgumentDescs()) { |
| 66 | int index = ((MethodDefEntry) method).getAccess().isStatic() ? 0 : 1; | 75 | update(counts, new LocalVariableEntry(method, index, "", true, null)); |
| 67 | for (TypeDescriptor argument : method.getDesc().getArgumentDescs()) { | 76 | index += argument.getSize(); |
| 68 | update(counts, new LocalVariableEntry(method, index, "", true,null)); | 77 | totalMappable++; |
| 69 | index += argument.getSize(); | 78 | } |
| 70 | totalMappable ++; | 79 | } |
| 71 | } | 80 | } |
| 72 | } | 81 | } |
| 73 | } | 82 | } |
| 74 | } | 83 | |
| 75 | } | 84 | if (includedMembers.contains(StatsMember.FIELDS)) { |
| 76 | 85 | for (FieldEntry field : entryIndex.getFields()) { | |
| 77 | if (includedMembers.contains(StatsMember.FIELDS)) { | 86 | progress.step(numDone++, I18n.translate("type.fields")); |
| 78 | for (FieldEntry field : entryIndex.getFields()) { | 87 | |
| 79 | progress.step(numDone++, I18n.translate("type.fields")); | 88 | if (!((FieldDefEntry) field).getAccess().isSynthetic()) { |
| 80 | if (!((FieldDefEntry)field).getAccess().isSynthetic()) { | 89 | update(counts, field); |
| 81 | update(counts, field); | 90 | totalMappable++; |
| 82 | totalMappable ++; | 91 | } |
| 83 | } | 92 | } |
| 84 | } | 93 | } |
| 85 | } | 94 | |
| 86 | 95 | if (includedMembers.contains(StatsMember.CLASSES)) { | |
| 87 | if (includedMembers.contains(StatsMember.CLASSES)) { | 96 | for (ClassEntry clazz : entryIndex.getClasses()) { |
| 88 | for (ClassEntry clazz : entryIndex.getClasses()) { | 97 | progress.step(numDone++, I18n.translate("type.classes")); |
| 89 | progress.step(numDone++, I18n.translate("type.classes")); | 98 | update(counts, clazz); |
| 90 | update(counts, clazz); | 99 | totalMappable++; |
| 91 | totalMappable ++; | 100 | } |
| 92 | } | 101 | } |
| 93 | } | 102 | |
| 94 | 103 | progress.step(-1, I18n.translate("progress.stats.data")); | |
| 95 | progress.step(-1, I18n.translate("progress.stats.data")); | 104 | |
| 96 | 105 | StatsResult.Tree<Integer> tree = new StatsResult.Tree<>(); | |
| 97 | StatsResult.Tree<Integer> tree = new StatsResult.Tree<>(); | 106 | |
| 98 | 107 | for (Map.Entry<String, Integer> entry : counts.entrySet()) { | |
| 99 | for (Map.Entry<String, Integer> entry : counts.entrySet()) { | 108 | if (entry.getKey().startsWith(topLevelPackage)) { |
| 100 | if (entry.getKey().startsWith(topLevelPackage)) { | 109 | tree.getNode(entry.getKey()).value = entry.getValue(); |
| 101 | tree.getNode(entry.getKey()).value = entry.getValue(); | 110 | } |
| 102 | } | 111 | } |
| 103 | } | 112 | |
| 104 | 113 | tree.collapse(tree.root); | |
| 105 | tree.collapse(tree.root); | 114 | return new StatsResult(totalMappable, counts.values().stream().mapToInt(i -> i).sum(), tree); |
| 106 | return new StatsResult(totalMappable, counts.values().stream().mapToInt(i -> i).sum(), tree); | 115 | } |
| 107 | } | 116 | |
| 108 | 117 | private void update(Map<String, Integer> counts, Entry<?> entry) { | |
| 109 | private void update(Map<String, Integer> counts, Entry<?> entry) { | 118 | if (project.isObfuscated(entry)) { |
| 110 | if (project.isObfuscated(entry)) { | 119 | String parent = mapper.deobfuscate(entry.getAncestry().get(0)).getName().replace('/', '.'); |
| 111 | String parent = mapper.deobfuscate(entry.getAncestry().get(0)).getName().replace('/', '.'); | 120 | counts.put(parent, counts.getOrDefault(parent, 0) + 1); |
| 112 | counts.put(parent, counts.getOrDefault(parent, 0) + 1); | 121 | } |
| 113 | } | 122 | } |
| 114 | } | ||
| 115 | } | 123 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java index 0e2452fa..0037ab5b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsMember.java | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | package cuchaz.enigma.gui.stats; | 1 | package cuchaz.enigma.gui.stats; |
| 2 | 2 | ||
| 3 | public enum StatsMember { | 3 | public enum StatsMember { |
| 4 | CLASSES, | 4 | CLASSES, |
| 5 | METHODS, | 5 | METHODS, |
| 6 | FIELDS, | 6 | FIELDS, |
| 7 | PARAMETERS | 7 | PARAMETERS |
| 8 | } | 8 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java index 0a71a647..12726c0b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsResult.java | |||
| @@ -1,14 +1,13 @@ | |||
| 1 | package cuchaz.enigma.gui.stats; | 1 | package cuchaz.enigma.gui.stats; |
| 2 | 2 | ||
| 3 | import com.google.gson.GsonBuilder; | ||
| 4 | |||
| 5 | import java.util.ArrayList; | 3 | import java.util.ArrayList; |
| 6 | import java.util.HashMap; | 4 | import java.util.HashMap; |
| 7 | import java.util.List; | 5 | import java.util.List; |
| 8 | import java.util.Map; | 6 | import java.util.Map; |
| 9 | 7 | ||
| 10 | public final class StatsResult { | 8 | import com.google.gson.GsonBuilder; |
| 11 | 9 | ||
| 10 | public final class StatsResult { | ||
| 12 | private final int total; | 11 | private final int total; |
| 13 | private final int unmapped; | 12 | private final int unmapped; |
| 14 | private final Tree<Integer> tree; | 13 | private final Tree<Integer> tree; |
| @@ -101,5 +100,4 @@ public final class StatsResult { | |||
| 101 | } | 100 | } |
| 102 | } | 101 | } |
| 103 | } | 102 | } |
| 104 | |||
| 105 | } | 103 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java index 612e3e92..f8ce36db 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/AbstractListCellRenderer.java | |||
| @@ -3,11 +3,16 @@ package cuchaz.enigma.gui.util; | |||
| 3 | import java.awt.Component; | 3 | import java.awt.Component; |
| 4 | import java.awt.event.MouseEvent; | 4 | import java.awt.event.MouseEvent; |
| 5 | 5 | ||
| 6 | import javax.swing.*; | 6 | import javax.swing.BorderFactory; |
| 7 | import javax.swing.JComponent; | ||
| 8 | import javax.swing.JList; | ||
| 9 | import javax.swing.JPanel; | ||
| 10 | import javax.swing.ListCellRenderer; | ||
| 11 | import javax.swing.UIDefaults; | ||
| 12 | import javax.swing.UIManager; | ||
| 7 | import javax.swing.border.Border; | 13 | import javax.swing.border.Border; |
| 8 | 14 | ||
| 9 | public abstract class AbstractListCellRenderer<E> extends JPanel implements ListCellRenderer<E> { | 15 | public abstract class AbstractListCellRenderer<E> extends JPanel implements ListCellRenderer<E> { |
| 10 | |||
| 11 | private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1); | 16 | private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1); |
| 12 | 17 | ||
| 13 | private Border noFocusBorder; | 18 | private Border noFocusBorder; |
| @@ -21,22 +26,27 @@ public abstract class AbstractListCellRenderer<E> extends JPanel implements List | |||
| 21 | Border border = UIManager.getLookAndFeel().getDefaults().getBorder("List.List.cellNoFocusBorder"); | 26 | Border border = UIManager.getLookAndFeel().getDefaults().getBorder("List.List.cellNoFocusBorder"); |
| 22 | noFocusBorder = border != null ? border : NO_FOCUS_BORDER; | 27 | noFocusBorder = border != null ? border : NO_FOCUS_BORDER; |
| 23 | } | 28 | } |
| 29 | |||
| 24 | return noFocusBorder; | 30 | return noFocusBorder; |
| 25 | } | 31 | } |
| 26 | 32 | ||
| 27 | protected Border getBorder(boolean isSelected, boolean cellHasFocus) { | 33 | protected Border getBorder(boolean isSelected, boolean cellHasFocus) { |
| 28 | Border b = null; | 34 | Border b = null; |
| 35 | |||
| 29 | if (cellHasFocus) { | 36 | if (cellHasFocus) { |
| 30 | UIDefaults defaults = UIManager.getLookAndFeel().getDefaults(); | 37 | UIDefaults defaults = UIManager.getLookAndFeel().getDefaults(); |
| 38 | |||
| 31 | if (isSelected) { | 39 | if (isSelected) { |
| 32 | b = defaults.getBorder("List.focusSelectedCellHighlightBorder"); | 40 | b = defaults.getBorder("List.focusSelectedCellHighlightBorder"); |
| 33 | } | 41 | } |
| 42 | |||
| 34 | if (b == null) { | 43 | if (b == null) { |
| 35 | b = defaults.getBorder("List.focusCellHighlightBorder"); | 44 | b = defaults.getBorder("List.focusCellHighlightBorder"); |
| 36 | } | 45 | } |
| 37 | } else { | 46 | } else { |
| 38 | b = getNoFocusBorder(); | 47 | b = getNoFocusBorder(); |
| 39 | } | 48 | } |
| 49 | |||
| 40 | return b; | 50 | return b; |
| 41 | } | 51 | } |
| 42 | 52 | ||
| @@ -68,10 +78,11 @@ public abstract class AbstractListCellRenderer<E> extends JPanel implements List | |||
| 68 | @Override | 78 | @Override |
| 69 | public String getToolTipText(MouseEvent event) { | 79 | public String getToolTipText(MouseEvent event) { |
| 70 | Component c = getComponentAt(event.getPoint()); | 80 | Component c = getComponentAt(event.getPoint()); |
| 81 | |||
| 71 | if (c instanceof JComponent) { | 82 | if (c instanceof JComponent) { |
| 72 | return ((JComponent) c).getToolTipText(); | 83 | return ((JComponent) c).getToolTipText(); |
| 73 | } | 84 | } |
| 85 | |||
| 74 | return getToolTipText(); | 86 | return getToolTipText(); |
| 75 | } | 87 | } |
| 76 | |||
| 77 | } | 88 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java index 6a756867..2d8aa73e 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GridBagConstraintsBuilder.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.gui.util; | |||
| 3 | import java.awt.GridBagConstraints; | 3 | import java.awt.GridBagConstraints; |
| 4 | 4 | ||
| 5 | public final class GridBagConstraintsBuilder { | 5 | public final class GridBagConstraintsBuilder { |
| 6 | |||
| 7 | private final GridBagConstraints inner; | 6 | private final GridBagConstraints inner; |
| 8 | 7 | ||
| 9 | private GridBagConstraintsBuilder(GridBagConstraints inner) { | 8 | private GridBagConstraintsBuilder(GridBagConstraints inner) { |
| @@ -136,5 +135,4 @@ public final class GridBagConstraintsBuilder { | |||
| 136 | public GridBagConstraints build() { | 135 | public GridBagConstraints build() { |
| 137 | return (GridBagConstraints) this.inner.clone(); | 136 | return (GridBagConstraints) this.inner.clone(); |
| 138 | } | 137 | } |
| 139 | |||
| 140 | } | 138 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java index 3b8ecbc5..d0784243 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/GuiUtil.java | |||
| @@ -1,8 +1,17 @@ | |||
| 1 | package cuchaz.enigma.gui.util; | 1 | package cuchaz.enigma.gui.util; |
| 2 | 2 | ||
| 3 | import java.awt.*; | 3 | import java.awt.Color; |
| 4 | import java.awt.Cursor; | ||
| 5 | import java.awt.Desktop; | ||
| 6 | import java.awt.Font; | ||
| 7 | import java.awt.Toolkit; | ||
| 4 | import java.awt.datatransfer.StringSelection; | 8 | import java.awt.datatransfer.StringSelection; |
| 5 | import java.awt.event.*; | 9 | import java.awt.event.MouseAdapter; |
| 10 | import java.awt.event.MouseEvent; | ||
| 11 | import java.awt.event.MouseListener; | ||
| 12 | import java.awt.event.WindowAdapter; | ||
| 13 | import java.awt.event.WindowEvent; | ||
| 14 | import java.awt.event.WindowListener; | ||
| 6 | import java.awt.font.TextAttribute; | 15 | import java.awt.font.TextAttribute; |
| 7 | import java.io.IOException; | 16 | import java.io.IOException; |
| 8 | import java.net.URI; | 17 | import java.net.URI; |
| @@ -13,7 +22,14 @@ import java.util.Map; | |||
| 13 | import java.util.NoSuchElementException; | 22 | import java.util.NoSuchElementException; |
| 14 | import java.util.function.Consumer; | 23 | import java.util.function.Consumer; |
| 15 | 24 | ||
| 16 | import javax.swing.*; | 25 | import javax.swing.Icon; |
| 26 | import javax.swing.JComponent; | ||
| 27 | import javax.swing.JLabel; | ||
| 28 | import javax.swing.JToolTip; | ||
| 29 | import javax.swing.Popup; | ||
| 30 | import javax.swing.PopupFactory; | ||
| 31 | import javax.swing.Timer; | ||
| 32 | import javax.swing.ToolTipManager; | ||
| 17 | import javax.swing.tree.TreeNode; | 33 | import javax.swing.tree.TreeNode; |
| 18 | import javax.swing.tree.TreePath; | 34 | import javax.swing.tree.TreePath; |
| 19 | 35 | ||
| @@ -28,160 +44,160 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry; | |||
| 28 | import cuchaz.enigma.utils.Os; | 44 | import cuchaz.enigma.utils.Os; |
| 29 | 45 | ||
| 30 | public class GuiUtil { | 46 | public class GuiUtil { |
| 31 | public static final Icon CLASS_ICON = loadIcon("class"); | 47 | public static final Icon CLASS_ICON = loadIcon("class"); |
| 32 | public static final Icon INTERFACE_ICON = loadIcon("interface"); | 48 | public static final Icon INTERFACE_ICON = loadIcon("interface"); |
| 33 | public static final Icon ENUM_ICON = loadIcon("enum"); | 49 | public static final Icon ENUM_ICON = loadIcon("enum"); |
| 34 | public static final Icon ANNOTATION_ICON = loadIcon("annotation"); | 50 | public static final Icon ANNOTATION_ICON = loadIcon("annotation"); |
| 35 | public static final Icon RECORD_ICON = loadIcon("record"); | 51 | public static final Icon RECORD_ICON = loadIcon("record"); |
| 36 | public static final Icon METHOD_ICON = loadIcon("method"); | 52 | public static final Icon METHOD_ICON = loadIcon("method"); |
| 37 | public static final Icon FIELD_ICON = loadIcon("field"); | 53 | public static final Icon FIELD_ICON = loadIcon("field"); |
| 38 | public static final Icon CONSTRUCTOR_ICON = loadIcon("constructor"); | 54 | public static final Icon CONSTRUCTOR_ICON = loadIcon("constructor"); |
| 39 | 55 | ||
| 40 | public static void openUrl(String url) { | 56 | public static void openUrl(String url) { |
| 41 | try { | 57 | try { |
| 42 | switch (Os.getOs()) { | 58 | switch (Os.getOs()) { |
| 43 | case LINUX: | 59 | case LINUX: |
| 44 | new ProcessBuilder("/usr/bin/env", "xdg-open", url).start(); | 60 | new ProcessBuilder("/usr/bin/env", "xdg-open", url).start(); |
| 45 | break; | 61 | break; |
| 46 | default: | 62 | default: |
| 47 | if (Desktop.isDesktopSupported()) { | 63 | if (Desktop.isDesktopSupported()) { |
| 48 | Desktop desktop = Desktop.getDesktop(); | 64 | Desktop desktop = Desktop.getDesktop(); |
| 49 | desktop.browse(new URI(url)); | 65 | desktop.browse(new URI(url)); |
| 50 | } | 66 | } |
| 51 | } | 67 | } |
| 52 | } catch (IOException ex) { | 68 | } catch (IOException ex) { |
| 53 | throw new RuntimeException(ex); | 69 | throw new RuntimeException(ex); |
| 54 | } catch (URISyntaxException ex) { | 70 | } catch (URISyntaxException ex) { |
| 55 | throw new IllegalArgumentException(ex); | 71 | throw new IllegalArgumentException(ex); |
| 56 | } | 72 | } |
| 57 | } | 73 | } |
| 58 | 74 | ||
| 59 | public static JLabel unboldLabel(JLabel label) { | 75 | public static JLabel unboldLabel(JLabel label) { |
| 60 | Font font = label.getFont(); | 76 | Font font = label.getFont(); |
| 61 | label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD)); | 77 | label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD)); |
| 62 | return label; | 78 | return label; |
| 63 | } | 79 | } |
| 64 | 80 | ||
| 65 | /** | 81 | /** |
| 66 | * Puts the provided {@code text} in the system clipboard. | 82 | * Puts the provided {@code text} in the system clipboard. |
| 67 | */ | 83 | */ |
| 68 | public static void copyToClipboard(String text) { | 84 | public static void copyToClipboard(String text) { |
| 69 | Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null); | 85 | Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null); |
| 70 | } | 86 | } |
| 71 | 87 | ||
| 72 | public static void showPopup(JComponent component, String text, int x, int y) { | 88 | public static void showPopup(JComponent component, String text, int x, int y) { |
| 73 | // from https://stackoverflow.com/questions/39955015/java-swing-show-tooltip-as-a-message-dialog | 89 | // from https://stackoverflow.com/questions/39955015/java-swing-show-tooltip-as-a-message-dialog |
| 74 | JToolTip tooltip = new JToolTip(); | 90 | JToolTip tooltip = new JToolTip(); |
| 75 | tooltip.setTipText(text); | 91 | tooltip.setTipText(text); |
| 76 | Popup p = PopupFactory.getSharedInstance().getPopup(component, tooltip, x + 10, y); | 92 | Popup p = PopupFactory.getSharedInstance().getPopup(component, tooltip, x + 10, y); |
| 77 | p.show(); | 93 | p.show(); |
| 78 | Timer t = new Timer(1000, e -> p.hide()); | 94 | Timer t = new Timer(1000, e -> p.hide()); |
| 79 | t.setRepeats(false); | 95 | t.setRepeats(false); |
| 80 | t.start(); | 96 | t.start(); |
| 81 | } | 97 | } |
| 82 | 98 | ||
| 83 | public static void showToolTipNow(JComponent component) { | 99 | public static void showToolTipNow(JComponent component) { |
| 84 | // HACKHACK: trick the tooltip manager into showing the tooltip right now | 100 | // HACKHACK: trick the tooltip manager into showing the tooltip right now |
| 85 | ToolTipManager manager = ToolTipManager.sharedInstance(); | 101 | ToolTipManager manager = ToolTipManager.sharedInstance(); |
| 86 | int oldDelay = manager.getInitialDelay(); | 102 | int oldDelay = manager.getInitialDelay(); |
| 87 | manager.setInitialDelay(0); | 103 | manager.setInitialDelay(0); |
| 88 | manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); | 104 | manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); |
| 89 | manager.setInitialDelay(oldDelay); | 105 | manager.setInitialDelay(oldDelay); |
| 90 | } | 106 | } |
| 91 | 107 | ||
| 92 | public static JLabel createLink(String text, Runnable action) { | 108 | public static JLabel createLink(String text, Runnable action) { |
| 93 | JLabel link = new JLabel(text); | 109 | JLabel link = new JLabel(text); |
| 94 | link.setForeground(Color.BLUE.darker()); | 110 | link.setForeground(Color.BLUE.darker()); |
| 95 | link.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); | 111 | link.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| 96 | @SuppressWarnings("unchecked") | 112 | @SuppressWarnings("unchecked") Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) link.getFont().getAttributes(); |
| 97 | Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) link.getFont().getAttributes(); | 113 | attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); |
| 98 | attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); | 114 | link.setFont(link.getFont().deriveFont(attributes)); |
| 99 | link.setFont(link.getFont().deriveFont(attributes)); | 115 | link.addMouseListener(new MouseAdapter() { |
| 100 | link.addMouseListener(new MouseAdapter() { | 116 | @Override |
| 101 | @Override | 117 | public void mousePressed(MouseEvent e) { |
| 102 | public void mousePressed(MouseEvent e) { | 118 | action.run(); |
| 103 | action.run(); | 119 | } |
| 104 | } | 120 | }); |
| 105 | }); | 121 | return link; |
| 106 | return link; | 122 | } |
| 107 | } | 123 | |
| 108 | 124 | public static Icon loadIcon(String name) { | |
| 109 | public static Icon loadIcon(String name) { | 125 | String path = "icons/" + name + ".svg"; |
| 110 | String path = "icons/" + name + ".svg"; | 126 | |
| 111 | 127 | // Do an eager check for a missing icon since FlatSVGIcon does it later at render time | |
| 112 | // Do an eager check for a missing icon since FlatSVGIcon does it later at render time | 128 | if (GuiUtil.class.getResource('/' + path) == null) { |
| 113 | if (GuiUtil.class.getResource('/' + path) == null) { | 129 | throw new NoSuchElementException("Missing icon: '" + name + "' at " + path); |
| 114 | throw new NoSuchElementException("Missing icon: '" + name + "' at " + path); | 130 | } |
| 115 | } | 131 | |
| 116 | 132 | // Note: the width and height are scaled automatically because the FlatLaf UI scale | |
| 117 | // Note: the width and height are scaled automatically because the FlatLaf UI scale | 133 | // is set in LookAndFeel.setGlobalLAF() |
| 118 | // is set in LookAndFeel.setGlobalLAF() | 134 | return new FlatSVGIcon(path, 16, 16, GuiUtil.class.getClassLoader()); |
| 119 | return new FlatSVGIcon(path, 16, 16, GuiUtil.class.getClassLoader()); | 135 | } |
| 120 | } | 136 | |
| 121 | 137 | public static Icon getClassIcon(Gui gui, ClassEntry entry) { | |
| 122 | public static Icon getClassIcon(Gui gui, ClassEntry entry) { | 138 | EntryIndex entryIndex = gui.getController().project.getJarIndex().getEntryIndex(); |
| 123 | EntryIndex entryIndex = gui.getController().project.getJarIndex().getEntryIndex(); | 139 | AccessFlags access = entryIndex.getClassAccess(entry); |
| 124 | AccessFlags access = entryIndex.getClassAccess(entry); | 140 | |
| 125 | 141 | if (access != null) { | |
| 126 | if (access != null) { | 142 | if (access.isAnnotation()) { |
| 127 | if (access.isAnnotation()) { | 143 | return ANNOTATION_ICON; |
| 128 | return ANNOTATION_ICON; | 144 | } else if (access.isInterface()) { |
| 129 | } else if (access.isInterface()) { | 145 | return INTERFACE_ICON; |
| 130 | return INTERFACE_ICON; | 146 | } else if (access.isEnum()) { |
| 131 | } else if (access.isEnum()) { | 147 | return ENUM_ICON; |
| 132 | return ENUM_ICON; | 148 | } else if (entryIndex.getDefinition(entry).isRecord()) { |
| 133 | } else if (entryIndex.getDefinition(entry).isRecord()) { | 149 | return RECORD_ICON; |
| 134 | return RECORD_ICON; | 150 | } |
| 135 | } | 151 | } |
| 136 | } | 152 | |
| 137 | 153 | return CLASS_ICON; | |
| 138 | return CLASS_ICON; | 154 | } |
| 139 | } | 155 | |
| 140 | 156 | public static Icon getMethodIcon(MethodEntry entry) { | |
| 141 | public static Icon getMethodIcon(MethodEntry entry) { | 157 | if (entry.isConstructor()) { |
| 142 | if (entry.isConstructor()) { | 158 | return CONSTRUCTOR_ICON; |
| 143 | return CONSTRUCTOR_ICON; | 159 | } |
| 144 | } | 160 | |
| 145 | return METHOD_ICON; | 161 | return METHOD_ICON; |
| 146 | } | 162 | } |
| 147 | 163 | ||
| 148 | public static TreePath getPathToRoot(TreeNode node) { | 164 | public static TreePath getPathToRoot(TreeNode node) { |
| 149 | List<TreeNode> nodes = Lists.newArrayList(); | 165 | List<TreeNode> nodes = Lists.newArrayList(); |
| 150 | TreeNode n = node; | 166 | TreeNode n = node; |
| 151 | 167 | ||
| 152 | do { | 168 | do { |
| 153 | nodes.add(n); | 169 | nodes.add(n); |
| 154 | n = n.getParent(); | 170 | n = n.getParent(); |
| 155 | } while (n != null); | 171 | } while (n != null); |
| 156 | 172 | ||
| 157 | Collections.reverse(nodes); | 173 | Collections.reverse(nodes); |
| 158 | return new TreePath(nodes.toArray()); | 174 | return new TreePath(nodes.toArray()); |
| 159 | } | 175 | } |
| 160 | 176 | ||
| 161 | public static MouseListener onMouseClick(Consumer<MouseEvent> op) { | 177 | public static MouseListener onMouseClick(Consumer<MouseEvent> op) { |
| 162 | return new MouseAdapter() { | 178 | return new MouseAdapter() { |
| 163 | @Override | 179 | @Override |
| 164 | public void mouseClicked(MouseEvent e) { | 180 | public void mouseClicked(MouseEvent e) { |
| 165 | op.accept(e); | 181 | op.accept(e); |
| 166 | } | 182 | } |
| 167 | }; | 183 | }; |
| 168 | } | 184 | } |
| 169 | 185 | ||
| 170 | public static MouseListener onMousePress(Consumer<MouseEvent> op) { | 186 | public static MouseListener onMousePress(Consumer<MouseEvent> op) { |
| 171 | return new MouseAdapter() { | 187 | return new MouseAdapter() { |
| 172 | @Override | 188 | @Override |
| 173 | public void mousePressed(MouseEvent e) { | 189 | public void mousePressed(MouseEvent e) { |
| 174 | op.accept(e); | 190 | op.accept(e); |
| 175 | } | 191 | } |
| 176 | }; | 192 | }; |
| 177 | } | 193 | } |
| 178 | 194 | ||
| 179 | public static WindowListener onWindowClose(Consumer<WindowEvent> op) { | 195 | public static WindowListener onWindowClose(Consumer<WindowEvent> op) { |
| 180 | return new WindowAdapter() { | 196 | return new WindowAdapter() { |
| 181 | @Override | 197 | @Override |
| 182 | public void windowClosing(WindowEvent e) { | 198 | public void windowClosing(WindowEvent e) { |
| 183 | op.accept(e); | 199 | op.accept(e); |
| 184 | } | 200 | } |
| 185 | }; | 201 | }; |
| 186 | } | 202 | } |
| 187 | } | 203 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java index b1286998..f1a8a7a9 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/History.java | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | package cuchaz.enigma.gui.util; | 1 | package cuchaz.enigma.gui.util; |
| 2 | 2 | ||
| 3 | import com.google.common.collect.Queues; | ||
| 4 | |||
| 5 | import java.util.Deque; | 3 | import java.util.Deque; |
| 6 | 4 | ||
| 5 | import com.google.common.collect.Queues; | ||
| 6 | |||
| 7 | public class History<T> { | 7 | public class History<T> { |
| 8 | private final Deque<T> previous = Queues.newArrayDeque(); | 8 | private final Deque<T> previous = Queues.newArrayDeque(); |
| 9 | private final Deque<T> next = Queues.newArrayDeque(); | 9 | private final Deque<T> next = Queues.newArrayDeque(); |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java index 9f53a44f..818e112b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageChangeListener.java | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | package cuchaz.enigma.gui.util; | 1 | package cuchaz.enigma.gui.util; |
| 2 | 2 | ||
| 3 | public interface LanguageChangeListener { | 3 | public interface LanguageChangeListener { |
| 4 | |||
| 5 | void retranslateUi(); | 4 | void retranslateUi(); |
| 6 | 5 | ||
| 7 | default boolean isValid() { | 6 | default boolean isValid() { |
| 8 | return true; | 7 | return true; |
| 9 | } | 8 | } |
| 10 | |||
| 11 | } | 9 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java index d3e63763..30a91809 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/LanguageUtil.java | |||
| @@ -4,7 +4,6 @@ import java.util.ArrayList; | |||
| 4 | import java.util.List; | 4 | import java.util.List; |
| 5 | 5 | ||
| 6 | public final class LanguageUtil { | 6 | public final class LanguageUtil { |
| 7 | |||
| 8 | private static final List<LanguageChangeListener> listeners = new ArrayList<>(); | 7 | private static final List<LanguageChangeListener> listeners = new ArrayList<>(); |
| 9 | 8 | ||
| 10 | public LanguageUtil() { | 9 | public LanguageUtil() { |
| @@ -21,5 +20,4 @@ public final class LanguageUtil { | |||
| 21 | public static void dispatchLanguageChange() { | 20 | public static void dispatchLanguageChange() { |
| 22 | listeners.forEach(LanguageChangeListener::retranslateUi); | 21 | listeners.forEach(LanguageChangeListener::retranslateUi); |
| 23 | } | 22 | } |
| 24 | |||
| 25 | } | 23 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java index d045c6d5..243f26fc 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleChangeListener.java | |||
| @@ -2,7 +2,5 @@ package cuchaz.enigma.gui.util; | |||
| 2 | 2 | ||
| 3 | @FunctionalInterface | 3 | @FunctionalInterface |
| 4 | public interface ScaleChangeListener { | 4 | public interface ScaleChangeListener { |
| 5 | |||
| 6 | void onScaleChanged(float scale, float oldScale); | 5 | void onScaleChanged(float scale, float oldScale); |
| 7 | |||
| 8 | } | 6 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java index 28e37693..bc587fa7 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/ScaleUtil.java | |||
| @@ -21,7 +21,6 @@ import de.sciss.syntaxpane.DefaultSyntaxKit; | |||
| 21 | import cuchaz.enigma.gui.config.UiConfig; | 21 | import cuchaz.enigma.gui.config.UiConfig; |
| 22 | 22 | ||
| 23 | public class ScaleUtil { | 23 | public class ScaleUtil { |
| 24 | |||
| 25 | private static List<ScaleChangeListener> listeners = new ArrayList<>(); | 24 | private static List<ScaleChangeListener> listeners = new ArrayList<>(); |
| 26 | 25 | ||
| 27 | public static void setScaleFactor(float scaleFactor) { | 26 | public static void setScaleFactor(float scaleFactor) { |
| @@ -110,15 +109,19 @@ public class ScaleUtil { | |||
| 110 | 109 | ||
| 111 | private static BasicTweaker createTweakerForCurrentLook(float dpiScaling) { | 110 | private static BasicTweaker createTweakerForCurrentLook(float dpiScaling) { |
| 112 | String testString = UIManager.getLookAndFeel().getName().toLowerCase(); | 111 | String testString = UIManager.getLookAndFeel().getName().toLowerCase(); |
| 112 | |||
| 113 | if (testString.contains("windows")) { | 113 | if (testString.contains("windows")) { |
| 114 | return new WindowsTweaker(dpiScaling, testString.contains("classic")); | 114 | return new WindowsTweaker(dpiScaling, testString.contains("classic")); |
| 115 | } | 115 | } |
| 116 | |||
| 116 | if (testString.contains("metal")) { | 117 | if (testString.contains("metal")) { |
| 117 | return new MetalTweaker(dpiScaling); | 118 | return new MetalTweaker(dpiScaling); |
| 118 | } | 119 | } |
| 120 | |||
| 119 | if (testString.contains("nimbus")) { | 121 | if (testString.contains("nimbus")) { |
| 120 | return new NimbusTweaker(dpiScaling); | 122 | return new NimbusTweaker(dpiScaling); |
| 121 | } | 123 | } |
| 124 | |||
| 122 | return new BasicTweaker(dpiScaling); | 125 | return new BasicTweaker(dpiScaling); |
| 123 | } | 126 | } |
| 124 | } | 127 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java index 8915264b..9d967b8c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/util/SingleTreeSelectionModel.java | |||
| @@ -4,8 +4,7 @@ import javax.swing.tree.DefaultTreeSelectionModel; | |||
| 4 | import javax.swing.tree.TreeSelectionModel; | 4 | import javax.swing.tree.TreeSelectionModel; |
| 5 | 5 | ||
| 6 | public class SingleTreeSelectionModel extends DefaultTreeSelectionModel { | 6 | public class SingleTreeSelectionModel extends DefaultTreeSelectionModel { |
| 7 | 7 | public SingleTreeSelectionModel() { | |
| 8 | public SingleTreeSelectionModel() { | 8 | this.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); |
| 9 | this.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); | 9 | } |
| 10 | } | ||
| 11 | } | 10 | } |
diff --git a/enigma/build.gradle b/enigma/build.gradle index b4a40629..13fb6b50 100644 --- a/enigma/build.gradle +++ b/enigma/build.gradle | |||
| @@ -1,19 +1,19 @@ | |||
| 1 | configurations { | 1 | configurations { |
| 2 | proGuard | 2 | proGuard |
| 3 | } | 3 | } |
| 4 | 4 | ||
| 5 | dependencies { | 5 | dependencies { |
| 6 | implementation 'org.ow2.asm:asm:9.3' | 6 | implementation 'org.ow2.asm:asm:9.3' |
| 7 | implementation 'org.ow2.asm:asm-commons:9.3' | 7 | implementation 'org.ow2.asm:asm-commons:9.3' |
| 8 | implementation 'org.ow2.asm:asm-tree:9.3' | 8 | implementation 'org.ow2.asm:asm-tree:9.3' |
| 9 | implementation 'org.ow2.asm:asm-util:9.3' | 9 | implementation 'org.ow2.asm:asm-util:9.3' |
| 10 | 10 | ||
| 11 | implementation 'net.fabricmc:procyon-fabric-compilertools:0.5.35.13' | 11 | implementation 'net.fabricmc:procyon-fabric-compilertools:0.5.35.13' |
| 12 | implementation 'net.fabricmc:cfr:0.1.0' | 12 | implementation 'net.fabricmc:cfr:0.1.0' |
| 13 | 13 | ||
| 14 | proGuard 'com.guardsquare:proguard-base:7.2.0-beta2' | 14 | proGuard 'com.guardsquare:proguard-base:7.2.0-beta2' |
| 15 | 15 | ||
| 16 | testImplementation 'com.google.jimfs:jimfs:1.2' | 16 | testImplementation 'com.google.jimfs:jimfs:1.2' |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | // Generate "version.txt" file | 19 | // Generate "version.txt" file |
| @@ -21,11 +21,11 @@ dependencies { | |||
| 21 | ext.genOutputDir = file("$buildDir/generated-resources") | 21 | ext.genOutputDir = file("$buildDir/generated-resources") |
| 22 | 22 | ||
| 23 | task generateVersionFile { | 23 | task generateVersionFile { |
| 24 | ext.outputFile = file("$genOutputDir/version.txt") | 24 | ext.outputFile = file("$genOutputDir/version.txt") |
| 25 | outputs.file(outputFile) | 25 | outputs.file(outputFile) |
| 26 | doLast { | 26 | doLast { |
| 27 | outputFile.text = "${project.version}" | 27 | outputFile.text = "${project.version}" |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | sourceSets.main.output.dir genOutputDir, builtBy: generateVersionFile | 31 | sourceSets.main.output.dir genOutputDir, builtBy: generateVersionFile |
| @@ -36,29 +36,29 @@ def libraryJarsArg = "<java.home>/jmods" | |||
| 36 | 36 | ||
| 37 | // If your test fails for class file version problem with proguard, run gradle with -Dorg.gradle.java.home="<older jdk>" flag | 37 | // If your test fails for class file version problem with proguard, run gradle with -Dorg.gradle.java.home="<older jdk>" flag |
| 38 | file('src/test/java/cuchaz/enigma/inputs').listFiles().each { theFile -> | 38 | file('src/test/java/cuchaz/enigma/inputs').listFiles().each { theFile -> |
| 39 | if (theFile.directory) { | 39 | if (theFile.directory) { |
| 40 | task("${theFile.name}TestJar", type: Jar) { | 40 | task("${theFile.name}TestJar", type: Jar) { |
| 41 | from(sourceSets.test.output) { | 41 | from(sourceSets.test.output) { |
| 42 | include "cuchaz/enigma/inputs/$theFile.name/**/*.class" | 42 | include "cuchaz/enigma/inputs/$theFile.name/**/*.class" |
| 43 | include 'cuchaz/enigma/inputs/Keep.class' | 43 | include 'cuchaz/enigma/inputs/Keep.class' |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | archiveFileName = theFile.name + '.jar' | 46 | archiveFileName = theFile.name + '.jar' |
| 47 | destinationDirectory = file('build/test-inputs') | 47 | destinationDirectory = file('build/test-inputs') |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | task("${theFile.name}TestObf", type: JavaExec, | 50 | task("${theFile.name}TestObf", type: JavaExec, |
| 51 | dependsOn: "${theFile.name}TestJar") { | 51 | dependsOn: "${theFile.name}TestJar") { |
| 52 | mainClass = 'proguard.ProGuard' | 52 | mainClass = 'proguard.ProGuard' |
| 53 | classpath configurations.proGuard | 53 | classpath configurations.proGuard |
| 54 | 54 | ||
| 55 | args '@src/test/resources/proguard-test.conf', '-injars', file('build/test-inputs/' + | 55 | args '@src/test/resources/proguard-test.conf', '-injars', file('build/test-inputs/' + |
| 56 | "${theFile.name}.jar"), '-libraryjars', libraryJarsArg, | 56 | "${theFile.name}.jar"), '-libraryjars', libraryJarsArg, |
| 57 | '-outjars', file('build/test-obf/' + "${theFile.name}.jar") | 57 | '-outjars', file('build/test-obf/' + "${theFile.name}.jar") |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | test.dependsOn "${theFile.name}TestObf" | 60 | test.dependsOn "${theFile.name}TestObf" |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | test.dependsOn 'translationTestObf' | 64 | test.dependsOn 'translationTestObf' |
diff --git a/enigma/src/main/java/cuchaz/enigma/Enigma.java b/enigma/src/main/java/cuchaz/enigma/Enigma.java index a37f074b..696a848d 100644 --- a/enigma/src/main/java/cuchaz/enigma/Enigma.java +++ b/enigma/src/main/java/cuchaz/enigma/Enigma.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| @@ -35,12 +35,12 @@ import cuchaz.enigma.classprovider.JarClassProvider; | |||
| 35 | import cuchaz.enigma.utils.Utils; | 35 | import cuchaz.enigma.utils.Utils; |
| 36 | 36 | ||
| 37 | public class Enigma { | 37 | public class Enigma { |
| 38 | public static final String NAME = "Enigma"; | 38 | public static final String NAME = "Enigma"; |
| 39 | public static final String VERSION; | 39 | public static final String VERSION; |
| 40 | public static final String URL = "https://fabricmc.net"; | 40 | public static final String URL = "https://fabricmc.net"; |
| 41 | public static final int ASM_VERSION = Opcodes.ASM9; | 41 | public static final int ASM_VERSION = Opcodes.ASM9; |
| 42 | 42 | ||
| 43 | private final EnigmaProfile profile; | 43 | private final EnigmaProfile profile; |
| 44 | private final EnigmaServices services; | 44 | private final EnigmaServices services; |
| 45 | 45 | ||
| 46 | private Enigma(EnigmaProfile profile, EnigmaServices services) { | 46 | private Enigma(EnigmaProfile profile, EnigmaServices services) { |
| @@ -97,6 +97,7 @@ public class Enigma { | |||
| 97 | 97 | ||
| 98 | public Enigma build() { | 98 | public Enigma build() { |
| 99 | PluginContext pluginContext = new PluginContext(profile); | 99 | PluginContext pluginContext = new PluginContext(profile); |
| 100 | |||
| 100 | for (EnigmaPlugin plugin : plugins) { | 101 | for (EnigmaPlugin plugin : plugins) { |
| 101 | plugin.init(pluginContext); | 102 | plugin.init(pluginContext); |
| 102 | } | 103 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java index daf27274..f95bf1e3 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProfile.java | |||
| @@ -1,5 +1,20 @@ | |||
| 1 | package cuchaz.enigma; | 1 | package cuchaz.enigma; |
| 2 | 2 | ||
| 3 | import java.io.BufferedReader; | ||
| 4 | import java.io.IOException; | ||
| 5 | import java.io.InputStreamReader; | ||
| 6 | import java.io.Reader; | ||
| 7 | import java.lang.reflect.Type; | ||
| 8 | import java.nio.charset.StandardCharsets; | ||
| 9 | import java.nio.file.Files; | ||
| 10 | import java.nio.file.Path; | ||
| 11 | import java.util.Collections; | ||
| 12 | import java.util.List; | ||
| 13 | import java.util.Map; | ||
| 14 | import java.util.Optional; | ||
| 15 | |||
| 16 | import javax.annotation.Nullable; | ||
| 17 | |||
| 3 | import com.google.common.collect.ImmutableMap; | 18 | import com.google.common.collect.ImmutableMap; |
| 4 | import com.google.gson.Gson; | 19 | import com.google.gson.Gson; |
| 5 | import com.google.gson.GsonBuilder; | 20 | import com.google.gson.GsonBuilder; |
| @@ -10,31 +25,16 @@ import com.google.gson.JsonObject; | |||
| 10 | import com.google.gson.JsonParseException; | 25 | import com.google.gson.JsonParseException; |
| 11 | import com.google.gson.annotations.SerializedName; | 26 | import com.google.gson.annotations.SerializedName; |
| 12 | import com.google.gson.reflect.TypeToken; | 27 | import com.google.gson.reflect.TypeToken; |
| 28 | |||
| 13 | import cuchaz.enigma.api.service.EnigmaServiceType; | 29 | import cuchaz.enigma.api.service.EnigmaServiceType; |
| 14 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 30 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 15 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 31 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 16 | 32 | ||
| 17 | import javax.annotation.Nullable; | ||
| 18 | import java.io.BufferedReader; | ||
| 19 | import java.io.IOException; | ||
| 20 | import java.io.InputStreamReader; | ||
| 21 | import java.io.Reader; | ||
| 22 | import java.lang.reflect.Type; | ||
| 23 | import java.nio.charset.StandardCharsets; | ||
| 24 | import java.nio.file.Files; | ||
| 25 | import java.nio.file.Path; | ||
| 26 | import java.util.Collections; | ||
| 27 | import java.util.List; | ||
| 28 | import java.util.Map; | ||
| 29 | import java.util.Optional; | ||
| 30 | |||
| 31 | public final class EnigmaProfile { | 33 | public final class EnigmaProfile { |
| 32 | public static final EnigmaProfile EMPTY = new EnigmaProfile(new ServiceContainer(ImmutableMap.of())); | 34 | public static final EnigmaProfile EMPTY = new EnigmaProfile(new ServiceContainer(ImmutableMap.of())); |
| 33 | 35 | ||
| 34 | private static final MappingSaveParameters DEFAULT_MAPPING_SAVE_PARAMETERS = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 36 | private static final MappingSaveParameters DEFAULT_MAPPING_SAVE_PARAMETERS = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 35 | private static final Gson GSON = new GsonBuilder() | 37 | private static final Gson GSON = new GsonBuilder().registerTypeAdapter(ServiceContainer.class, (JsonDeserializer<ServiceContainer>) EnigmaProfile::loadServiceContainer).create(); |
| 36 | .registerTypeAdapter(ServiceContainer.class, (JsonDeserializer<ServiceContainer>) EnigmaProfile::loadServiceContainer) | ||
| 37 | .create(); | ||
| 38 | private static final Type SERVICE_LIST_TYPE = new TypeToken<List<Service>>() { | 38 | private static final Type SERVICE_LIST_TYPE = new TypeToken<List<Service>>() { |
| 39 | }.getType(); | 39 | }.getType(); |
| 40 | 40 | ||
| @@ -78,6 +78,7 @@ public final class EnigmaProfile { | |||
| 78 | 78 | ||
| 79 | for (Map.Entry<String, JsonElement> entry : object.entrySet()) { | 79 | for (Map.Entry<String, JsonElement> entry : object.entrySet()) { |
| 80 | JsonElement value = entry.getValue(); | 80 | JsonElement value = entry.getValue(); |
| 81 | |||
| 81 | if (value.isJsonObject()) { | 82 | if (value.isJsonObject()) { |
| 82 | builder.put(entry.getKey(), Collections.singletonList(GSON.fromJson(value, Service.class))); | 83 | builder.put(entry.getKey(), Collections.singletonList(GSON.fromJson(value, Service.class))); |
| 83 | } else if (value.isJsonArray()) { | 84 | } else if (value.isJsonArray()) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java index 4f50f2ff..15d5e980 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java | |||
| @@ -18,16 +18,16 @@ import java.util.stream.Stream; | |||
| 18 | 18 | ||
| 19 | import com.google.common.base.Functions; | 19 | import com.google.common.base.Functions; |
| 20 | import com.google.common.base.Preconditions; | 20 | import com.google.common.base.Preconditions; |
| 21 | import cuchaz.enigma.api.service.ObfuscationTestService; | ||
| 22 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; | ||
| 23 | import org.objectweb.asm.ClassWriter; | 21 | import org.objectweb.asm.ClassWriter; |
| 24 | import org.objectweb.asm.tree.ClassNode; | 22 | import org.objectweb.asm.tree.ClassNode; |
| 25 | 23 | ||
| 26 | import cuchaz.enigma.analysis.EntryReference; | 24 | import cuchaz.enigma.analysis.EntryReference; |
| 27 | import cuchaz.enigma.analysis.index.JarIndex; | 25 | import cuchaz.enigma.analysis.index.JarIndex; |
| 28 | import cuchaz.enigma.api.service.NameProposalService; | 26 | import cuchaz.enigma.api.service.NameProposalService; |
| 27 | import cuchaz.enigma.api.service.ObfuscationTestService; | ||
| 29 | import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; | 28 | import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; |
| 30 | import cuchaz.enigma.classprovider.ClassProvider; | 29 | import cuchaz.enigma.classprovider.ClassProvider; |
| 30 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; | ||
| 31 | import cuchaz.enigma.source.Decompiler; | 31 | import cuchaz.enigma.source.Decompiler; |
| 32 | import cuchaz.enigma.source.DecompilerService; | 32 | import cuchaz.enigma.source.DecompilerService; |
| 33 | import cuchaz.enigma.source.SourceSettings; | 33 | import cuchaz.enigma.source.SourceSettings; |
| @@ -101,6 +101,7 @@ public class EnigmaProject { | |||
| 101 | DeltaTrackingTree<EntryMapping> mappings = mapper.getObfToDeobf(); | 101 | DeltaTrackingTree<EntryMapping> mappings = mapper.getObfToDeobf(); |
| 102 | 102 | ||
| 103 | Collection<Entry<?>> dropped = dropMappings(mappings, progress); | 103 | Collection<Entry<?>> dropped = dropMappings(mappings, progress); |
| 104 | |||
| 104 | for (Entry<?> entry : dropped) { | 105 | for (Entry<?> entry : dropped) { |
| 105 | mappings.trackChange(entry); | 106 | mappings.trackChange(entry); |
| 106 | } | 107 | } |
| @@ -112,6 +113,7 @@ public class EnigmaProject { | |||
| 112 | MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress); | 113 | MappingsChecker.Dropped dropped = checker.dropBrokenMappings(progress); |
| 113 | 114 | ||
| 114 | Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings(); | 115 | Map<Entry<?>, String> droppedMappings = dropped.getDroppedMappings(); |
| 116 | |||
| 115 | for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) { | 117 | for (Map.Entry<Entry<?>, String> mapping : droppedMappings.entrySet()) { |
| 116 | System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped."); | 118 | System.out.println("WARNING: Couldn't find " + mapping.getKey() + " (" + mapping.getValue() + ") in jar. Mapping was dropped."); |
| 117 | } | 119 | } |
| @@ -124,6 +126,7 @@ public class EnigmaProject { | |||
| 124 | // HACKHACK: Object methods are not obfuscated identifiers | 126 | // HACKHACK: Object methods are not obfuscated identifiers |
| 125 | String name = obfMethodEntry.getName(); | 127 | String name = obfMethodEntry.getName(); |
| 126 | String sig = obfMethodEntry.getDesc().toString(); | 128 | String sig = obfMethodEntry.getDesc().toString(); |
| 129 | |||
| 127 | //TODO replace with a map or check if declaring class is java.lang.Object | 130 | //TODO replace with a map or check if declaring class is java.lang.Object |
| 128 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { | 131 | if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { |
| 129 | return false; | 132 | return false; |
| @@ -163,6 +166,7 @@ public class EnigmaProject { | |||
| 163 | String name = entry.getName(); | 166 | String name = entry.getName(); |
| 164 | 167 | ||
| 165 | List<ObfuscationTestService> obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE); | 168 | List<ObfuscationTestService> obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE); |
| 169 | |||
| 166 | if (!obfuscationTestServices.isEmpty()) { | 170 | if (!obfuscationTestServices.isEmpty()) { |
| 167 | for (ObfuscationTestService service : obfuscationTestServices) { | 171 | for (ObfuscationTestService service : obfuscationTestServices) { |
| 168 | if (service.testDeobfuscated(entry)) { | 172 | if (service.testDeobfuscated(entry)) { |
| @@ -172,6 +176,7 @@ public class EnigmaProject { | |||
| 172 | } | 176 | } |
| 173 | 177 | ||
| 174 | List<NameProposalService> nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE); | 178 | List<NameProposalService> nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE); |
| 179 | |||
| 175 | if (!nameProposalServices.isEmpty()) { | 180 | if (!nameProposalServices.isEmpty()) { |
| 176 | for (NameProposalService service : nameProposalServices) { | 181 | for (NameProposalService service : nameProposalServices) { |
| 177 | if (service.proposeName(entry, mapper).isPresent()) { | 182 | if (service.proposeName(entry, mapper).isPresent()) { |
| @@ -181,6 +186,7 @@ public class EnigmaProject { | |||
| 181 | } | 186 | } |
| 182 | 187 | ||
| 183 | String mappedName = mapper.deobfuscate(entry).getName(); | 188 | String mappedName = mapper.deobfuscate(entry).getName(); |
| 189 | |||
| 184 | if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) { | 190 | if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) { |
| 185 | return false; | 191 | return false; |
| 186 | } | 192 | } |
| @@ -198,22 +204,20 @@ public class EnigmaProject { | |||
| 198 | AtomicInteger count = new AtomicInteger(); | 204 | AtomicInteger count = new AtomicInteger(); |
| 199 | progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating")); | 205 | progress.init(classEntries.size(), I18n.translate("progress.classes.deobfuscating")); |
| 200 | 206 | ||
| 201 | Map<String, ClassNode> compiled = classEntries.parallelStream() | 207 | Map<String, ClassNode> compiled = classEntries.parallelStream().map(entry -> { |
| 202 | .map(entry -> { | 208 | ClassEntry translatedEntry = deobfuscator.translate(entry); |
| 203 | ClassEntry translatedEntry = deobfuscator.translate(entry); | 209 | progress.step(count.getAndIncrement(), translatedEntry.toString()); |
| 204 | progress.step(count.getAndIncrement(), translatedEntry.toString()); | ||
| 205 | 210 | ||
| 206 | ClassNode node = fixingClassProvider.get(entry.getFullName()); | 211 | ClassNode node = fixingClassProvider.get(entry.getFullName()); |
| 207 | if (node != null) { | ||
| 208 | ClassNode translatedNode = new ClassNode(); | ||
| 209 | node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode)); | ||
| 210 | return translatedNode; | ||
| 211 | } | ||
| 212 | 212 | ||
| 213 | return null; | 213 | if (node != null) { |
| 214 | }) | 214 | ClassNode translatedNode = new ClassNode(); |
| 215 | .filter(Objects::nonNull) | 215 | node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, translatedNode)); |
| 216 | .collect(Collectors.toMap(n -> n.name, Functions.identity())); | 216 | return translatedNode; |
| 217 | } | ||
| 218 | |||
| 219 | return null; | ||
| 220 | }).filter(Objects::nonNull).collect(Collectors.toMap(n -> n.name, Functions.identity())); | ||
| 217 | 221 | ||
| 218 | return new JarExport(mapper, compiled); | 222 | return new JarExport(mapper, compiled); |
| 219 | } | 223 | } |
| @@ -254,9 +258,7 @@ public class EnigmaProject { | |||
| 254 | } | 258 | } |
| 255 | 259 | ||
| 256 | public Stream<ClassSource> decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { | 260 | public Stream<ClassSource> decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { |
| 257 | Collection<ClassNode> classes = this.compiled.values().stream() | 261 | Collection<ClassNode> classes = this.compiled.values().stream().filter(classNode -> classNode.name.indexOf('$') == -1).toList(); |
| 258 | .filter(classNode -> classNode.name.indexOf('$') == -1) | ||
| 259 | .toList(); | ||
| 260 | 262 | ||
| 261 | progress.init(classes.size(), I18n.translate("progress.classes.decompiling")); | 263 | progress.init(classes.size(), I18n.translate("progress.classes.decompiling")); |
| 262 | 264 | ||
| @@ -265,33 +267,34 @@ public class EnigmaProject { | |||
| 265 | 267 | ||
| 266 | AtomicInteger count = new AtomicInteger(); | 268 | AtomicInteger count = new AtomicInteger(); |
| 267 | 269 | ||
| 268 | return classes.parallelStream() | 270 | return classes.parallelStream().map(translatedNode -> { |
| 269 | .map(translatedNode -> { | 271 | progress.step(count.getAndIncrement(), translatedNode.name); |
| 270 | progress.step(count.getAndIncrement(), translatedNode.name); | 272 | |
| 271 | 273 | String source = null; | |
| 272 | String source = null; | 274 | |
| 273 | try { | 275 | try { |
| 274 | source = decompileClass(translatedNode, decompiler); | 276 | source = decompileClass(translatedNode, decompiler); |
| 275 | } catch (Throwable throwable) { | 277 | } catch (Throwable throwable) { |
| 276 | switch (errorStrategy) { | 278 | switch (errorStrategy) { |
| 277 | case PROPAGATE: throw throwable; | 279 | case PROPAGATE: |
| 278 | case IGNORE: break; | 280 | throw throwable; |
| 279 | case TRACE_AS_SOURCE: { | 281 | case IGNORE: |
| 280 | StringWriter writer = new StringWriter(); | 282 | break; |
| 281 | throwable.printStackTrace(new PrintWriter(writer)); | 283 | case TRACE_AS_SOURCE: { |
| 282 | source = writer.toString(); | 284 | StringWriter writer = new StringWriter(); |
| 283 | break; | 285 | throwable.printStackTrace(new PrintWriter(writer)); |
| 284 | } | 286 | source = writer.toString(); |
| 285 | } | 287 | break; |
| 286 | } | 288 | } |
| 287 | 289 | } | |
| 288 | if (source == null) { | 290 | } |
| 289 | return null; | 291 | |
| 290 | } | 292 | if (source == null) { |
| 291 | 293 | return null; | |
| 292 | return new ClassSource(translatedNode.name, source); | 294 | } |
| 293 | }) | 295 | |
| 294 | .filter(Objects::nonNull); | 296 | return new ClassSource(translatedNode.name, source); |
| 297 | }).filter(Objects::nonNull); | ||
| 295 | } | 298 | } |
| 296 | 299 | ||
| 297 | private String decompileClass(ClassNode translatedNode, Decompiler decompiler) { | 300 | private String decompileClass(ClassNode translatedNode, Decompiler decompiler) { |
| @@ -310,6 +313,7 @@ public class EnigmaProject { | |||
| 310 | progress.init(decompiled.size(), I18n.translate("progress.sources.writing")); | 313 | progress.init(decompiled.size(), I18n.translate("progress.sources.writing")); |
| 311 | 314 | ||
| 312 | int count = 0; | 315 | int count = 0; |
| 316 | |||
| 313 | for (ClassSource source : decompiled) { | 317 | for (ClassSource source : decompiled) { |
| 314 | progress.step(count++, source.name); | 318 | progress.step(count++, source.name); |
| 315 | 319 | ||
| @@ -329,7 +333,6 @@ public class EnigmaProject { | |||
| 329 | } | 333 | } |
| 330 | 334 | ||
| 331 | public void writeTo(Path path) throws IOException { | 335 | public void writeTo(Path path) throws IOException { |
| 332 | Files.createDirectories(path.getParent()); | ||
| 333 | try (BufferedWriter writer = Files.newBufferedWriter(path)) { | 336 | try (BufferedWriter writer = Files.newBufferedWriter(path)) { |
| 334 | writer.write(source); | 337 | writer.write(source); |
| 335 | } | 338 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java index df3b7bba..bbdc6846 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaServices.java | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | package cuchaz.enigma; | 1 | package cuchaz.enigma; |
| 2 | 2 | ||
| 3 | import java.util.List; | ||
| 4 | |||
| 3 | import com.google.common.collect.ImmutableListMultimap; | 5 | import com.google.common.collect.ImmutableListMultimap; |
| 6 | |||
| 4 | import cuchaz.enigma.api.service.EnigmaService; | 7 | import cuchaz.enigma.api.service.EnigmaService; |
| 5 | import cuchaz.enigma.api.service.EnigmaServiceType; | 8 | import cuchaz.enigma.api.service.EnigmaServiceType; |
| 6 | 9 | ||
| 7 | import java.util.List; | ||
| 8 | |||
| 9 | public final class EnigmaServices { | 10 | public final class EnigmaServices { |
| 10 | private final ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services; | 11 | private final ImmutableListMultimap<EnigmaServiceType<?>, EnigmaService> services; |
| 11 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java index 82ca6692..cc7d121f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/Access.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/Access.java | |||
| @@ -1,23 +1,25 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.AccessFlags; | ||
| 15 | |||
| 16 | import java.lang.reflect.Modifier; | 14 | import java.lang.reflect.Modifier; |
| 17 | 15 | ||
| 18 | public enum Access { | 16 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 19 | 17 | ||
| 20 | PUBLIC, PROTECTED, PACKAGE, PRIVATE; | 18 | public enum Access { |
| 19 | PUBLIC, | ||
| 20 | PROTECTED, | ||
| 21 | PACKAGE, | ||
| 22 | PRIVATE; | ||
| 21 | 23 | ||
| 22 | public static Access get(AccessFlags flags) { | 24 | public static Access get(AccessFlags flags) { |
| 23 | return get(flags.getFlags()); | 25 | return get(flags.getFlags()); |
| @@ -37,6 +39,7 @@ public enum Access { | |||
| 37 | } else if (!isPublic && !isProtected && !isPrivate) { | 39 | } else if (!isPublic && !isProtected && !isPrivate) { |
| 38 | return PACKAGE; | 40 | return PACKAGE; |
| 39 | } | 41 | } |
| 42 | |||
| 40 | // assume public by default | 43 | // assume public by default |
| 41 | return PUBLIC; | 44 | return PUBLIC; |
| 42 | } | 45 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java index 013c52f5..45dac2c1 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java | |||
| @@ -1,17 +1,13 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.Enigma; | 3 | import java.util.ArrayList; |
| 4 | import cuchaz.enigma.api.EnigmaPlugin; | 4 | import java.util.HashMap; |
| 5 | import cuchaz.enigma.api.EnigmaPluginContext; | 5 | import java.util.HashSet; |
| 6 | import cuchaz.enigma.api.service.JarIndexerService; | 6 | import java.util.List; |
| 7 | import cuchaz.enigma.api.service.NameProposalService; | 7 | import java.util.Map; |
| 8 | import cuchaz.enigma.source.DecompilerService; | 8 | import java.util.Optional; |
| 9 | import cuchaz.enigma.source.Decompilers; | 9 | import java.util.Set; |
| 10 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 10 | |
| 11 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 14 | import cuchaz.enigma.utils.Pair; | ||
| 15 | import org.objectweb.asm.ClassVisitor; | 11 | import org.objectweb.asm.ClassVisitor; |
| 16 | import org.objectweb.asm.FieldVisitor; | 12 | import org.objectweb.asm.FieldVisitor; |
| 17 | import org.objectweb.asm.MethodVisitor; | 13 | import org.objectweb.asm.MethodVisitor; |
| @@ -27,16 +23,20 @@ import org.objectweb.asm.tree.analysis.Frame; | |||
| 27 | import org.objectweb.asm.tree.analysis.SourceInterpreter; | 23 | import org.objectweb.asm.tree.analysis.SourceInterpreter; |
| 28 | import org.objectweb.asm.tree.analysis.SourceValue; | 24 | import org.objectweb.asm.tree.analysis.SourceValue; |
| 29 | 25 | ||
| 30 | import java.util.ArrayList; | 26 | import cuchaz.enigma.Enigma; |
| 31 | import java.util.HashMap; | 27 | import cuchaz.enigma.api.EnigmaPlugin; |
| 32 | import java.util.HashSet; | 28 | import cuchaz.enigma.api.EnigmaPluginContext; |
| 33 | import java.util.List; | 29 | import cuchaz.enigma.api.service.JarIndexerService; |
| 34 | import java.util.Map; | 30 | import cuchaz.enigma.api.service.NameProposalService; |
| 35 | import java.util.Optional; | 31 | import cuchaz.enigma.source.DecompilerService; |
| 36 | import java.util.Set; | 32 | import cuchaz.enigma.source.Decompilers; |
| 33 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 34 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 35 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 36 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 37 | import cuchaz.enigma.utils.Pair; | ||
| 37 | 38 | ||
| 38 | public final class BuiltinPlugin implements EnigmaPlugin { | 39 | public final class BuiltinPlugin implements EnigmaPlugin { |
| 39 | |||
| 40 | public BuiltinPlugin() { | 40 | public BuiltinPlugin() { |
| 41 | } | 41 | } |
| 42 | 42 | ||
| @@ -61,7 +61,6 @@ public final class BuiltinPlugin implements EnigmaPlugin { | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | private static final class EnumFieldNameFindingVisitor extends ClassVisitor { | 63 | private static final class EnumFieldNameFindingVisitor extends ClassVisitor { |
| 64 | |||
| 65 | private ClassEntry clazz; | 64 | private ClassEntry clazz; |
| 66 | private String className; | 65 | private String className; |
| 67 | private final Map<Entry<?>, String> mappings; | 66 | private final Map<Entry<?>, String> mappings; |
| @@ -89,6 +88,7 @@ public final class BuiltinPlugin implements EnigmaPlugin { | |||
| 89 | throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!"); | 88 | throw new IllegalArgumentException("Found two enum fields with the same name \"" + name + "\" and desc \"" + descriptor + "\"!"); |
| 90 | } | 89 | } |
| 91 | } | 90 | } |
| 91 | |||
| 92 | return super.visitField(access, name, descriptor, signature, value); | 92 | return super.visitField(access, name, descriptor, signature, value); |
| 93 | } | 93 | } |
| 94 | 94 | ||
| @@ -99,12 +99,14 @@ public final class BuiltinPlugin implements EnigmaPlugin { | |||
| 99 | classInits.add(node); | 99 | classInits.add(node); |
| 100 | return node; | 100 | return node; |
| 101 | } | 101 | } |
| 102 | |||
| 102 | return super.visitMethod(access, name, descriptor, signature, exceptions); | 103 | return super.visitMethod(access, name, descriptor, signature, exceptions); |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | @Override | 106 | @Override |
| 106 | public void visitEnd() { | 107 | public void visitEnd() { |
| 107 | super.visitEnd(); | 108 | super.visitEnd(); |
| 109 | |||
| 108 | try { | 110 | try { |
| 109 | collectResults(); | 111 | collectResults(); |
| 110 | } catch (Exception ex) { | 112 | } catch (Exception ex) { |
| @@ -118,21 +120,18 @@ public final class BuiltinPlugin implements EnigmaPlugin { | |||
| 118 | 120 | ||
| 119 | for (MethodNode mn : classInits) { | 121 | for (MethodNode mn : classInits) { |
| 120 | Frame<SourceValue>[] frames = analyzer.analyze(className, mn); | 122 | Frame<SourceValue>[] frames = analyzer.analyze(className, mn); |
| 121 | |||
| 122 | InsnList instrs = mn.instructions; | 123 | InsnList instrs = mn.instructions; |
| 124 | |||
| 123 | for (int i = 1; i < instrs.size(); i++) { | 125 | for (int i = 1; i < instrs.size(); i++) { |
| 124 | AbstractInsnNode instr1 = instrs.get(i - 1); | 126 | AbstractInsnNode instr1 = instrs.get(i - 1); |
| 125 | AbstractInsnNode instr2 = instrs.get(i); | 127 | AbstractInsnNode instr2 = instrs.get(i); |
| 126 | String s = null; | 128 | String s = null; |
| 127 | 129 | ||
| 128 | if (instr2.getOpcode() == Opcodes.PUTSTATIC | 130 | if (instr2.getOpcode() == Opcodes.PUTSTATIC && ((FieldInsnNode) instr2).owner.equals(owner) && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc)) && instr1.getOpcode() == Opcodes.INVOKESPECIAL && "<init>".equals( |
| 129 | && ((FieldInsnNode) instr2).owner.equals(owner) | 131 | ((MethodInsnNode) instr1).name)) { |
| 130 | && enumFields.contains(new Pair<>(((FieldInsnNode) instr2).name, ((FieldInsnNode) instr2).desc)) | ||
| 131 | && instr1.getOpcode() == Opcodes.INVOKESPECIAL | ||
| 132 | && "<init>".equals(((MethodInsnNode) instr1).name)) { | ||
| 133 | |||
| 134 | for (int j = 0; j < frames[i - 1].getStackSize(); j++) { | 132 | for (int j = 0; j < frames[i - 1].getStackSize(); j++) { |
| 135 | SourceValue sv = frames[i - 1].getStack(j); | 133 | SourceValue sv = frames[i - 1].getStack(j); |
| 134 | |||
| 136 | for (AbstractInsnNode ci : sv.insns) { | 135 | for (AbstractInsnNode ci : sv.insns) { |
| 137 | if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) { | 136 | if (ci instanceof LdcInsnNode && ((LdcInsnNode) ci).cst instanceof String) { |
| 138 | //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) { | 137 | //if (s == null || !s.equals(((LdcInsnNode) ci).cst)) { |
| @@ -148,6 +147,7 @@ public final class BuiltinPlugin implements EnigmaPlugin { | |||
| 148 | if (s != null) { | 147 | if (s != null) { |
| 149 | mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s); | 148 | mappings.put(new FieldEntry(clazz, ((FieldInsnNode) instr2).name, new TypeDescriptor(((FieldInsnNode) instr2).desc)), s); |
| 150 | } | 149 | } |
| 150 | |||
| 151 | // report otherwise? | 151 | // report otherwise? |
| 152 | } | 152 | } |
| 153 | } | 153 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index 0fc44ca6..8ef28d9f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java | |||
| @@ -1,27 +1,29 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import java.util.Collection; | ||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 14 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
| 20 | |||
| 15 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 21 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 16 | import cuchaz.enigma.analysis.index.JarIndex; | 22 | import cuchaz.enigma.analysis.index.JarIndex; |
| 17 | import cuchaz.enigma.translation.Translator; | 23 | import cuchaz.enigma.translation.Translator; |
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 24 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 25 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 20 | 26 | ||
| 21 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 22 | import java.util.Collection; | ||
| 23 | import java.util.List; | ||
| 24 | |||
| 25 | public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { | 27 | public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { |
| 26 | private final Translator translator; | 28 | private final Translator translator; |
| 27 | private final ClassEntry entry; | 29 | private final ClassEntry entry; |
| @@ -40,10 +42,12 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { | |||
| 40 | // recurse | 42 | // recurse |
| 41 | for (int i = 0; i < node.getChildCount(); i++) { | 43 | for (int i = 0; i < node.getChildCount(); i++) { |
| 42 | ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); | 44 | ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode) node.getChildAt(i), entry); |
| 45 | |||
| 43 | if (foundNode != null) { | 46 | if (foundNode != null) { |
| 44 | return foundNode; | 47 | return foundNode; |
| 45 | } | 48 | } |
| 46 | } | 49 | } |
| 50 | |||
| 47 | return null; | 51 | return null; |
| 48 | } | 52 | } |
| 49 | 53 | ||
| @@ -62,6 +66,7 @@ public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { | |||
| 62 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); | 66 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); |
| 63 | 67 | ||
| 64 | Collection<ClassEntry> inheritors = inheritanceIndex.getChildren(entry); | 68 | Collection<ClassEntry> inheritors = inheritanceIndex.getChildren(entry); |
| 69 | |||
| 65 | for (ClassEntry inheritor : inheritors) { | 70 | for (ClassEntry inheritor : inheritors) { |
| 66 | nodes.add(new ClassImplementationsTreeNode(translator, inheritor)); | 71 | nodes.add(new ClassImplementationsTreeNode(translator, inheritor)); |
| 67 | } | 72 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index 788c5347..24da23c5 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java | |||
| @@ -1,24 +1,26 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import java.util.List; | ||
| 15 | |||
| 16 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 17 | |||
| 14 | import com.google.common.collect.Lists; | 18 | import com.google.common.collect.Lists; |
| 19 | |||
| 15 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 20 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 16 | import cuchaz.enigma.translation.Translator; | 21 | import cuchaz.enigma.translation.Translator; |
| 17 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 22 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 18 | 23 | ||
| 19 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 20 | import java.util.List; | ||
| 21 | |||
| 22 | public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { | 24 | public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { |
| 23 | private final Translator translator; | 25 | private final Translator translator; |
| 24 | private final ClassEntry obfClassEntry; | 26 | private final ClassEntry obfClassEntry; |
| @@ -37,10 +39,12 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { | |||
| 37 | // recurse | 39 | // recurse |
| 38 | for (int i = 0; i < node.getChildCount(); i++) { | 40 | for (int i = 0; i < node.getChildCount(); i++) { |
| 39 | ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); | 41 | ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode) node.getChildAt(i), entry); |
| 42 | |||
| 40 | if (foundNode != null) { | 43 | if (foundNode != null) { |
| 41 | return foundNode; | 44 | return foundNode; |
| 42 | } | 45 | } |
| 43 | } | 46 | } |
| 47 | |||
| 44 | return null; | 48 | return null; |
| 45 | } | 49 | } |
| 46 | 50 | ||
| @@ -63,6 +67,7 @@ public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { | |||
| 63 | public void load(InheritanceIndex ancestries, boolean recurse) { | 67 | public void load(InheritanceIndex ancestries, boolean recurse) { |
| 64 | // get all the child nodes | 68 | // get all the child nodes |
| 65 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); | 69 | List<ClassInheritanceTreeNode> nodes = Lists.newArrayList(); |
| 70 | |||
| 66 | for (ClassEntry inheritor : ancestries.getChildren(this.obfClassEntry)) { | 71 | for (ClassEntry inheritor : ancestries.getChildren(this.obfClassEntry)) { |
| 67 | nodes.add(new ClassInheritanceTreeNode(translator, inheritor.getFullName())); | 72 | nodes.add(new ClassInheritanceTreeNode(translator, inheritor.getFullName())); |
| 68 | } | 73 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java index 01424120..c76dca7b 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/ClassReferenceTreeNode.java | |||
| @@ -1,17 +1,23 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import java.util.Set; | ||
| 15 | |||
| 16 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 17 | import javax.swing.tree.TreeNode; | ||
| 18 | |||
| 14 | import com.google.common.collect.Sets; | 19 | import com.google.common.collect.Sets; |
| 20 | |||
| 15 | import cuchaz.enigma.analysis.index.JarIndex; | 21 | import cuchaz.enigma.analysis.index.JarIndex; |
| 16 | import cuchaz.enigma.analysis.index.ReferenceIndex; | 22 | import cuchaz.enigma.analysis.index.ReferenceIndex; |
| 17 | import cuchaz.enigma.translation.Translator; | 23 | import cuchaz.enigma.translation.Translator; |
| @@ -19,13 +25,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 19 | import cuchaz.enigma.translation.representation.entry.Entry; | 25 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 20 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 26 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 21 | 27 | ||
| 22 | import javax.swing.tree.DefaultMutableTreeNode; | 28 | public class ClassReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<ClassEntry, MethodDefEntry> { |
| 23 | import javax.swing.tree.TreeNode; | ||
| 24 | import java.util.Set; | ||
| 25 | |||
| 26 | public class ClassReferenceTreeNode extends DefaultMutableTreeNode | ||
| 27 | implements ReferenceTreeNode<ClassEntry, MethodDefEntry> { | ||
| 28 | |||
| 29 | private Translator deobfuscatingTranslator; | 29 | private Translator deobfuscatingTranslator; |
| 30 | private ClassEntry entry; | 30 | private ClassEntry entry; |
| 31 | private EntryReference<ClassEntry, MethodDefEntry> reference; | 31 | private EntryReference<ClassEntry, MethodDefEntry> reference; |
| @@ -57,6 +57,7 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode | |||
| 57 | if (this.reference != null) { | 57 | if (this.reference != null) { |
| 58 | return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context)); | 58 | return String.format("%s", this.deobfuscatingTranslator.translate(this.reference.context)); |
| 59 | } | 59 | } |
| 60 | |||
| 60 | return this.deobfuscatingTranslator.translate(this.entry).getFullName(); | 61 | return this.deobfuscatingTranslator.translate(this.entry).getFullName(); |
| 61 | } | 62 | } |
| 62 | 63 | ||
| @@ -71,16 +72,18 @@ public class ClassReferenceTreeNode extends DefaultMutableTreeNode | |||
| 71 | if (recurse && this.children != null) { | 72 | if (recurse && this.children != null) { |
| 72 | for (Object child : this.children) { | 73 | for (Object child : this.children) { |
| 73 | if (child instanceof ClassReferenceTreeNode node) { | 74 | if (child instanceof ClassReferenceTreeNode node) { |
| 74 | |||
| 75 | // don't recurse into ancestor | 75 | // don't recurse into ancestor |
| 76 | Set<Entry<?>> ancestors = Sets.newHashSet(); | 76 | Set<Entry<?>> ancestors = Sets.newHashSet(); |
| 77 | TreeNode n = node; | 77 | TreeNode n = node; |
| 78 | |||
| 78 | while (n.getParent() != null) { | 79 | while (n.getParent() != null) { |
| 79 | n = n.getParent(); | 80 | n = n.getParent(); |
| 81 | |||
| 80 | if (n instanceof ClassReferenceTreeNode) { | 82 | if (n instanceof ClassReferenceTreeNode) { |
| 81 | ancestors.add(((ClassReferenceTreeNode) n).getEntry()); | 83 | ancestors.add(((ClassReferenceTreeNode) n).getEntry()); |
| 82 | } | 84 | } |
| 83 | } | 85 | } |
| 86 | |||
| 84 | if (ancestors.contains(node.getEntry())) { | 87 | if (ancestors.contains(node.getEntry())) { |
| 85 | continue; | 88 | continue; |
| 86 | } | 89 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java index 281b05ff..9c542814 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/EntryReference.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| @@ -26,7 +26,6 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 26 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 26 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 27 | 27 | ||
| 28 | public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements Translatable { | 28 | public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements Translatable { |
| 29 | |||
| 30 | private static final List<String> CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static"); | 29 | private static final List<String> CONSTRUCTOR_NON_NAMES = Arrays.asList("this", "super", "static"); |
| 31 | public final E entry; | 30 | public final E entry; |
| 32 | public final C context; | 31 | public final C context; |
| @@ -60,8 +59,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 60 | this.targetType = targetType; | 59 | this.targetType = targetType; |
| 61 | this.declaration = declaration; | 60 | this.declaration = declaration; |
| 62 | 61 | ||
| 63 | this.sourceName = sourceName != null && !sourceName.isEmpty() && | 62 | this.sourceName = sourceName != null && !sourceName.isEmpty() && !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName)); |
| 64 | !(entry instanceof MethodEntry && ((MethodEntry) entry).isConstructor() && CONSTRUCTOR_NON_NAMES.contains(sourceName)); | ||
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | public EntryReference(E entry, C context, EntryReference<E, C> other) { | 65 | public EntryReference(E entry, C context, EntryReference<E, C> other) { |
| @@ -76,6 +74,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 76 | if (context != null) { | 74 | if (context != null) { |
| 77 | return context.getContainingClass(); | 75 | return context.getContainingClass(); |
| 78 | } | 76 | } |
| 77 | |||
| 79 | return entry.getContainingClass(); | 78 | return entry.getContainingClass(); |
| 80 | } | 79 | } |
| 81 | 80 | ||
| @@ -95,6 +94,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 95 | // renaming a constructor really means renaming the class | 94 | // renaming a constructor really means renaming the class |
| 96 | return entry.getContainingClass(); | 95 | return entry.getContainingClass(); |
| 97 | } | 96 | } |
| 97 | |||
| 98 | return entry; | 98 | return entry; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| @@ -107,6 +107,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 107 | if (context != null) { | 107 | if (context != null) { |
| 108 | return Objects.hash(entry.hashCode(), context.hashCode()); | 108 | return Objects.hash(entry.hashCode(), context.hashCode()); |
| 109 | } | 109 | } |
| 110 | |||
| 110 | return entry.hashCode() ^ Boolean.hashCode(this.declaration); | 111 | return entry.hashCode() ^ Boolean.hashCode(this.declaration); |
| 111 | } | 112 | } |
| 112 | 113 | ||
| @@ -116,10 +117,7 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | public boolean equals(EntryReference<?, ?> other) { | 119 | public boolean equals(EntryReference<?, ?> other) { |
| 119 | return other != null | 120 | return other != null && Objects.equals(entry, other.entry) && Objects.equals(context, other.context) && declaration == other.declaration; |
| 120 | && Objects.equals(entry, other.entry) | ||
| 121 | && Objects.equals(context, other.context) | ||
| 122 | && declaration == other.declaration; | ||
| 123 | } | 121 | } |
| 124 | 122 | ||
| 125 | @Override | 123 | @Override |
| @@ -149,5 +147,4 @@ public class EntryReference<E extends Entry<?>, C extends Entry<?>> implements T | |||
| 149 | public TranslateResult<EntryReference<E, C>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 147 | public TranslateResult<EntryReference<E, C>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 150 | return translator.extendedTranslate(this.entry).map(e -> new EntryReference<>(e, translator.translate(context), this)); | 148 | return translator.extendedTranslate(this.entry).map(e -> new EntryReference<>(e, translator.translate(context), this)); |
| 151 | } | 149 | } |
| 152 | |||
| 153 | } | 150 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index c93ac53f..cc511f39 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 15 | |||
| 14 | import cuchaz.enigma.analysis.index.JarIndex; | 16 | import cuchaz.enigma.analysis.index.JarIndex; |
| 15 | import cuchaz.enigma.analysis.index.ReferenceIndex; | 17 | import cuchaz.enigma.analysis.index.ReferenceIndex; |
| 16 | import cuchaz.enigma.translation.Translator; | 18 | import cuchaz.enigma.translation.Translator; |
| @@ -18,10 +20,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 20 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 20 | 22 | ||
| 21 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 22 | |||
| 23 | public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, MethodDefEntry> { | 23 | public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<FieldEntry, MethodDefEntry> { |
| 24 | |||
| 25 | private final Translator translator; | 24 | private final Translator translator; |
| 26 | private FieldEntry entry; | 25 | private FieldEntry entry; |
| 27 | private EntryReference<FieldEntry, MethodDefEntry> reference; | 26 | private EntryReference<FieldEntry, MethodDefEntry> reference; |
| @@ -53,6 +52,7 @@ public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements Re | |||
| 53 | if (this.reference != null) { | 52 | if (this.reference != null) { |
| 54 | return String.format("%s", translator.translate(this.reference.context)); | 53 | return String.format("%s", translator.translate(this.reference.context)); |
| 55 | } | 54 | } |
| 55 | |||
| 56 | return translator.translate(entry).toString(); | 56 | return translator.translate(entry).toString(); |
| 57 | } | 57 | } |
| 58 | 58 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java index ec8f3237..44a768ea 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java | |||
| @@ -1,154 +1,160 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import java.util.Set; | ||
| 4 | |||
| 5 | import org.objectweb.asm.Type; | ||
| 6 | import org.objectweb.asm.tree.analysis.BasicValue; | ||
| 7 | import org.objectweb.asm.tree.analysis.SimpleVerifier; | ||
| 8 | |||
| 3 | import cuchaz.enigma.Enigma; | 9 | import cuchaz.enigma.Enigma; |
| 4 | import cuchaz.enigma.analysis.index.EntryIndex; | 10 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 5 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 11 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 6 | import cuchaz.enigma.translation.representation.AccessFlags; | 12 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 7 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | 13 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 8 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 14 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 9 | import org.objectweb.asm.Type; | ||
| 10 | import org.objectweb.asm.tree.analysis.BasicValue; | ||
| 11 | import org.objectweb.asm.tree.analysis.SimpleVerifier; | ||
| 12 | |||
| 13 | import java.util.Set; | ||
| 14 | 15 | ||
| 15 | public class IndexSimpleVerifier extends SimpleVerifier { | 16 | public class IndexSimpleVerifier extends SimpleVerifier { |
| 16 | private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); | 17 | private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); |
| 17 | private final EntryIndex entryIndex; | 18 | private final EntryIndex entryIndex; |
| 18 | private final InheritanceIndex inheritanceIndex; | 19 | private final InheritanceIndex inheritanceIndex; |
| 19 | 20 | ||
| 20 | public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { | 21 | public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { |
| 21 | super(Enigma.ASM_VERSION, null, null, null, false); | 22 | super(Enigma.ASM_VERSION, null, null, null, false); |
| 22 | this.entryIndex = entryIndex; | 23 | this.entryIndex = entryIndex; |
| 23 | this.inheritanceIndex = inheritanceIndex; | 24 | this.inheritanceIndex = inheritanceIndex; |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | @Override | 27 | @Override |
| 27 | protected boolean isSubTypeOf(BasicValue value, BasicValue expected) { | 28 | protected boolean isSubTypeOf(BasicValue value, BasicValue expected) { |
| 28 | Type expectedType = expected.getType(); | 29 | Type expectedType = expected.getType(); |
| 29 | Type type = value.getType(); | 30 | Type type = value.getType(); |
| 30 | switch (expectedType.getSort()) { | 31 | switch (expectedType.getSort()) { |
| 31 | case Type.INT: | 32 | case Type.INT: |
| 32 | case Type.FLOAT: | 33 | case Type.FLOAT: |
| 33 | case Type.LONG: | 34 | case Type.LONG: |
| 34 | case Type.DOUBLE: | 35 | case Type.DOUBLE: |
| 35 | return type.equals(expectedType); | 36 | return type.equals(expectedType); |
| 36 | case Type.ARRAY: | 37 | case Type.ARRAY: |
| 37 | case Type.OBJECT: | 38 | case Type.OBJECT: |
| 38 | if (type.equals(NULL_TYPE)) { | 39 | if (type.equals(NULL_TYPE)) { |
| 39 | return true; | 40 | return true; |
| 40 | } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { | 41 | } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { |
| 41 | if (isAssignableFrom(expectedType, type)) { | 42 | if (isAssignableFrom(expectedType, type)) { |
| 42 | return true; | 43 | return true; |
| 43 | } else if (isInterface(expectedType)) { | 44 | } else if (isInterface(expectedType)) { |
| 44 | return isAssignableFrom(OBJECT_TYPE, type); | 45 | return isAssignableFrom(OBJECT_TYPE, type); |
| 45 | } else { | 46 | } else { |
| 46 | return false; | 47 | return false; |
| 47 | } | 48 | } |
| 48 | } else { | 49 | } else { |
| 49 | return false; | 50 | return false; |
| 50 | } | 51 | } |
| 51 | default: | 52 | default: |
| 52 | throw new AssertionError(); | 53 | throw new AssertionError(); |
| 53 | } | 54 | } |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | @Override | 57 | @Override |
| 57 | protected boolean isInterface(Type type) { | 58 | protected boolean isInterface(Type type) { |
| 58 | AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName())); | 59 | AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName())); |
| 59 | if (classAccess != null) { | 60 | |
| 60 | return classAccess.isInterface(); | 61 | if (classAccess != null) { |
| 61 | } | 62 | return classAccess.isInterface(); |
| 62 | 63 | } | |
| 63 | Class<?> clazz = getClass(type); | 64 | |
| 64 | if (clazz != null) { | 65 | Class<?> clazz = getClass(type); |
| 65 | return clazz.isInterface(); | 66 | |
| 66 | } | 67 | if (clazz != null) { |
| 67 | 68 | return clazz.isInterface(); | |
| 68 | return false; | 69 | } |
| 69 | } | 70 | |
| 70 | 71 | return false; | |
| 71 | @Override | 72 | } |
| 72 | protected Type getSuperClass(Type type) { | 73 | |
| 73 | ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName())); | 74 | @Override |
| 74 | if (definition != null) { | 75 | protected Type getSuperClass(Type type) { |
| 75 | return Type.getType('L' + definition.getSuperClass().getFullName() + ';'); | 76 | ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName())); |
| 76 | } | 77 | |
| 77 | 78 | if (definition != null) { | |
| 78 | Class<?> clazz = getClass(type); | 79 | return Type.getType('L' + definition.getSuperClass().getFullName() + ';'); |
| 79 | if (clazz != null) { | 80 | } |
| 80 | return Type.getType(clazz.getSuperclass()); | 81 | |
| 81 | } | 82 | Class<?> clazz = getClass(type); |
| 82 | 83 | ||
| 83 | return OBJECT_TYPE; | 84 | if (clazz != null) { |
| 84 | } | 85 | return Type.getType(clazz.getSuperclass()); |
| 85 | 86 | } | |
| 86 | @Override | 87 | |
| 87 | protected boolean isAssignableFrom(Type type1, Type type2) { | 88 | return OBJECT_TYPE; |
| 88 | if (type1.equals(type2)) { | 89 | } |
| 89 | return true; | 90 | |
| 90 | } | 91 | @Override |
| 91 | 92 | protected boolean isAssignableFrom(Type type1, Type type2) { | |
| 92 | if (type2.equals(NULL_TYPE)) { | 93 | if (type1.equals(type2)) { |
| 93 | return true; | 94 | return true; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | if (type1.getSort() == Type.ARRAY) { | 97 | if (type2.equals(NULL_TYPE)) { |
| 97 | return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1))); | 98 | return true; |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | if (type2.getSort() == Type.ARRAY) { | 101 | if (type1.getSort() == Type.ARRAY) { |
| 101 | return type1.equals(OBJECT_TYPE); | 102 | return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1))); |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) { | 105 | if (type2.getSort() == Type.ARRAY) { |
| 105 | if (type1.equals(OBJECT_TYPE)) { | 106 | return type1.equals(OBJECT_TYPE); |
| 106 | return true; | 107 | } |
| 107 | } | 108 | |
| 108 | 109 | if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) { | |
| 109 | ClassEntry class1 = new ClassEntry(type1.getInternalName()); | 110 | if (type1.equals(OBJECT_TYPE)) { |
| 110 | ClassEntry class2 = new ClassEntry(type2.getInternalName()); | 111 | return true; |
| 111 | 112 | } | |
| 112 | if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) { | 113 | |
| 113 | return inheritanceIndex.getAncestors(class2).contains(class1); | 114 | ClassEntry class1 = new ClassEntry(type1.getInternalName()); |
| 114 | } | 115 | ClassEntry class2 = new ClassEntry(type2.getInternalName()); |
| 115 | 116 | ||
| 116 | Class<?> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';')); | 117 | if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) { |
| 117 | Class<?> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';')); | 118 | return inheritanceIndex.getAncestors(class2).contains(class1); |
| 118 | 119 | } | |
| 119 | if (class1Class == null) { | 120 | |
| 120 | return true; // missing classes to find out | 121 | Class<?> class1Class = getClass(Type.getType('L' + class1.getFullName() + ';')); |
| 121 | } | 122 | Class<?> class2Class = getClass(Type.getType('L' + class2.getFullName() + ';')); |
| 122 | 123 | ||
| 123 | if (class2Class != null) { | 124 | if (class1Class == null) { |
| 124 | return class1Class.isAssignableFrom(class2Class); | 125 | return true; // missing classes to find out |
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | if (entryIndex.hasClass(class2)) { | 128 | if (class2Class != null) { |
| 128 | Set<ClassEntry> ancestors = inheritanceIndex.getAncestors(class2); | 129 | return class1Class.isAssignableFrom(class2Class); |
| 129 | 130 | } | |
| 130 | for (ClassEntry ancestorEntry : ancestors) { | 131 | |
| 131 | Class<?> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';')); | 132 | if (entryIndex.hasClass(class2)) { |
| 132 | if (ancestor == null || class1Class.isAssignableFrom(ancestor)) { | 133 | Set<ClassEntry> ancestors = inheritanceIndex.getAncestors(class2); |
| 133 | return true; // assignable, or missing classes to find out | 134 | |
| 134 | } | 135 | for (ClassEntry ancestorEntry : ancestors) { |
| 135 | } | 136 | Class<?> ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';')); |
| 136 | 137 | ||
| 137 | return false; | 138 | if (ancestor == null || class1Class.isAssignableFrom(ancestor)) { |
| 138 | } | 139 | return true; // assignable, or missing classes to find out |
| 139 | 140 | } | |
| 140 | return true; // missing classes to find out | 141 | } |
| 141 | } | 142 | |
| 142 | 143 | return false; | |
| 143 | return false; | 144 | } |
| 144 | } | 145 | |
| 145 | 146 | return true; // missing classes to find out | |
| 146 | @Override | 147 | } |
| 147 | protected final Class<?> getClass(Type type) { | 148 | |
| 148 | try { | 149 | return false; |
| 149 | return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null); | 150 | } |
| 150 | } catch (ClassNotFoundException e) { | 151 | |
| 151 | return null; | 152 | @Override |
| 152 | } | 153 | protected final Class<?> getClass(Type type) { |
| 153 | } | 154 | try { |
| 155 | return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null); | ||
| 156 | } catch (ClassNotFoundException e) { | ||
| 157 | return null; | ||
| 158 | } | ||
| 159 | } | ||
| 154 | } | 160 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java index 0c2dfd77..3043577b 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/IndexTreeBuilder.java | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.List; | ||
| 5 | |||
| 3 | import com.google.common.collect.Lists; | 6 | import com.google.common.collect.Lists; |
| 7 | |||
| 4 | import cuchaz.enigma.analysis.index.JarIndex; | 8 | import cuchaz.enigma.analysis.index.JarIndex; |
| 5 | import cuchaz.enigma.translation.Translator; | 9 | import cuchaz.enigma.translation.Translator; |
| 6 | import cuchaz.enigma.translation.mapping.EntryResolver; | 10 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| @@ -8,9 +12,6 @@ import cuchaz.enigma.translation.mapping.ResolutionStrategy; | |||
| 8 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 12 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 9 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 13 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 10 | 14 | ||
| 11 | import java.util.Collection; | ||
| 12 | import java.util.List; | ||
| 13 | |||
| 14 | public class IndexTreeBuilder { | 15 | public class IndexTreeBuilder { |
| 15 | private final JarIndex index; | 16 | private final JarIndex index; |
| 16 | 17 | ||
| @@ -22,6 +23,7 @@ public class IndexTreeBuilder { | |||
| 22 | // get the root node | 23 | // get the root node |
| 23 | List<String> ancestry = Lists.newArrayList(); | 24 | List<String> ancestry = Lists.newArrayList(); |
| 24 | ancestry.add(obfClassEntry.getFullName()); | 25 | ancestry.add(obfClassEntry.getFullName()); |
| 26 | |||
| 25 | for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) { | 27 | for (ClassEntry classEntry : index.getInheritanceIndex().getAncestors(obfClassEntry)) { |
| 26 | ancestry.add(classEntry.getFullName()); | 28 | ancestry.add(classEntry.getFullName()); |
| 27 | } | 29 | } |
| @@ -40,6 +42,7 @@ public class IndexTreeBuilder { | |||
| 40 | node.load(index); | 42 | node.load(index); |
| 41 | return node; | 43 | return node; |
| 42 | } | 44 | } |
| 45 | |||
| 43 | return null; | 46 | return null; |
| 44 | } | 47 | } |
| 45 | 48 | ||
| @@ -47,10 +50,7 @@ public class IndexTreeBuilder { | |||
| 47 | MethodEntry resolvedEntry = index.getEntryResolver().resolveFirstEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); | 50 | MethodEntry resolvedEntry = index.getEntryResolver().resolveFirstEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); |
| 48 | 51 | ||
| 49 | // make a root node at the base | 52 | // make a root node at the base |
| 50 | MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( | 53 | MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode(translator, resolvedEntry, index.getEntryIndex().hasMethod(resolvedEntry)); |
| 51 | translator, resolvedEntry, | ||
| 52 | index.getEntryIndex().hasMethod(resolvedEntry) | ||
| 53 | ); | ||
| 54 | 54 | ||
| 55 | // expand the full tree | 55 | // expand the full tree |
| 56 | rootNode.load(index); | 56 | rootNode.load(index); |
| @@ -63,6 +63,7 @@ public class IndexTreeBuilder { | |||
| 63 | Collection<MethodEntry> resolvedEntries = resolver.resolveEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); | 63 | Collection<MethodEntry> resolvedEntries = resolver.resolveEntry(obfMethodEntry, ResolutionStrategy.RESOLVE_ROOT); |
| 64 | 64 | ||
| 65 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); | 65 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 66 | |||
| 66 | for (MethodEntry resolvedEntry : resolvedEntries) { | 67 | for (MethodEntry resolvedEntry : resolvedEntries) { |
| 67 | MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(translator, resolvedEntry); | 68 | MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(translator, resolvedEntry); |
| 68 | node.load(index); | 69 | node.load(index); |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java index a624b7c5..2ca1dfd3 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/InterpreterPair.java | |||
| @@ -1,129 +1,106 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.Enigma; | 3 | import java.util.List; |
| 4 | import java.util.Objects; | ||
| 5 | |||
| 4 | import org.objectweb.asm.Type; | 6 | import org.objectweb.asm.Type; |
| 5 | import org.objectweb.asm.tree.AbstractInsnNode; | 7 | import org.objectweb.asm.tree.AbstractInsnNode; |
| 6 | import org.objectweb.asm.tree.analysis.AnalyzerException; | 8 | import org.objectweb.asm.tree.analysis.AnalyzerException; |
| 7 | import org.objectweb.asm.tree.analysis.Interpreter; | 9 | import org.objectweb.asm.tree.analysis.Interpreter; |
| 8 | import org.objectweb.asm.tree.analysis.Value; | 10 | import org.objectweb.asm.tree.analysis.Value; |
| 9 | 11 | ||
| 10 | import java.util.List; | 12 | import cuchaz.enigma.Enigma; |
| 11 | import java.util.Objects; | ||
| 12 | 13 | ||
| 13 | public class InterpreterPair<V extends Value, W extends Value> extends Interpreter<InterpreterPair.PairValue<V, W>> { | 14 | public class InterpreterPair<V extends Value, W extends Value> extends Interpreter<InterpreterPair.PairValue<V, W>> { |
| 14 | private final Interpreter<V> left; | 15 | private final Interpreter<V> left; |
| 15 | private final Interpreter<W> right; | 16 | private final Interpreter<W> right; |
| 16 | 17 | ||
| 17 | public InterpreterPair(Interpreter<V> left, Interpreter<W> right) { | 18 | public InterpreterPair(Interpreter<V> left, Interpreter<W> right) { |
| 18 | super(Enigma.ASM_VERSION); | 19 | super(Enigma.ASM_VERSION); |
| 19 | this.left = left; | 20 | this.left = left; |
| 20 | this.right = right; | 21 | this.right = right; |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | @Override | 24 | @Override |
| 24 | public PairValue<V, W> newValue(Type type) { | 25 | public PairValue<V, W> newValue(Type type) { |
| 25 | return pair( | 26 | return pair(left.newValue(type), right.newValue(type)); |
| 26 | left.newValue(type), | 27 | } |
| 27 | right.newValue(type) | 28 | |
| 28 | ); | 29 | @Override |
| 29 | } | 30 | public PairValue<V, W> newOperation(AbstractInsnNode insn) throws AnalyzerException { |
| 30 | 31 | return pair(left.newOperation(insn), right.newOperation(insn)); | |
| 31 | @Override | 32 | } |
| 32 | public PairValue<V, W> newOperation(AbstractInsnNode insn) throws AnalyzerException { | 33 | |
| 33 | return pair( | 34 | @Override |
| 34 | left.newOperation(insn), | 35 | public PairValue<V, W> copyOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { |
| 35 | right.newOperation(insn) | 36 | return pair(left.copyOperation(insn, value.left), right.copyOperation(insn, value.right)); |
| 36 | ); | 37 | } |
| 37 | } | 38 | |
| 38 | 39 | @Override | |
| 39 | @Override | 40 | public PairValue<V, W> unaryOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { |
| 40 | public PairValue<V, W> copyOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { | 41 | return pair(left.unaryOperation(insn, value.left), right.unaryOperation(insn, value.right)); |
| 41 | return pair( | 42 | } |
| 42 | left.copyOperation(insn, value.left), | 43 | |
| 43 | right.copyOperation(insn, value.right) | 44 | @Override |
| 44 | ); | 45 | public PairValue<V, W> binaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2) throws AnalyzerException { |
| 45 | } | 46 | return pair(left.binaryOperation(insn, value1.left, value2.left), right.binaryOperation(insn, value1.right, value2.right)); |
| 46 | 47 | } | |
| 47 | @Override | 48 | |
| 48 | public PairValue<V, W> unaryOperation(AbstractInsnNode insn, PairValue<V, W> value) throws AnalyzerException { | 49 | @Override |
| 49 | return pair( | 50 | public PairValue<V, W> ternaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2, PairValue<V, W> value3) throws AnalyzerException { |
| 50 | left.unaryOperation(insn, value.left), | 51 | return pair(left.ternaryOperation(insn, value1.left, value2.left, value3.left), right.ternaryOperation(insn, value1.right, value2.right, value3.right)); |
| 51 | right.unaryOperation(insn, value.right) | 52 | } |
| 52 | ); | 53 | |
| 53 | } | 54 | @Override |
| 54 | 55 | public PairValue<V, W> naryOperation(AbstractInsnNode insn, List<? extends PairValue<V, W>> values) throws AnalyzerException { | |
| 55 | @Override | 56 | return pair(left.naryOperation(insn, values.stream().map(v -> v.left).toList()), right.naryOperation(insn, values.stream().map(v -> v.right).toList())); |
| 56 | public PairValue<V, W> binaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2) throws AnalyzerException { | 57 | } |
| 57 | return pair( | 58 | |
| 58 | left.binaryOperation(insn, value1.left, value2.left), | 59 | @Override |
| 59 | right.binaryOperation(insn, value1.right, value2.right) | 60 | public void returnOperation(AbstractInsnNode insn, PairValue<V, W> value, PairValue<V, W> expected) throws AnalyzerException { |
| 60 | ); | 61 | left.returnOperation(insn, value.left, expected.left); |
| 61 | } | 62 | right.returnOperation(insn, value.right, expected.right); |
| 62 | 63 | } | |
| 63 | @Override | 64 | |
| 64 | public PairValue<V, W> ternaryOperation(AbstractInsnNode insn, PairValue<V, W> value1, PairValue<V, W> value2, PairValue<V, W> value3) throws AnalyzerException { | 65 | @Override |
| 65 | return pair( | 66 | public PairValue<V, W> merge(PairValue<V, W> value1, PairValue<V, W> value2) { |
| 66 | left.ternaryOperation(insn, value1.left, value2.left, value3.left), | 67 | return pair(left.merge(value1.left, value2.left), right.merge(value1.right, value2.right)); |
| 67 | right.ternaryOperation(insn, value1.right, value2.right, value3.right) | 68 | } |
| 68 | ); | 69 | |
| 69 | } | 70 | private PairValue<V, W> pair(V left, W right) { |
| 70 | 71 | if (left == null && right == null) { | |
| 71 | @Override | 72 | return null; |
| 72 | public PairValue<V, W> naryOperation(AbstractInsnNode insn, List<? extends PairValue<V, W>> values) throws AnalyzerException { | 73 | } |
| 73 | return pair( | 74 | |
| 74 | left.naryOperation(insn, values.stream().map(v -> v.left).toList()), | 75 | return new PairValue<>(left, right); |
| 75 | right.naryOperation(insn, values.stream().map(v -> v.right).toList()) | 76 | } |
| 76 | ); | 77 | |
| 77 | } | 78 | public static final class PairValue<V extends Value, W extends Value> implements Value { |
| 78 | 79 | public final V left; | |
| 79 | @Override | 80 | public final W right; |
| 80 | public void returnOperation(AbstractInsnNode insn, PairValue<V, W> value, PairValue<V, W> expected) throws AnalyzerException { | 81 | |
| 81 | left.returnOperation(insn, value.left, expected.left); | 82 | public PairValue(V left, W right) { |
| 82 | right.returnOperation(insn, value.right, expected.right); | 83 | if (left == null && right == null) { |
| 83 | } | 84 | throw new IllegalArgumentException("should use null rather than pair of nulls"); |
| 84 | 85 | } | |
| 85 | @Override | 86 | |
| 86 | public PairValue<V, W> merge(PairValue<V, W> value1, PairValue<V, W> value2) { | 87 | this.left = left; |
| 87 | return pair( | 88 | this.right = right; |
| 88 | left.merge(value1.left, value2.left), | 89 | } |
| 89 | right.merge(value1.right, value2.right) | 90 | |
| 90 | ); | 91 | @Override |
| 91 | } | 92 | public boolean equals(Object o) { |
| 92 | 93 | return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right); | |
| 93 | private PairValue<V, W> pair(V left, W right) { | 94 | } |
| 94 | if (left == null && right == null) { | 95 | |
| 95 | return null; | 96 | @Override |
| 96 | } | 97 | public int hashCode() { |
| 97 | 98 | return left.hashCode() * 31 + right.hashCode(); | |
| 98 | return new PairValue<>(left, right); | 99 | } |
| 99 | } | 100 | |
| 100 | 101 | @Override | |
| 101 | public static final class PairValue<V extends Value, W extends Value> implements Value { | 102 | public int getSize() { |
| 102 | public final V left; | 103 | return (left == null ? right : left).getSize(); |
| 103 | public final W right; | 104 | } |
| 104 | 105 | } | |
| 105 | public PairValue(V left, W right) { | ||
| 106 | if (left == null && right == null) { | ||
| 107 | throw new IllegalArgumentException("should use null rather than pair of nulls"); | ||
| 108 | } | ||
| 109 | |||
| 110 | this.left = left; | ||
| 111 | this.right = right; | ||
| 112 | } | ||
| 113 | |||
| 114 | @Override | ||
| 115 | public boolean equals(Object o) { | ||
| 116 | return o instanceof InterpreterPair.PairValue pairValue && Objects.equals(left, pairValue.left) && Objects.equals(right, pairValue.right); | ||
| 117 | } | ||
| 118 | |||
| 119 | @Override | ||
| 120 | public int hashCode() { | ||
| 121 | return left.hashCode() * 31 + right.hashCode(); | ||
| 122 | } | ||
| 123 | |||
| 124 | @Override | ||
| 125 | public int getSize() { | ||
| 126 | return (left == null ? right : left).getSize(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | 106 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 4633ace8..83275da6 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | |||
| @@ -1,17 +1,23 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import java.util.Collection; | ||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 18 | |||
| 14 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
| 20 | |||
| 15 | import cuchaz.enigma.analysis.index.EntryIndex; | 21 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 16 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 22 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 17 | import cuchaz.enigma.analysis.index.JarIndex; | 23 | import cuchaz.enigma.analysis.index.JarIndex; |
| @@ -19,17 +25,13 @@ import cuchaz.enigma.translation.Translator; | |||
| 19 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 25 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 20 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 26 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 21 | 27 | ||
| 22 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 23 | import java.util.Collection; | ||
| 24 | import java.util.List; | ||
| 25 | |||
| 26 | public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { | 28 | public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { |
| 27 | |||
| 28 | private final Translator translator; | 29 | private final Translator translator; |
| 29 | private MethodEntry entry; | 30 | private MethodEntry entry; |
| 30 | 31 | ||
| 31 | public MethodImplementationsTreeNode(Translator translator, MethodEntry entry) { | 32 | public MethodImplementationsTreeNode(Translator translator, MethodEntry entry) { |
| 32 | this.translator = translator; | 33 | this.translator = translator; |
| 34 | |||
| 33 | if (entry == null) { | 35 | if (entry == null) { |
| 34 | throw new IllegalArgumentException("Entry cannot be null!"); | 36 | throw new IllegalArgumentException("Entry cannot be null!"); |
| 35 | } | 37 | } |
| @@ -46,10 +48,12 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { | |||
| 46 | // recurse | 48 | // recurse |
| 47 | for (int i = 0; i < node.getChildCount(); i++) { | 49 | for (int i = 0; i < node.getChildCount(); i++) { |
| 48 | MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); | 50 | MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode) node.getChildAt(i), entry); |
| 51 | |||
| 49 | if (foundNode != null) { | 52 | if (foundNode != null) { |
| 50 | return foundNode; | 53 | return foundNode; |
| 51 | } | 54 | } |
| 52 | } | 55 | } |
| 56 | |||
| 53 | return null; | 57 | return null; |
| 54 | } | 58 | } |
| 55 | 59 | ||
| @@ -70,8 +74,10 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { | |||
| 70 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); | 74 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); |
| 71 | 75 | ||
| 72 | Collection<ClassEntry> descendants = inheritanceIndex.getDescendants(entry.getParent()); | 76 | Collection<ClassEntry> descendants = inheritanceIndex.getDescendants(entry.getParent()); |
| 77 | |||
| 73 | for (ClassEntry inheritor : descendants) { | 78 | for (ClassEntry inheritor : descendants) { |
| 74 | MethodEntry methodEntry = entry.withParent(inheritor); | 79 | MethodEntry methodEntry = entry.withParent(inheritor); |
| 80 | |||
| 75 | if (entryIndex.hasMethod(methodEntry)) { | 81 | if (entryIndex.hasMethod(methodEntry)) { |
| 76 | nodes.add(new MethodImplementationsTreeNode(translator, methodEntry)); | 82 | nodes.add(new MethodImplementationsTreeNode(translator, methodEntry)); |
| 77 | } | 83 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 455456f0..2afeed9e 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 15 | |||
| 14 | import cuchaz.enigma.analysis.index.EntryIndex; | 16 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 15 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 17 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 16 | import cuchaz.enigma.analysis.index.JarIndex; | 18 | import cuchaz.enigma.analysis.index.JarIndex; |
| @@ -18,10 +20,7 @@ import cuchaz.enigma.translation.Translator; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 20 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 20 | 22 | ||
| 21 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 22 | |||
| 23 | public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { | 23 | public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { |
| 24 | |||
| 25 | private final Translator translator; | 24 | private final Translator translator; |
| 26 | private MethodEntry entry; | 25 | private MethodEntry entry; |
| 27 | private boolean implemented; | 26 | private boolean implemented; |
| @@ -41,10 +40,12 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { | |||
| 41 | // recurse | 40 | // recurse |
| 42 | for (int i = 0; i < node.getChildCount(); i++) { | 41 | for (int i = 0; i < node.getChildCount(); i++) { |
| 43 | MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); | 42 | MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode) node.getChildAt(i), entry); |
| 43 | |||
| 44 | if (foundNode != null) { | 44 | if (foundNode != null) { |
| 45 | return foundNode; | 45 | return foundNode; |
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | |||
| 48 | return null; | 49 | return null; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| @@ -79,6 +80,7 @@ public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { | |||
| 79 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); | 80 | InheritanceIndex inheritanceIndex = index.getInheritanceIndex(); |
| 80 | 81 | ||
| 81 | boolean ret = false; | 82 | boolean ret = false; |
| 83 | |||
| 82 | for (ClassEntry inheritorEntry : inheritanceIndex.getChildren(this.entry.getParent())) { | 84 | for (ClassEntry inheritorEntry : inheritanceIndex.getChildren(this.entry.getParent())) { |
| 83 | MethodEntry methodEntry = new MethodEntry(inheritorEntry, this.entry.getName(), this.entry.getDesc()); | 85 | MethodEntry methodEntry = new MethodEntry(inheritorEntry, this.entry.getName(), this.entry.getDesc()); |
| 84 | 86 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java index 81171038..8dc7fe68 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodNodeWithAction.java | |||
| @@ -1,19 +1,19 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.tree.MethodNode; | ||
| 4 | |||
| 5 | import java.util.function.Consumer; | 3 | import java.util.function.Consumer; |
| 6 | 4 | ||
| 5 | import org.objectweb.asm.tree.MethodNode; | ||
| 6 | |||
| 7 | public class MethodNodeWithAction extends MethodNode { | 7 | public class MethodNodeWithAction extends MethodNode { |
| 8 | private final Consumer<MethodNode> action; | 8 | private final Consumer<MethodNode> action; |
| 9 | 9 | ||
| 10 | public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer<MethodNode> action) { | 10 | public MethodNodeWithAction(int api, int access, String name, String descriptor, String signature, String[] exceptions, Consumer<MethodNode> action) { |
| 11 | super(api, access, name, descriptor, signature, exceptions); | 11 | super(api, access, name, descriptor, signature, exceptions); |
| 12 | this.action = action; | 12 | this.action = action; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | @Override | 15 | @Override |
| 16 | public void visitEnd() { | 16 | public void visitEnd() { |
| 17 | action.accept(this); | 17 | action.accept(this); |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java index 68038615..fc58c6d0 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/MethodReferenceTreeNode.java | |||
| @@ -1,17 +1,25 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
| 14 | import java.util.ArrayList; | ||
| 15 | import java.util.Collection; | ||
| 16 | import java.util.Set; | ||
| 17 | |||
| 18 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 19 | import javax.swing.tree.TreeNode; | ||
| 20 | |||
| 14 | import com.google.common.collect.Sets; | 21 | import com.google.common.collect.Sets; |
| 22 | |||
| 15 | import cuchaz.enigma.analysis.index.JarIndex; | 23 | import cuchaz.enigma.analysis.index.JarIndex; |
| 16 | import cuchaz.enigma.analysis.index.ReferenceIndex; | 24 | import cuchaz.enigma.analysis.index.ReferenceIndex; |
| 17 | import cuchaz.enigma.translation.Translator; | 25 | import cuchaz.enigma.translation.Translator; |
| @@ -20,14 +28,7 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 20 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 28 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 29 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 22 | 30 | ||
| 23 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 24 | import javax.swing.tree.TreeNode; | ||
| 25 | import java.util.ArrayList; | ||
| 26 | import java.util.Collection; | ||
| 27 | import java.util.Set; | ||
| 28 | |||
| 29 | public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<MethodEntry, MethodDefEntry> { | 31 | public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode<MethodEntry, MethodDefEntry> { |
| 30 | |||
| 31 | private final Translator translator; | 32 | private final Translator translator; |
| 32 | private MethodEntry entry; | 33 | private MethodEntry entry; |
| 33 | private EntryReference<MethodEntry, MethodDefEntry> reference; | 34 | private EntryReference<MethodEntry, MethodDefEntry> reference; |
| @@ -59,6 +60,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R | |||
| 59 | if (this.reference != null) { | 60 | if (this.reference != null) { |
| 60 | return String.format("%s", translator.translate(this.reference.context)); | 61 | return String.format("%s", translator.translate(this.reference.context)); |
| 61 | } | 62 | } |
| 63 | |||
| 62 | return translator.translate(this.entry).getName(); | 64 | return translator.translate(this.entry).getName(); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| @@ -73,16 +75,18 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R | |||
| 73 | if (recurse && this.children != null) { | 75 | if (recurse && this.children != null) { |
| 74 | for (Object child : this.children) { | 76 | for (Object child : this.children) { |
| 75 | if (child instanceof MethodReferenceTreeNode node) { | 77 | if (child instanceof MethodReferenceTreeNode node) { |
| 76 | |||
| 77 | // don't recurse into ancestor | 78 | // don't recurse into ancestor |
| 78 | Set<Entry<?>> ancestors = Sets.newHashSet(); | 79 | Set<Entry<?>> ancestors = Sets.newHashSet(); |
| 79 | TreeNode n = node; | 80 | TreeNode n = node; |
| 81 | |||
| 80 | while (n.getParent() != null) { | 82 | while (n.getParent() != null) { |
| 81 | n = n.getParent(); | 83 | n = n.getParent(); |
| 84 | |||
| 82 | if (n instanceof MethodReferenceTreeNode) { | 85 | if (n instanceof MethodReferenceTreeNode) { |
| 83 | ancestors.add(((MethodReferenceTreeNode) n).getEntry()); | 86 | ancestors.add(((MethodReferenceTreeNode) n).getEntry()); |
| 84 | } | 87 | } |
| 85 | } | 88 | } |
| 89 | |||
| 86 | if (ancestors.contains(node.getEntry())) { | 90 | if (ancestors.contains(node.getEntry())) { |
| 87 | continue; | 91 | continue; |
| 88 | } | 92 | } |
| @@ -100,6 +104,7 @@ public class MethodReferenceTreeNode extends DefaultMutableTreeNode implements R | |||
| 100 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references = new ArrayList<>(); | 104 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references = new ArrayList<>(); |
| 101 | 105 | ||
| 102 | EntryResolver entryResolver = index.getEntryResolver(); | 106 | EntryResolver entryResolver = index.getEntryResolver(); |
| 107 | |||
| 103 | for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) { | 108 | for (MethodEntry methodEntry : entryResolver.resolveEquivalentMethods(entry)) { |
| 104 | references.addAll(referenceIndex.getReferencesToMethod(methodEntry)); | 109 | references.addAll(referenceIndex.getReferencesToMethod(methodEntry)); |
| 105 | } | 110 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java index 5b19d189..4dcb834a 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTargetType.java | |||
| @@ -3,72 +3,72 @@ package cuchaz.enigma.analysis; | |||
| 3 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 3 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 4 | 4 | ||
| 5 | public abstract class ReferenceTargetType { | 5 | public abstract class ReferenceTargetType { |
| 6 | private static final None NONE = new None(); | 6 | private static final None NONE = new None(); |
| 7 | private static final Uninitialized UNINITIALIZED = new Uninitialized(); | 7 | private static final Uninitialized UNINITIALIZED = new Uninitialized(); |
| 8 | 8 | ||
| 9 | public abstract Kind getKind(); | 9 | public abstract Kind getKind(); |
| 10 | 10 | ||
| 11 | public static None none() { | 11 | public static None none() { |
| 12 | return NONE; | 12 | return NONE; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | public static Uninitialized uninitialized() { | 15 | public static Uninitialized uninitialized() { |
| 16 | return UNINITIALIZED; | 16 | return UNINITIALIZED; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | public static ClassType classType(ClassEntry name) { | 19 | public static ClassType classType(ClassEntry name) { |
| 20 | return new ClassType(name); | 20 | return new ClassType(name); |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | public enum Kind { | 23 | public enum Kind { |
| 24 | NONE, | 24 | NONE, |
| 25 | UNINITIALIZED, | 25 | UNINITIALIZED, |
| 26 | CLASS_TYPE | 26 | CLASS_TYPE |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | public static class None extends ReferenceTargetType { | 29 | public static class None extends ReferenceTargetType { |
| 30 | @Override | 30 | @Override |
| 31 | public Kind getKind() { | 31 | public Kind getKind() { |
| 32 | return Kind.NONE; | 32 | return Kind.NONE; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | @Override | 35 | @Override |
| 36 | public String toString() { | 36 | public String toString() { |
| 37 | return "(none)"; | 37 | return "(none)"; |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | public static class Uninitialized extends ReferenceTargetType { | 41 | public static class Uninitialized extends ReferenceTargetType { |
| 42 | @Override | 42 | @Override |
| 43 | public Kind getKind() { | 43 | public Kind getKind() { |
| 44 | return Kind.UNINITIALIZED; | 44 | return Kind.UNINITIALIZED; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | @Override | 47 | @Override |
| 48 | public String toString() { | 48 | public String toString() { |
| 49 | return "(uninitialized)"; | 49 | return "(uninitialized)"; |
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | public static class ClassType extends ReferenceTargetType { | 53 | public static class ClassType extends ReferenceTargetType { |
| 54 | private final ClassEntry entry; | 54 | private final ClassEntry entry; |
| 55 | 55 | ||
| 56 | private ClassType(ClassEntry entry) { | 56 | private ClassType(ClassEntry entry) { |
| 57 | this.entry = entry; | 57 | this.entry = entry; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | public ClassEntry getEntry() { | 60 | public ClassEntry getEntry() { |
| 61 | return entry; | 61 | return entry; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | @Override | 64 | @Override |
| 65 | public Kind getKind() { | 65 | public Kind getKind() { |
| 66 | return Kind.CLASS_TYPE; | 66 | return Kind.CLASS_TYPE; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | @Override | 69 | @Override |
| 70 | public String toString() { | 70 | public String toString() { |
| 71 | return entry.toString(); | 71 | return entry.toString(); |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java index ce23cb6d..8e0afd59 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/ReferenceTreeNode.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis; | 12 | package cuchaz.enigma.analysis; |
| 13 | 13 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java index aea76180..b3ba8965 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java | |||
| @@ -1,180 +1,196 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.Comparator; | ||
| 5 | import java.util.List; | ||
| 6 | import java.util.stream.Stream; | ||
| 7 | |||
| 8 | import javax.swing.tree.DefaultMutableTreeNode; | ||
| 9 | |||
| 3 | import cuchaz.enigma.EnigmaProject; | 10 | import cuchaz.enigma.EnigmaProject; |
| 4 | import cuchaz.enigma.api.service.NameProposalService; | 11 | import cuchaz.enigma.api.service.NameProposalService; |
| 5 | import cuchaz.enigma.translation.TranslateResult; | 12 | import cuchaz.enigma.translation.TranslateResult; |
| 6 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 13 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 7 | import cuchaz.enigma.translation.representation.AccessFlags; | 14 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 8 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 15 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 9 | import cuchaz.enigma.translation.representation.entry.*; | 16 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 10 | 17 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | |
| 11 | import javax.swing.tree.DefaultMutableTreeNode; | 18 | import cuchaz.enigma.translation.representation.entry.DefEntry; |
| 12 | import java.util.ArrayList; | 19 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; |
| 13 | import java.util.Comparator; | 20 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 14 | import java.util.List; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 15 | import java.util.stream.Stream; | 22 | import cuchaz.enigma.translation.representation.entry.ParentedEntry; |
| 16 | 23 | ||
| 17 | public class StructureTreeNode extends DefaultMutableTreeNode { | 24 | public class StructureTreeNode extends DefaultMutableTreeNode { |
| 18 | private final List<NameProposalService> nameProposalServices; | 25 | private final List<NameProposalService> nameProposalServices; |
| 19 | private final EntryRemapper mapper; | 26 | private final EntryRemapper mapper; |
| 20 | private final ClassEntry parentEntry; | 27 | private final ClassEntry parentEntry; |
| 21 | private final ParentedEntry entry; | 28 | private final ParentedEntry entry; |
| 22 | 29 | ||
| 23 | public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) { | 30 | public StructureTreeNode(EnigmaProject project, ClassEntry parentEntry, ParentedEntry entry) { |
| 24 | this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE); | 31 | this.nameProposalServices = project.getEnigma().getServices().get(NameProposalService.TYPE); |
| 25 | this.mapper = project.getMapper(); | 32 | this.mapper = project.getMapper(); |
| 26 | this.parentEntry = parentEntry; | 33 | this.parentEntry = parentEntry; |
| 27 | this.entry = entry; | 34 | this.entry = entry; |
| 28 | } | 35 | } |
| 29 | 36 | ||
| 30 | /** | 37 | /** |
| 31 | * Returns the parented entry represented by this tree node. | 38 | * Returns the parented entry represented by this tree node. |
| 32 | */ | 39 | */ |
| 33 | public ParentedEntry getEntry() { | 40 | public ParentedEntry getEntry() { |
| 34 | return this.entry; | 41 | return this.entry; |
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | public void load(EnigmaProject project, StructureTreeOptions options) { | 44 | public void load(EnigmaProject project, StructureTreeOptions options) { |
| 38 | Stream<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream(); | 45 | Stream<ParentedEntry> children = project.getJarIndex().getChildrenByClass().get(this.parentEntry).stream(); |
| 39 | 46 | ||
| 40 | children = switch (options.obfuscationVisibility()) { | 47 | children = switch (options.obfuscationVisibility()) { |
| 41 | case ALL -> children; | 48 | case ALL -> children; |
| 42 | case OBFUSCATED -> children | 49 | case OBFUSCATED -> children |
| 43 | // remove deobfuscated members if only obfuscated, unless it's an inner class | 50 | // remove deobfuscated members if only obfuscated, unless it's an inner class |
| 44 | .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e))) | 51 | .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e))) |
| 45 | // keep constructor methods if the class is obfuscated | 52 | // keep constructor methods if the class is obfuscated |
| 46 | .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent())); | 53 | .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent())); |
| 47 | case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) | 54 | case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) || (!project.isObfuscated(e) && project.isRenamable(e)) |
| 48 | || (!project.isObfuscated(e) && project.isRenamable(e)) | 55 | // keep constructor methods if the class is deobfuscated |
| 49 | // keep constructor methods if the class is deobfuscated | 56 | || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent())); |
| 50 | || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent())); | 57 | }; |
| 51 | }; | 58 | |
| 52 | 59 | children = switch (options.documentationVisibility()) { | |
| 53 | children = switch (options.documentationVisibility()) { | 60 | case ALL -> children; |
| 54 | case ALL -> children; | 61 | // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation |
| 55 | // TODO remove EntryRemapper.deobfuscate() calls when javadocs will no longer be tied to deobfuscation | 62 | case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank())); |
| 56 | case DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() != null && !project.getMapper().deobfuscate(e).getJavadocs().isBlank())); | 63 | case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank())); |
| 57 | case NON_DOCUMENTED -> children.filter(e -> (e instanceof ClassEntry) || (project.getMapper().deobfuscate(e).getJavadocs() == null || project.getMapper().deobfuscate(e).getJavadocs().isBlank())); | 64 | }; |
| 58 | }; | 65 | |
| 59 | 66 | children = switch (options.sortingOrder()) { | |
| 60 | children = switch (options.sortingOrder()) { | 67 | case DEFAULT -> children; |
| 61 | case DEFAULT -> children; | 68 | case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) |
| 62 | case A_Z -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) | 69 | // compare the class name when the entry is a constructor |
| 63 | // compare the class name when the entry is a constructor | 70 | ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase())); |
| 64 | ? project.getMapper().deobfuscate(e.getParent()).getSimpleName().toLowerCase() | 71 | case Z_A -> children.sorted( |
| 65 | : project.getMapper().deobfuscate(e).getSimpleName().toLowerCase())); | 72 | Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) ? project.getMapper().deobfuscate(((ParentedEntry<?>) e).getParent()).getSimpleName().toLowerCase() : project.getMapper().deobfuscate((ParentedEntry<?>) e).getSimpleName().toLowerCase()).reversed()); |
| 66 | case Z_A -> children.sorted(Comparator.comparing(e -> (e instanceof MethodEntry m && m.isConstructor()) | 73 | }; |
| 67 | ? project.getMapper().deobfuscate(((ParentedEntry<?>) e).getParent()).getSimpleName().toLowerCase() | 74 | |
| 68 | : project.getMapper().deobfuscate((ParentedEntry<?>) e).getSimpleName().toLowerCase()) | 75 | for (ParentedEntry<?> child : children.toList()) { |
| 69 | .reversed()); | 76 | StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child); |
| 70 | }; | 77 | |
| 71 | 78 | if (child instanceof ClassEntry) { | |
| 72 | for (ParentedEntry<?> child : children.toList()) { | 79 | childNode = new StructureTreeNode(project, (ClassEntry) child, child); |
| 73 | StructureTreeNode childNode = new StructureTreeNode(project, this.parentEntry, child); | 80 | childNode.load(project, options); |
| 74 | 81 | } | |
| 75 | if (child instanceof ClassEntry) { | 82 | |
| 76 | childNode = new StructureTreeNode(project, (ClassEntry) child, child); | 83 | this.add(childNode); |
| 77 | childNode.load(project, options); | 84 | } |
| 78 | } | 85 | } |
| 79 | 86 | ||
| 80 | this.add(childNode); | 87 | @Override |
| 81 | } | 88 | public String toString() { |
| 82 | } | 89 | TranslateResult<ParentedEntry> translateResult = this.mapper.extendedDeobfuscate(this.entry); |
| 83 | 90 | String result = translateResult.getValue().getName(); | |
| 84 | @Override | 91 | |
| 85 | public String toString() { | 92 | if (translateResult.isObfuscated()) { |
| 86 | TranslateResult<ParentedEntry> translateResult = this.mapper.extendedDeobfuscate(this.entry); | 93 | if (!this.nameProposalServices.isEmpty()) { |
| 87 | String result = translateResult.getValue().getName(); | 94 | for (NameProposalService service : this.nameProposalServices) { |
| 88 | 95 | if (service.proposeName(this.entry, this.mapper).isPresent()) { | |
| 89 | if (translateResult.isObfuscated()) { | 96 | result = service.proposeName(this.entry, this.mapper).get(); |
| 90 | if (!this.nameProposalServices.isEmpty()) { | 97 | } |
| 91 | for (NameProposalService service : this.nameProposalServices) { | 98 | } |
| 92 | if (service.proposeName(this.entry, this.mapper).isPresent()) { | 99 | } |
| 93 | result = service.proposeName(this.entry, this.mapper).get(); | 100 | } |
| 94 | } | 101 | |
| 95 | } | 102 | if (this.entry instanceof FieldDefEntry) { |
| 96 | } | 103 | FieldDefEntry field = (FieldDefEntry) translateResult.getValue(); |
| 97 | } | 104 | String returnType = this.parseDesc(field.getDesc()); |
| 98 | 105 | ||
| 99 | if (this.entry instanceof FieldDefEntry) { | 106 | result = result + ": " + returnType; |
| 100 | FieldDefEntry field = (FieldDefEntry) translateResult.getValue(); | 107 | } else if (this.entry instanceof MethodDefEntry) { |
| 101 | String returnType = this.parseDesc(field.getDesc()); | 108 | MethodDefEntry method = (MethodDefEntry) translateResult.getValue(); |
| 102 | 109 | String args = this.parseArgs(method.getDesc().getArgumentDescs()); | |
| 103 | result = result + ": " + returnType; | 110 | String returnType = this.parseDesc(method.getDesc().getReturnDesc()); |
| 104 | } else if (this.entry instanceof MethodDefEntry) { | 111 | |
| 105 | MethodDefEntry method = (MethodDefEntry) translateResult.getValue(); | 112 | if (method.isConstructor()) { |
| 106 | String args = this.parseArgs(method.getDesc().getArgumentDescs()); | 113 | result = method.getParent().getSimpleName() + args; |
| 107 | String returnType = this.parseDesc(method.getDesc().getReturnDesc()); | 114 | } else { |
| 108 | 115 | result = result + args + ": " + returnType; | |
| 109 | if (method.isConstructor()) { | 116 | } |
| 110 | result = method.getParent().getSimpleName() + args; | 117 | } |
| 111 | } else { | 118 | |
| 112 | result = result + args + ": " + returnType; | 119 | return result; |
| 113 | } | 120 | } |
| 114 | } | 121 | |
| 115 | 122 | public String toHtml() { | |
| 116 | return result; | 123 | List<String> modifiers = new ArrayList<>(); |
| 117 | } | 124 | |
| 118 | 125 | if (this.entry instanceof DefEntry<?> defEntry) { | |
| 119 | public String toHtml() { | 126 | AccessFlags access = defEntry.getAccess(); |
| 120 | List<String> modifiers = new ArrayList<>(); | 127 | boolean isInterfaceMethod = false; |
| 121 | 128 | ||
| 122 | if (this.entry instanceof DefEntry<?> defEntry) { | 129 | if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) { |
| 123 | AccessFlags access = defEntry.getAccess(); | 130 | isInterfaceMethod = parent.getAccess().isInterface(); |
| 124 | boolean isInterfaceMethod = false; | 131 | } |
| 125 | 132 | ||
| 126 | if (this.entry instanceof MethodEntry && this.entry.getParent() instanceof ClassDefEntry parent) { | 133 | if (access.isStatic() && !access.isEnum()) { |
| 127 | isInterfaceMethod = parent.getAccess().isInterface(); | 134 | // Static member, but not an enum constant |
| 128 | } | 135 | modifiers.add("static"); |
| 129 | 136 | } else if (isInterfaceMethod && !access.isAbstract()) { | |
| 130 | if (access.isStatic() && !access.isEnum()) { | 137 | // Non-static default interface method |
| 131 | // Static member, but not an enum constant | 138 | modifiers.add("default"); |
| 132 | modifiers.add("static"); | 139 | } |
| 133 | } else if (isInterfaceMethod && !access.isAbstract()) { | 140 | |
| 134 | // Non-static default interface method | 141 | if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) { |
| 135 | modifiers.add("default"); | 142 | // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless) |
| 136 | } | 143 | modifiers.add("abstract"); |
| 137 | 144 | } else if (access.isFinal() && !access.isEnum()) { | |
| 138 | if (access.isAbstract() && !access.isInterface() && !isInterfaceMethod && !access.isEnum()) { | 145 | // Final, but not an enum or an enum constant (they're always final) |
| 139 | // Abstract, but not an interface, an interface method or an enum class (abstract is the default or meaningless) | 146 | modifiers.add("final"); |
| 140 | modifiers.add("abstract"); | 147 | } |
| 141 | } else if (access.isFinal() && !access.isEnum()) { | 148 | } |
| 142 | // Final, but not an enum or an enum constant (they're always final) | 149 | |
| 143 | modifiers.add("final"); | 150 | return "<i>" + String.join(" ", modifiers) + "</i> " + toString(); |
| 144 | } | 151 | } |
| 145 | } | 152 | |
| 146 | 153 | private String parseArgs(List<TypeDescriptor> args) { | |
| 147 | return "<i>" + String.join(" ", modifiers) + "</i> " + toString(); | 154 | if (args.size() > 0) { |
| 148 | } | 155 | String result = "("; |
| 149 | 156 | ||
| 150 | private String parseArgs(List<TypeDescriptor> args) { | 157 | for (int i = 0; i < args.size(); i++) { |
| 151 | if (args.size() > 0) { | 158 | if (i > 0) { |
| 152 | String result = "("; | 159 | result += ", "; |
| 153 | 160 | } | |
| 154 | for (int i = 0; i < args.size(); i++) { | 161 | |
| 155 | if (i > 0) { | 162 | result += this.parseDesc(args.get(i)); |
| 156 | result += ", "; | 163 | } |
| 157 | } | 164 | |
| 158 | 165 | return result + ")"; | |
| 159 | result += this.parseDesc(args.get(i)); | 166 | } |
| 160 | } | 167 | |
| 161 | 168 | return "()"; | |
| 162 | return result + ")"; | 169 | } |
| 163 | } | 170 | |
| 164 | 171 | private String parseDesc(TypeDescriptor desc) { | |
| 165 | return "()"; | 172 | if (desc.isVoid()) { |
| 166 | } | 173 | return "void"; |
| 167 | 174 | } | |
| 168 | private String parseDesc(TypeDescriptor desc) { | 175 | |
| 169 | if (desc.isVoid()) return "void"; | 176 | if (desc.isPrimitive()) { |
| 170 | if (desc.isPrimitive()) return desc.getPrimitive().getKeyword(); | 177 | return desc.getPrimitive().getKeyword(); |
| 171 | if (desc.isType()) return desc.getTypeEntry().getSimpleName(); | 178 | } |
| 172 | 179 | ||
| 173 | if (desc.isArray()) { | 180 | if (desc.isType()) { |
| 174 | if (desc.getArrayType().isPrimitive()) return desc.getArrayType().getPrimitive().getKeyword() + "[]"; | 181 | return desc.getTypeEntry().getSimpleName(); |
| 175 | if (desc.getArrayType().isType()) return desc.getArrayType().getTypeEntry().getSimpleName() + "[]"; | 182 | } |
| 176 | } | 183 | |
| 177 | 184 | if (desc.isArray()) { | |
| 178 | return null; | 185 | if (desc.getArrayType().isPrimitive()) { |
| 179 | } | 186 | return desc.getArrayType().getPrimitive().getKeyword() + "[]"; |
| 187 | } | ||
| 188 | |||
| 189 | if (desc.getArrayType().isType()) { | ||
| 190 | return desc.getArrayType().getTypeEntry().getSimpleName() + "[]"; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | return null; | ||
| 195 | } | ||
| 180 | } | 196 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java index cfc80b4a..e2e5084f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeOptions.java | |||
| @@ -1,59 +1,55 @@ | |||
| 1 | package cuchaz.enigma.analysis; | 1 | package cuchaz.enigma.analysis; |
| 2 | 2 | ||
| 3 | public record StructureTreeOptions( | 3 | public record StructureTreeOptions(ObfuscationVisibility obfuscationVisibility, DocumentationVisibility documentationVisibility, SortingOrder sortingOrder) { |
| 4 | ObfuscationVisibility obfuscationVisibility, | 4 | public enum ObfuscationVisibility implements Option { |
| 5 | DocumentationVisibility documentationVisibility, | 5 | ALL("structure.options.obfuscation.all"), |
| 6 | SortingOrder sortingOrder) { | 6 | OBFUSCATED("structure.options.obfuscation.obfuscated"), |
| 7 | 7 | DEOBFUSCATED("structure.options.obfuscation.deobfuscated"); | |
| 8 | public enum ObfuscationVisibility implements Option { | 8 | |
| 9 | ALL("structure.options.obfuscation.all"), | 9 | private final String translationKey; |
| 10 | OBFUSCATED("structure.options.obfuscation.obfuscated"), | 10 | |
| 11 | DEOBFUSCATED("structure.options.obfuscation.deobfuscated"); | 11 | ObfuscationVisibility(String translationKey) { |
| 12 | 12 | this.translationKey = translationKey; | |
| 13 | private final String translationKey; | 13 | } |
| 14 | 14 | ||
| 15 | ObfuscationVisibility(String translationKey) { | 15 | public String getTranslationKey() { |
| 16 | this.translationKey = translationKey; | 16 | return this.translationKey; |
| 17 | } | 17 | } |
| 18 | 18 | } | |
| 19 | public String getTranslationKey() { | 19 | |
| 20 | return this.translationKey; | 20 | public enum DocumentationVisibility implements Option { |
| 21 | } | 21 | ALL("structure.options.documentation.all"), |
| 22 | } | 22 | DOCUMENTED("structure.options.documentation.documented"), |
| 23 | 23 | NON_DOCUMENTED("structure.options.documentation.non_documented"); | |
| 24 | public enum DocumentationVisibility implements Option { | 24 | |
| 25 | ALL("structure.options.documentation.all"), | 25 | private final String translationKey; |
| 26 | DOCUMENTED("structure.options.documentation.documented"), | 26 | |
| 27 | NON_DOCUMENTED("structure.options.documentation.non_documented"); | 27 | DocumentationVisibility(String translationKey) { |
| 28 | 28 | this.translationKey = translationKey; | |
| 29 | private final String translationKey; | 29 | } |
| 30 | 30 | ||
| 31 | DocumentationVisibility(String translationKey) { | 31 | public String getTranslationKey() { |
| 32 | this.translationKey = translationKey; | 32 | return this.translationKey; |
| 33 | } | 33 | } |
| 34 | 34 | } | |
| 35 | public String getTranslationKey() { | 35 | |
| 36 | return this.translationKey; | 36 | public enum SortingOrder implements Option { |
| 37 | } | 37 | DEFAULT("structure.options.sorting.default"), |
| 38 | } | 38 | A_Z("structure.options.sorting.a_z"), |
| 39 | 39 | Z_A("structure.options.sorting.z_a"); | |
| 40 | public enum SortingOrder implements Option { | 40 | |
| 41 | DEFAULT("structure.options.sorting.default"), | 41 | private final String translationKey; |
| 42 | A_Z("structure.options.sorting.a_z"), | 42 | |
| 43 | Z_A("structure.options.sorting.z_a"); | 43 | SortingOrder(String translationKey) { |
| 44 | 44 | this.translationKey = translationKey; | |
| 45 | private final String translationKey; | 45 | } |
| 46 | 46 | ||
| 47 | SortingOrder(String translationKey) { | 47 | public String getTranslationKey() { |
| 48 | this.translationKey = translationKey; | 48 | return this.translationKey; |
| 49 | } | 49 | } |
| 50 | 50 | } | |
| 51 | public String getTranslationKey() { | 51 | |
| 52 | return this.translationKey; | 52 | public interface Option { |
| 53 | } | 53 | String getTranslationKey(); |
| 54 | } | 54 | } |
| 55 | |||
| 56 | public interface Option { | ||
| 57 | String getTranslationKey(); | ||
| 58 | } | ||
| 59 | } | 55 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java index a4b1aac9..26093c3c 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/BridgeMethodIndex.java | |||
| @@ -1,6 +1,15 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.Collections; | ||
| 5 | import java.util.HashMap; | ||
| 6 | import java.util.List; | ||
| 7 | import java.util.Map; | ||
| 8 | |||
| 9 | import javax.annotation.Nullable; | ||
| 10 | |||
| 3 | import com.google.common.collect.Maps; | 11 | import com.google.common.collect.Maps; |
| 12 | |||
| 4 | import cuchaz.enigma.translation.representation.AccessFlags; | 13 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 5 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 14 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 6 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 15 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| @@ -8,9 +17,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 8 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 17 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 9 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 10 | 19 | ||
| 11 | import javax.annotation.Nullable; | ||
| 12 | import java.util.*; | ||
| 13 | |||
| 14 | public class BridgeMethodIndex implements JarIndexer { | 20 | public class BridgeMethodIndex implements JarIndexer { |
| 15 | private final EntryIndex entryIndex; | 21 | private final EntryIndex entryIndex; |
| 16 | private final InheritanceIndex inheritanceIndex; | 22 | private final InheritanceIndex inheritanceIndex; |
| @@ -31,6 +37,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 31 | MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; | 37 | MethodDefEntry methodDefEntry = (MethodDefEntry) methodEntry; |
| 32 | 38 | ||
| 33 | AccessFlags access = methodDefEntry.getAccess(); | 39 | AccessFlags access = methodDefEntry.getAccess(); |
| 40 | |||
| 34 | if (access == null || !access.isSynthetic()) { | 41 | if (access == null || !access.isSynthetic()) { |
| 35 | continue; | 42 | continue; |
| 36 | } | 43 | } |
| @@ -46,6 +53,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 46 | for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) { | 53 | for (Map.Entry<MethodEntry, MethodEntry> entry : copiedAccessToBridge.entrySet()) { |
| 47 | MethodEntry specializedEntry = entry.getKey(); | 54 | MethodEntry specializedEntry = entry.getKey(); |
| 48 | MethodEntry bridgeEntry = entry.getValue(); | 55 | MethodEntry bridgeEntry = entry.getValue(); |
| 56 | |||
| 49 | if (bridgeEntry.getName().equals(specializedEntry.getName())) { | 57 | if (bridgeEntry.getName().equals(specializedEntry.getName())) { |
| 50 | continue; | 58 | continue; |
| 51 | } | 59 | } |
| @@ -57,6 +65,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 57 | 65 | ||
| 58 | private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { | 66 | private void indexSyntheticMethod(MethodDefEntry syntheticMethod, AccessFlags access) { |
| 59 | MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); | 67 | MethodEntry specializedMethod = findSpecializedMethod(syntheticMethod); |
| 68 | |||
| 60 | if (specializedMethod == null) { | 69 | if (specializedMethod == null) { |
| 61 | return; | 70 | return; |
| 62 | } | 71 | } |
| @@ -84,6 +93,7 @@ public class BridgeMethodIndex implements JarIndexer { | |||
| 84 | private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) { | 93 | private boolean isPotentialBridge(MethodDefEntry bridgeMethod, MethodEntry specializedMethod) { |
| 85 | // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited | 94 | // Bridge methods only exist for inheritance purposes, if we're private, final, or static, we cannot be inherited |
| 86 | AccessFlags bridgeAccess = bridgeMethod.getAccess(); | 95 | AccessFlags bridgeAccess = bridgeMethod.getAccess(); |
| 96 | |||
| 87 | if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { | 97 | if (bridgeAccess.isPrivate() || bridgeAccess.isFinal() || bridgeAccess.isStatic()) { |
| 88 | return false; | 98 | return false; |
| 89 | } | 99 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java index bb992b73..0e4cdcfa 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/EntryIndex.java | |||
| @@ -1,13 +1,21 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.AccessFlags; | ||
| 4 | import cuchaz.enigma.translation.representation.entry.*; | ||
| 5 | |||
| 6 | import javax.annotation.Nullable; | ||
| 7 | import java.util.Collection; | 3 | import java.util.Collection; |
| 8 | import java.util.HashMap; | 4 | import java.util.HashMap; |
| 9 | import java.util.Map; | 5 | import java.util.Map; |
| 10 | 6 | ||
| 7 | import javax.annotation.Nullable; | ||
| 8 | |||
| 9 | import cuchaz.enigma.translation.representation.AccessFlags; | ||
| 10 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 11 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 15 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 17 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 18 | |||
| 11 | public class EntryIndex implements JarIndexer { | 19 | public class EntryIndex implements JarIndexer { |
| 12 | private Map<ClassEntry, AccessFlags> classes = new HashMap<>(); | 20 | private Map<ClassEntry, AccessFlags> classes = new HashMap<>(); |
| 13 | private Map<FieldEntry, AccessFlags> fields = new HashMap<>(); | 21 | private Map<FieldEntry, AccessFlags> fields = new HashMap<>(); |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java index f9cb23ce..e697182f 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexClassVisitor.java | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 4 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 5 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 6 | import org.objectweb.asm.ClassVisitor; | 3 | import org.objectweb.asm.ClassVisitor; |
| 7 | import org.objectweb.asm.FieldVisitor; | 4 | import org.objectweb.asm.FieldVisitor; |
| 8 | import org.objectweb.asm.MethodVisitor; | 5 | import org.objectweb.asm.MethodVisitor; |
| 9 | 6 | ||
| 7 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 10 | |||
| 10 | public class IndexClassVisitor extends ClassVisitor { | 11 | public class IndexClassVisitor extends ClassVisitor { |
| 11 | private final JarIndexer indexer; | 12 | private final JarIndexer indexer; |
| 12 | private ClassDefEntry classEntry; | 13 | private ClassDefEntry classEntry; |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java index efea83d4..97fec47b 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/IndexReferenceVisitor.java | |||
| @@ -1,5 +1,22 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import java.util.List; | ||
| 4 | |||
| 5 | import org.objectweb.asm.ClassVisitor; | ||
| 6 | import org.objectweb.asm.Handle; | ||
| 7 | import org.objectweb.asm.MethodVisitor; | ||
| 8 | import org.objectweb.asm.Opcodes; | ||
| 9 | import org.objectweb.asm.Type; | ||
| 10 | import org.objectweb.asm.tree.AbstractInsnNode; | ||
| 11 | import org.objectweb.asm.tree.FieldInsnNode; | ||
| 12 | import org.objectweb.asm.tree.InvokeDynamicInsnNode; | ||
| 13 | import org.objectweb.asm.tree.MethodInsnNode; | ||
| 14 | import org.objectweb.asm.tree.analysis.Analyzer; | ||
| 15 | import org.objectweb.asm.tree.analysis.AnalyzerException; | ||
| 16 | import org.objectweb.asm.tree.analysis.BasicValue; | ||
| 17 | import org.objectweb.asm.tree.analysis.SourceInterpreter; | ||
| 18 | import org.objectweb.asm.tree.analysis.SourceValue; | ||
| 19 | |||
| 3 | import cuchaz.enigma.analysis.IndexSimpleVerifier; | 20 | import cuchaz.enigma.analysis.IndexSimpleVerifier; |
| 4 | import cuchaz.enigma.analysis.InterpreterPair; | 21 | import cuchaz.enigma.analysis.InterpreterPair; |
| 5 | import cuchaz.enigma.analysis.MethodNodeWithAction; | 22 | import cuchaz.enigma.analysis.MethodNodeWithAction; |
| @@ -8,15 +25,11 @@ import cuchaz.enigma.translation.representation.AccessFlags; | |||
| 8 | import cuchaz.enigma.translation.representation.Lambda; | 25 | import cuchaz.enigma.translation.representation.Lambda; |
| 9 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 26 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 10 | import cuchaz.enigma.translation.representation.Signature; | 27 | import cuchaz.enigma.translation.representation.Signature; |
| 11 | import cuchaz.enigma.translation.representation.entry.*; | 28 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 12 | import org.objectweb.asm.*; | 29 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 13 | import org.objectweb.asm.tree.AbstractInsnNode; | 30 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 14 | import org.objectweb.asm.tree.FieldInsnNode; | 31 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 15 | import org.objectweb.asm.tree.InvokeDynamicInsnNode; | 32 | import cuchaz.enigma.translation.representation.entry.ParentedEntry; |
| 16 | import org.objectweb.asm.tree.MethodInsnNode; | ||
| 17 | import org.objectweb.asm.tree.analysis.*; | ||
| 18 | |||
| 19 | import java.util.List; | ||
| 20 | 33 | ||
| 21 | public class IndexReferenceVisitor extends ClassVisitor { | 34 | public class IndexReferenceVisitor extends ClassVisitor { |
| 22 | private final JarIndexer indexer; | 35 | private final JarIndexer indexer; |
| @@ -54,7 +67,7 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 54 | private final MethodDefEntry callerEntry; | 67 | private final MethodDefEntry callerEntry; |
| 55 | private JarIndexer indexer; | 68 | private JarIndexer indexer; |
| 56 | 69 | ||
| 57 | public MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { | 70 | MethodInterpreter(MethodDefEntry callerEntry, JarIndexer indexer, EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { |
| 58 | super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); | 71 | super(new IndexSimpleVerifier(entryIndex, inheritanceIndex), new SourceInterpreter()); |
| 59 | this.callerEntry = callerEntry; | 72 | this.callerEntry = callerEntry; |
| 60 | this.indexer = indexer; | 73 | this.indexer = indexer; |
| @@ -85,7 +98,6 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 85 | return super.unaryOperation(insn, value); | 98 | return super.unaryOperation(insn, value); |
| 86 | } | 99 | } |
| 87 | 100 | ||
| 88 | |||
| 89 | @Override | 101 | @Override |
| 90 | public PairValue<BasicValue, SourceValue> binaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value1, PairValue<BasicValue, SourceValue> value2) throws AnalyzerException { | 102 | public PairValue<BasicValue, SourceValue> binaryOperation(AbstractInsnNode insn, PairValue<BasicValue, SourceValue> value1, PairValue<BasicValue, SourceValue> value2) throws AnalyzerException { |
| 91 | if (insn.getOpcode() == Opcodes.PUTFIELD) { | 103 | if (insn.getOpcode() == Opcodes.PUTFIELD) { |
| @@ -119,6 +131,7 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 119 | Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2]; | 131 | Type instantiatedMethodType = (Type) invokeDynamicInsn.bsmArgs[2]; |
| 120 | 132 | ||
| 121 | ReferenceTargetType targetType; | 133 | ReferenceTargetType targetType; |
| 134 | |||
| 122 | if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) { | 135 | if (implMethod.getTag() != Opcodes.H_GETSTATIC && implMethod.getTag() != Opcodes.H_PUTFIELD && implMethod.getTag() != Opcodes.H_INVOKESTATIC) { |
| 123 | if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) { | 136 | if (instantiatedMethodType.getArgumentTypes().length < Type.getArgumentTypes(implMethod.getDesc()).length) { |
| 124 | targetType = getReferenceTargetType(values.get(0), insn); | 137 | targetType = getReferenceTargetType(values.get(0), insn); |
| @@ -129,13 +142,7 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 129 | targetType = ReferenceTargetType.none(); | 142 | targetType = ReferenceTargetType.none(); |
| 130 | } | 143 | } |
| 131 | 144 | ||
| 132 | indexer.indexLambda(callerEntry, new Lambda( | 145 | indexer.indexLambda(callerEntry, new Lambda(invokeDynamicInsn.name, new MethodDescriptor(invokeDynamicInsn.desc), new MethodDescriptor(samMethodType.getDescriptor()), getHandleEntry(implMethod), new MethodDescriptor(instantiatedMethodType.getDescriptor())), targetType); |
| 133 | invokeDynamicInsn.name, | ||
| 134 | new MethodDescriptor(invokeDynamicInsn.desc), | ||
| 135 | new MethodDescriptor(samMethodType.getDescriptor()), | ||
| 136 | getHandleEntry(implMethod), | ||
| 137 | new MethodDescriptor(instantiatedMethodType.getDescriptor()) | ||
| 138 | ), targetType); | ||
| 139 | } | 146 | } |
| 140 | } | 147 | } |
| 141 | 148 | ||
| @@ -160,17 +167,17 @@ public class IndexReferenceVisitor extends ClassVisitor { | |||
| 160 | 167 | ||
| 161 | private static ParentedEntry<?> getHandleEntry(Handle handle) { | 168 | private static ParentedEntry<?> getHandleEntry(Handle handle) { |
| 162 | switch (handle.getTag()) { | 169 | switch (handle.getTag()) { |
| 163 | case Opcodes.H_GETFIELD: | 170 | case Opcodes.H_GETFIELD: |
| 164 | case Opcodes.H_GETSTATIC: | 171 | case Opcodes.H_GETSTATIC: |
| 165 | case Opcodes.H_PUTFIELD: | 172 | case Opcodes.H_PUTFIELD: |
| 166 | case Opcodes.H_PUTSTATIC: | 173 | case Opcodes.H_PUTSTATIC: |
| 167 | return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); | 174 | return FieldEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); |
| 168 | case Opcodes.H_INVOKEINTERFACE: | 175 | case Opcodes.H_INVOKEINTERFACE: |
| 169 | case Opcodes.H_INVOKESPECIAL: | 176 | case Opcodes.H_INVOKESPECIAL: |
| 170 | case Opcodes.H_INVOKESTATIC: | 177 | case Opcodes.H_INVOKESTATIC: |
| 171 | case Opcodes.H_INVOKEVIRTUAL: | 178 | case Opcodes.H_INVOKEVIRTUAL: |
| 172 | case Opcodes.H_NEWINVOKESPECIAL: | 179 | case Opcodes.H_NEWINVOKESPECIAL: |
| 173 | return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); | 180 | return MethodEntry.parse(handle.getOwner(), handle.getName(), handle.getDesc()); |
| 174 | } | 181 | } |
| 175 | 182 | ||
| 176 | throw new RuntimeException("Invalid handle tag " + handle.getTag()); | 183 | throw new RuntimeException("Invalid handle tag " + handle.getTag()); |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java index 1ab2abdf..1c60db96 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/InheritanceIndex.java | |||
| @@ -1,27 +1,28 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis.index; | 12 | package cuchaz.enigma.analysis.index; |
| 13 | 13 | ||
| 14 | import java.util.Collection; | ||
| 15 | import java.util.HashSet; | ||
| 16 | import java.util.LinkedList; | ||
| 17 | import java.util.Set; | ||
| 18 | |||
| 14 | import com.google.common.collect.HashMultimap; | 19 | import com.google.common.collect.HashMultimap; |
| 15 | import com.google.common.collect.Multimap; | 20 | import com.google.common.collect.Multimap; |
| 16 | import com.google.common.collect.Sets; | 21 | import com.google.common.collect.Sets; |
| 22 | |||
| 17 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | 23 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 24 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | 25 | ||
| 20 | import java.util.Collection; | ||
| 21 | import java.util.HashSet; | ||
| 22 | import java.util.LinkedList; | ||
| 23 | import java.util.Set; | ||
| 24 | |||
| 25 | public class InheritanceIndex implements JarIndexer { | 26 | public class InheritanceIndex implements JarIndexer { |
| 26 | private final EntryIndex entryIndex; | 27 | private final EntryIndex entryIndex; |
| 27 | 28 | ||
| @@ -39,6 +40,7 @@ public class InheritanceIndex implements JarIndexer { | |||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | ClassEntry superClass = classEntry.getSuperClass(); | 42 | ClassEntry superClass = classEntry.getSuperClass(); |
| 43 | |||
| 42 | if (superClass != null && !superClass.getName().equals("java/lang/Object")) { | 44 | if (superClass != null && !superClass.getName().equals("java/lang/Object")) { |
| 43 | indexParent(classEntry, superClass); | 45 | indexParent(classEntry, superClass); |
| 44 | } | 46 | } |
| @@ -96,8 +98,13 @@ public class InheritanceIndex implements JarIndexer { | |||
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) { | 100 | public Relation computeClassRelation(ClassEntry classEntry, ClassEntry potentialAncestor) { |
| 99 | if (potentialAncestor.getName().equals("java/lang/Object")) return Relation.RELATED; | 101 | if (potentialAncestor.getName().equals("java/lang/Object")) { |
| 100 | if (!entryIndex.hasClass(classEntry)) return Relation.UNKNOWN; | 102 | return Relation.RELATED; |
| 103 | } | ||
| 104 | |||
| 105 | if (!entryIndex.hasClass(classEntry)) { | ||
| 106 | return Relation.UNKNOWN; | ||
| 107 | } | ||
| 101 | 108 | ||
| 102 | for (ClassEntry ancestor : getAncestors(classEntry)) { | 109 | for (ClassEntry ancestor : getAncestors(classEntry)) { |
| 103 | if (potentialAncestor.equals(ancestor)) { | 110 | if (potentialAncestor.equals(ancestor)) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java index 6c26282e..60864ba5 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java | |||
| @@ -1,17 +1,26 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.analysis.index; | 12 | package cuchaz.enigma.analysis.index; |
| 13 | 13 | ||
| 14 | import com.google.common.collect.*; | 14 | import java.util.Collection; |
| 15 | import java.util.HashSet; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.Set; | ||
| 18 | |||
| 19 | import com.google.common.collect.ArrayListMultimap; | ||
| 20 | import com.google.common.collect.HashMultimap; | ||
| 21 | import com.google.common.collect.ListMultimap; | ||
| 22 | import com.google.common.collect.Multimap; | ||
| 23 | |||
| 15 | import cuchaz.enigma.Enigma; | 24 | import cuchaz.enigma.Enigma; |
| 16 | import cuchaz.enigma.ProgressListener; | 25 | import cuchaz.enigma.ProgressListener; |
| 17 | import cuchaz.enigma.analysis.ReferenceTargetType; | 26 | import cuchaz.enigma.analysis.ReferenceTargetType; |
| @@ -19,11 +28,15 @@ import cuchaz.enigma.classprovider.ClassProvider; | |||
| 19 | import cuchaz.enigma.translation.mapping.EntryResolver; | 28 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 20 | import cuchaz.enigma.translation.mapping.IndexEntryResolver; | 29 | import cuchaz.enigma.translation.mapping.IndexEntryResolver; |
| 21 | import cuchaz.enigma.translation.representation.Lambda; | 30 | import cuchaz.enigma.translation.representation.Lambda; |
| 22 | import cuchaz.enigma.translation.representation.entry.*; | 31 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 32 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 33 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 34 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 35 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 36 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 37 | import cuchaz.enigma.translation.representation.entry.ParentedEntry; | ||
| 23 | import cuchaz.enigma.utils.I18n; | 38 | import cuchaz.enigma.utils.I18n; |
| 24 | 39 | ||
| 25 | import java.util.*; | ||
| 26 | |||
| 27 | public class JarIndex implements JarIndexer { | 40 | public class JarIndex implements JarIndexer { |
| 28 | private final Set<String> indexedClasses = new HashSet<>(); | 41 | private final Set<String> indexedClasses = new HashSet<>(); |
| 29 | private final EntryIndex entryIndex; | 42 | private final EntryIndex entryIndex; |
| @@ -99,6 +112,7 @@ public class JarIndex implements JarIndexer { | |||
| 99 | } | 112 | } |
| 100 | 113 | ||
| 101 | indexers.forEach(indexer -> indexer.indexClass(classEntry)); | 114 | indexers.forEach(indexer -> indexer.indexClass(classEntry)); |
| 115 | |||
| 102 | if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) { | 116 | if (classEntry.isInnerClass() && !classEntry.getAccess().isSynthetic()) { |
| 103 | childrenByClass.put(classEntry.getParent(), classEntry); | 117 | childrenByClass.put(classEntry.getParent(), classEntry); |
| 104 | } | 118 | } |
| @@ -111,6 +125,7 @@ public class JarIndex implements JarIndexer { | |||
| 111 | } | 125 | } |
| 112 | 126 | ||
| 113 | indexers.forEach(indexer -> indexer.indexField(fieldEntry)); | 127 | indexers.forEach(indexer -> indexer.indexField(fieldEntry)); |
| 128 | |||
| 114 | if (!fieldEntry.getAccess().isSynthetic()) { | 129 | if (!fieldEntry.getAccess().isSynthetic()) { |
| 115 | childrenByClass.put(fieldEntry.getParent(), fieldEntry); | 130 | childrenByClass.put(fieldEntry.getParent(), fieldEntry); |
| 116 | } | 131 | } |
| @@ -123,6 +138,7 @@ public class JarIndex implements JarIndexer { | |||
| 123 | } | 138 | } |
| 124 | 139 | ||
| 125 | indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); | 140 | indexers.forEach(indexer -> indexer.indexMethod(methodEntry)); |
| 141 | |||
| 126 | if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("<clinit>")) { | 142 | if (!methodEntry.getAccess().isSynthetic() && !methodEntry.getName().equals("<clinit>")) { |
| 127 | childrenByClass.put(methodEntry.getParent(), methodEntry); | 143 | childrenByClass.put(methodEntry.getParent(), methodEntry); |
| 128 | } | 144 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java index f17e7c98..8726fb56 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndexer.java | |||
| @@ -2,7 +2,11 @@ package cuchaz.enigma.analysis.index; | |||
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.ReferenceTargetType; | 3 | import cuchaz.enigma.analysis.ReferenceTargetType; |
| 4 | import cuchaz.enigma.translation.representation.Lambda; | 4 | import cuchaz.enigma.translation.representation.Lambda; |
| 5 | import cuchaz.enigma.translation.representation.entry.*; | 5 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 6 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 7 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 6 | 10 | ||
| 7 | public interface JarIndexer { | 11 | public interface JarIndexer { |
| 8 | default void indexClass(ClassDefEntry classEntry) { | 12 | default void indexClass(ClassDefEntry classEntry) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java index 64de5f37..b400a66c 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/PackageVisibilityIndex.java | |||
| @@ -1,15 +1,25 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.HashSet; | ||
| 5 | import java.util.Iterator; | ||
| 6 | import java.util.List; | ||
| 7 | import java.util.Map; | ||
| 8 | import java.util.Set; | ||
| 9 | |||
| 3 | import com.google.common.collect.HashMultimap; | 10 | import com.google.common.collect.HashMultimap; |
| 4 | import com.google.common.collect.Lists; | 11 | import com.google.common.collect.Lists; |
| 5 | import com.google.common.collect.Maps; | 12 | import com.google.common.collect.Maps; |
| 6 | import com.google.common.collect.Sets; | 13 | import com.google.common.collect.Sets; |
| 14 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | 15 | import cuchaz.enigma.analysis.EntryReference; |
| 8 | import cuchaz.enigma.analysis.ReferenceTargetType; | 16 | import cuchaz.enigma.analysis.ReferenceTargetType; |
| 9 | import cuchaz.enigma.translation.representation.AccessFlags; | 17 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 10 | import cuchaz.enigma.translation.representation.entry.*; | 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 11 | 19 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | |
| 12 | import java.util.*; | 20 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 21 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 22 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 13 | 23 | ||
| 14 | public class PackageVisibilityIndex implements JarIndexer { | 24 | public class PackageVisibilityIndex implements JarIndexer { |
| 15 | private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { | 25 | private static boolean requiresSamePackage(AccessFlags entryAcc, EntryReference ref, InheritanceIndex inheritanceIndex) { |
| @@ -30,9 +40,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 30 | } | 40 | } |
| 31 | 41 | ||
| 32 | // access to instance member only valid if target's class assignable to context class | 42 | // access to instance member only valid if target's class assignable to context class |
| 33 | return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || | 43 | return !(ref.targetType.getKind() == ReferenceTargetType.Kind.UNINITIALIZED || ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass)); |
| 34 | ((ReferenceTargetType.ClassType) ref.targetType).getEntry().equals(contextClass) || | ||
| 35 | inheritanceIndex.getAncestors(((ReferenceTargetType.ClassType) ref.targetType).getEntry()).contains(contextClass)); | ||
| 36 | } | 44 | } |
| 37 | 45 | ||
| 38 | return true; | 46 | return true; |
| @@ -61,6 +69,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 61 | private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) { | 69 | private void addConnections(EntryIndex entryIndex, ReferenceIndex referenceIndex, InheritanceIndex inheritanceIndex) { |
| 62 | for (FieldEntry entry : entryIndex.getFields()) { | 70 | for (FieldEntry entry : entryIndex.getFields()) { |
| 63 | AccessFlags entryAcc = entryIndex.getFieldAccess(entry); | 71 | AccessFlags entryAcc = entryIndex.getFieldAccess(entry); |
| 72 | |||
| 64 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | 73 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { |
| 65 | for (EntryReference<FieldEntry, MethodDefEntry> ref : referenceIndex.getReferencesToField(entry)) { | 74 | for (EntryReference<FieldEntry, MethodDefEntry> ref : referenceIndex.getReferencesToField(entry)) { |
| 66 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { | 75 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { |
| @@ -72,6 +81,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 72 | 81 | ||
| 73 | for (MethodEntry entry : entryIndex.getMethods()) { | 82 | for (MethodEntry entry : entryIndex.getMethods()) { |
| 74 | AccessFlags entryAcc = entryIndex.getMethodAccess(entry); | 83 | AccessFlags entryAcc = entryIndex.getMethodAccess(entry); |
| 84 | |||
| 75 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | 85 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { |
| 76 | for (EntryReference<MethodEntry, MethodDefEntry> ref : referenceIndex.getReferencesToMethod(entry)) { | 86 | for (EntryReference<MethodEntry, MethodDefEntry> ref : referenceIndex.getReferencesToMethod(entry)) { |
| 77 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { | 87 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { |
| @@ -83,6 +93,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 83 | 93 | ||
| 84 | for (ClassEntry entry : entryIndex.getClasses()) { | 94 | for (ClassEntry entry : entryIndex.getClasses()) { |
| 85 | AccessFlags entryAcc = entryIndex.getClassAccess(entry); | 95 | AccessFlags entryAcc = entryIndex.getClassAccess(entry); |
| 96 | |||
| 86 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { | 97 | if (!entryAcc.isPublic() && !entryAcc.isPrivate()) { |
| 87 | for (EntryReference<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) { | 98 | for (EntryReference<ClassEntry, FieldDefEntry> ref : referenceIndex.getFieldTypeReferencesToClass(entry)) { |
| 88 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { | 99 | if (requiresSamePackage(entryAcc, ref, inheritanceIndex)) { |
| @@ -99,12 +110,14 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 99 | 110 | ||
| 100 | for (ClassEntry parent : inheritanceIndex.getParents(entry)) { | 111 | for (ClassEntry parent : inheritanceIndex.getParents(entry)) { |
| 101 | AccessFlags parentAcc = entryIndex.getClassAccess(parent); | 112 | AccessFlags parentAcc = entryIndex.getClassAccess(parent); |
| 113 | |||
| 102 | if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) { | 114 | if (parentAcc != null && !parentAcc.isPublic() && !parentAcc.isPrivate()) { |
| 103 | addConnection(entry, parent); | 115 | addConnection(entry, parent); |
| 104 | } | 116 | } |
| 105 | } | 117 | } |
| 106 | 118 | ||
| 107 | ClassEntry outerClass = entry.getOuterClass(); | 119 | ClassEntry outerClass = entry.getOuterClass(); |
| 120 | |||
| 108 | if (outerClass != null) { | 121 | if (outerClass != null) { |
| 109 | addConnection(entry, outerClass); | 122 | addConnection(entry, outerClass); |
| 110 | } | 123 | } |
| @@ -113,6 +126,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 113 | 126 | ||
| 114 | private void addPartitions(EntryIndex entryIndex) { | 127 | private void addPartitions(EntryIndex entryIndex) { |
| 115 | Set<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); | 128 | Set<ClassEntry> unassignedClasses = Sets.newHashSet(entryIndex.getClasses()); |
| 129 | |||
| 116 | while (!unassignedClasses.isEmpty()) { | 130 | while (!unassignedClasses.isEmpty()) { |
| 117 | Iterator<ClassEntry> iterator = unassignedClasses.iterator(); | 131 | Iterator<ClassEntry> iterator = unassignedClasses.iterator(); |
| 118 | ClassEntry initialEntry = iterator.next(); | 132 | ClassEntry initialEntry = iterator.next(); |
| @@ -122,6 +136,7 @@ public class PackageVisibilityIndex implements JarIndexer { | |||
| 122 | partition.add(initialEntry); | 136 | partition.add(initialEntry); |
| 123 | buildPartition(unassignedClasses, partition, initialEntry); | 137 | buildPartition(unassignedClasses, partition, initialEntry); |
| 124 | partitions.add(partition); | 138 | partitions.add(partition); |
| 139 | |||
| 125 | for (ClassEntry entry : partition) { | 140 | for (ClassEntry entry : partition) { |
| 126 | classPartitions.put(entry, partition); | 141 | classPartitions.put(entry, partition); |
| 127 | } | 142 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java index b6797c21..332a9674 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/ReferenceIndex.java | |||
| @@ -1,17 +1,23 @@ | |||
| 1 | package cuchaz.enigma.analysis.index; | 1 | package cuchaz.enigma.analysis.index; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.Map; | ||
| 5 | |||
| 3 | import com.google.common.collect.HashMultimap; | 6 | import com.google.common.collect.HashMultimap; |
| 4 | import com.google.common.collect.Multimap; | 7 | import com.google.common.collect.Multimap; |
| 8 | |||
| 5 | import cuchaz.enigma.analysis.EntryReference; | 9 | import cuchaz.enigma.analysis.EntryReference; |
| 6 | import cuchaz.enigma.analysis.ReferenceTargetType; | 10 | import cuchaz.enigma.analysis.ReferenceTargetType; |
| 7 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 11 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 8 | import cuchaz.enigma.translation.representation.Lambda; | 12 | import cuchaz.enigma.translation.representation.Lambda; |
| 9 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 13 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 10 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 14 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 11 | import cuchaz.enigma.translation.representation.entry.*; | 15 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 12 | 16 | import cuchaz.enigma.translation.representation.entry.Entry; | |
| 13 | import java.util.Collection; | 17 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; |
| 14 | import java.util.Map; | 18 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 20 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | 21 | ||
| 16 | public class ReferenceIndex implements JarIndexer { | 22 | public class ReferenceIndex implements JarIndexer { |
| 17 | private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); | 23 | private Multimap<MethodEntry, MethodEntry> methodReferences = HashMultimap.create(); |
| @@ -24,13 +30,14 @@ public class ReferenceIndex implements JarIndexer { | |||
| 24 | 30 | ||
| 25 | @Override | 31 | @Override |
| 26 | public void indexMethod(MethodDefEntry methodEntry) { | 32 | public void indexMethod(MethodDefEntry methodEntry) { |
| 27 | indexMethodDescriptor(methodEntry, methodEntry.getDesc()); | 33 | indexMethodDescriptor(methodEntry, methodEntry.getDesc()); |
| 28 | } | 34 | } |
| 29 | 35 | ||
| 30 | private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) { | 36 | private void indexMethodDescriptor(MethodDefEntry entry, MethodDescriptor descriptor) { |
| 31 | for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) { | 37 | for (TypeDescriptor typeDescriptor : descriptor.getArgumentDescs()) { |
| 32 | indexMethodTypeDescriptor(entry, typeDescriptor); | 38 | indexMethodTypeDescriptor(entry, typeDescriptor); |
| 33 | } | 39 | } |
| 40 | |||
| 34 | indexMethodTypeDescriptor(entry, descriptor.getReturnDesc()); | 41 | indexMethodTypeDescriptor(entry, descriptor.getReturnDesc()); |
| 35 | } | 42 | } |
| 36 | 43 | ||
| @@ -45,7 +52,7 @@ public class ReferenceIndex implements JarIndexer { | |||
| 45 | 52 | ||
| 46 | @Override | 53 | @Override |
| 47 | public void indexField(FieldDefEntry fieldEntry) { | 54 | public void indexField(FieldDefEntry fieldEntry) { |
| 48 | indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc()); | 55 | indexFieldTypeDescriptor(fieldEntry, fieldEntry.getDesc()); |
| 49 | } | 56 | } |
| 50 | 57 | ||
| 51 | private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) { | 58 | private void indexFieldTypeDescriptor(FieldDefEntry field, TypeDescriptor typeDescriptor) { |
| @@ -53,7 +60,7 @@ public class ReferenceIndex implements JarIndexer { | |||
| 53 | ClassEntry referencedClass = typeDescriptor.getTypeEntry(); | 60 | ClassEntry referencedClass = typeDescriptor.getTypeEntry(); |
| 54 | fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field)); | 61 | fieldTypeReferences.put(referencedClass, new EntryReference<>(referencedClass, referencedClass.getName(), field)); |
| 55 | } else if (typeDescriptor.isArray()) { | 62 | } else if (typeDescriptor.isArray()) { |
| 56 | indexFieldTypeDescriptor(field, typeDescriptor.getArrayType()); | 63 | indexFieldTypeDescriptor(field, typeDescriptor.getArrayType()); |
| 57 | } | 64 | } |
| 58 | } | 65 | } |
| 59 | 66 | ||
| @@ -99,18 +106,22 @@ public class ReferenceIndex implements JarIndexer { | |||
| 99 | private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) { | 106 | private <K extends Entry<?>, V extends Entry<?>> Multimap<K, V> remapReferences(JarIndex index, Multimap<K, V> multimap) { |
| 100 | final int keySetSize = multimap.keySet().size(); | 107 | final int keySetSize = multimap.keySet().size(); |
| 101 | Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize); | 108 | Multimap<K, V> resolved = HashMultimap.create(multimap.keySet().size(), keySetSize == 0 ? 0 : multimap.size() / keySetSize); |
| 109 | |||
| 102 | for (Map.Entry<K, V> entry : multimap.entries()) { | 110 | for (Map.Entry<K, V> entry : multimap.entries()) { |
| 103 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); | 111 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); |
| 104 | } | 112 | } |
| 113 | |||
| 105 | return resolved; | 114 | return resolved; |
| 106 | } | 115 | } |
| 107 | 116 | ||
| 108 | private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) { | 117 | private <E extends Entry<?>, C extends Entry<?>> Multimap<E, EntryReference<E, C>> remapReferencesTo(JarIndex index, Multimap<E, EntryReference<E, C>> multimap) { |
| 109 | final int keySetSize = multimap.keySet().size(); | 118 | final int keySetSize = multimap.keySet().size(); |
| 110 | Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize); | 119 | Multimap<E, EntryReference<E, C>> resolved = HashMultimap.create(keySetSize, keySetSize == 0 ? 0 : multimap.size() / keySetSize); |
| 120 | |||
| 111 | for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { | 121 | for (Map.Entry<E, EntryReference<E, C>> entry : multimap.entries()) { |
| 112 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); | 122 | resolved.put(remap(index, entry.getKey()), remap(index, entry.getValue())); |
| 113 | } | 123 | } |
| 124 | |||
| 114 | return resolved; | 125 | return resolved; |
| 115 | } | 126 | } |
| 116 | 127 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java index 358828f0..e2cb6b12 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java +++ b/enigma/src/main/java/cuchaz/enigma/api/service/EnigmaServiceType.java | |||
| @@ -18,7 +18,9 @@ public final class EnigmaServiceType<T extends EnigmaService> { | |||
| 18 | 18 | ||
| 19 | @Override | 19 | @Override |
| 20 | public boolean equals(Object obj) { | 20 | public boolean equals(Object obj) { |
| 21 | if (obj == this) return true; | 21 | if (obj == this) { |
| 22 | return true; | ||
| 23 | } | ||
| 22 | 24 | ||
| 23 | if (obj instanceof EnigmaServiceType) { | 25 | if (obj instanceof EnigmaServiceType) { |
| 24 | return ((EnigmaServiceType) obj).key.equals(key); | 26 | return ((EnigmaServiceType) obj).key.equals(key); |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java index 5417531c..3ed6d338 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java +++ b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | package cuchaz.enigma.api.service; | 1 | package cuchaz.enigma.api.service; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.index.JarIndex; | 3 | import java.util.Set; |
| 4 | import cuchaz.enigma.classprovider.ClassProvider; | 4 | |
| 5 | import org.objectweb.asm.ClassVisitor; | 5 | import org.objectweb.asm.ClassVisitor; |
| 6 | 6 | ||
| 7 | import java.util.Set; | 7 | import cuchaz.enigma.analysis.index.JarIndex; |
| 8 | import cuchaz.enigma.classprovider.ClassProvider; | ||
| 8 | 9 | ||
| 9 | public interface JarIndexerService extends EnigmaService { | 10 | public interface JarIndexerService extends EnigmaService { |
| 10 | EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer"); | 11 | EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer"); |
| @@ -12,7 +13,7 @@ public interface JarIndexerService extends EnigmaService { | |||
| 12 | void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex); | 13 | void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex); |
| 13 | 14 | ||
| 14 | static JarIndexerService fromVisitor(ClassVisitor visitor) { | 15 | static JarIndexerService fromVisitor(ClassVisitor visitor) { |
| 15 | return (scope, classProvider, jarIndex) -> { | 16 | return (scope, classProvider, jarIndex) -> { |
| 16 | for (String className : scope) { | 17 | for (String className : scope) { |
| 17 | classProvider.get(className).accept(visitor); | 18 | classProvider.get(className).accept(visitor); |
| 18 | } | 19 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java index 4c357db1..4c40868e 100644 --- a/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java +++ b/enigma/src/main/java/cuchaz/enigma/api/service/NameProposalService.java | |||
| @@ -1,10 +1,10 @@ | |||
| 1 | package cuchaz.enigma.api.service; | 1 | package cuchaz.enigma.api.service; |
| 2 | 2 | ||
| 3 | import java.util.Optional; | ||
| 4 | |||
| 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 5 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 4 | import cuchaz.enigma.translation.representation.entry.Entry; | 6 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 5 | 7 | ||
| 6 | import java.util.Optional; | ||
| 7 | |||
| 8 | public interface NameProposalService extends EnigmaService { | 8 | public interface NameProposalService extends EnigmaService { |
| 9 | EnigmaServiceType<NameProposalService> TYPE = EnigmaServiceType.create("name_proposal"); | 9 | EnigmaServiceType<NameProposalService> TYPE = EnigmaServiceType.create("name_proposal"); |
| 10 | 10 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java index 341cfce4..891fe9d1 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/AsmObjectTranslator.java | |||
| @@ -1,32 +1,34 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.Handle; | ||
| 4 | import org.objectweb.asm.Opcodes; | ||
| 5 | import org.objectweb.asm.Type; | ||
| 6 | |||
| 3 | import cuchaz.enigma.translation.Translator; | 7 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 8 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 5 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 9 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 6 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 10 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 7 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 11 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 8 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 12 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 9 | import org.objectweb.asm.Handle; | ||
| 10 | import org.objectweb.asm.Opcodes; | ||
| 11 | import org.objectweb.asm.Type; | ||
| 12 | 13 | ||
| 13 | public class AsmObjectTranslator { | 14 | public class AsmObjectTranslator { |
| 14 | public static Type translateType(Translator translator, Type type) { | 15 | public static Type translateType(Translator translator, Type type) { |
| 15 | String descString = type.getDescriptor(); | 16 | String descString = type.getDescriptor(); |
| 16 | switch (type.getSort()) { | 17 | switch (type.getSort()) { |
| 17 | case Type.OBJECT: { | 18 | case Type.OBJECT: { |
| 18 | ClassEntry classEntry = new ClassEntry(type.getInternalName()); | 19 | ClassEntry classEntry = new ClassEntry(type.getInternalName()); |
| 19 | return Type.getObjectType(translator.translate(classEntry).getFullName()); | 20 | return Type.getObjectType(translator.translate(classEntry).getFullName()); |
| 20 | } | 21 | } |
| 21 | case Type.ARRAY: { | 22 | case Type.ARRAY: { |
| 22 | TypeDescriptor descriptor = new TypeDescriptor(descString); | 23 | TypeDescriptor descriptor = new TypeDescriptor(descString); |
| 23 | return Type.getType(translator.translate(descriptor).toString()); | 24 | return Type.getType(translator.translate(descriptor).toString()); |
| 24 | } | 25 | } |
| 25 | case Type.METHOD: { | 26 | case Type.METHOD: { |
| 26 | MethodDescriptor descriptor = new MethodDescriptor(descString); | 27 | MethodDescriptor descriptor = new MethodDescriptor(descString); |
| 27 | return Type.getMethodType(translator.translate(descriptor).toString()); | 28 | return Type.getMethodType(translator.translate(descriptor).toString()); |
| 28 | } | ||
| 29 | } | 29 | } |
| 30 | } | ||
| 31 | |||
| 30 | return type; | 32 | return type; |
| 31 | } | 33 | } |
| 32 | 34 | ||
| @@ -55,6 +57,7 @@ public class AsmObjectTranslator { | |||
| 55 | } else if (value instanceof Handle) { | 57 | } else if (value instanceof Handle) { |
| 56 | return translateHandle(translator, (Handle) value); | 58 | return translateHandle(translator, (Handle) value); |
| 57 | } | 59 | } |
| 60 | |||
| 58 | return value; | 61 | return value; |
| 59 | } | 62 | } |
| 60 | } | 63 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java index cfd8fbee..dc399e53 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/LocalVariableFixVisitor.java | |||
| @@ -1,18 +1,19 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import java.util.HashMap; | ||
| 4 | import java.util.List; | ||
| 5 | import java.util.Map; | ||
| 6 | |||
| 3 | import com.google.common.base.CharMatcher; | 7 | import com.google.common.base.CharMatcher; |
| 4 | import cuchaz.enigma.translation.LocalNameGenerator; | ||
| 5 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 6 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | ||
| 7 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 8 | import org.objectweb.asm.ClassVisitor; | 8 | import org.objectweb.asm.ClassVisitor; |
| 9 | import org.objectweb.asm.Label; | 9 | import org.objectweb.asm.Label; |
| 10 | import org.objectweb.asm.MethodVisitor; | 10 | import org.objectweb.asm.MethodVisitor; |
| 11 | import org.objectweb.asm.Opcodes; | 11 | import org.objectweb.asm.Opcodes; |
| 12 | 12 | ||
| 13 | import java.util.HashMap; | 13 | import cuchaz.enigma.translation.LocalNameGenerator; |
| 14 | import java.util.List; | 14 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 15 | import java.util.Map; | 15 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 16 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 16 | 17 | ||
| 17 | public class LocalVariableFixVisitor extends ClassVisitor { | 18 | public class LocalVariableFixVisitor extends ClassVisitor { |
| 18 | private ClassDefEntry ownerEntry; | 19 | private ClassDefEntry ownerEntry; |
| @@ -46,6 +47,7 @@ public class LocalVariableFixVisitor extends ClassVisitor { | |||
| 46 | 47 | ||
| 47 | int lvIndex = methodEntry.getAccess().isStatic() ? 0 : 1; | 48 | int lvIndex = methodEntry.getAccess().isStatic() ? 0 : 1; |
| 48 | List<TypeDescriptor> parameters = methodEntry.getDesc().getArgumentDescs(); | 49 | List<TypeDescriptor> parameters = methodEntry.getDesc().getArgumentDescs(); |
| 50 | |||
| 49 | for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) { | 51 | for (int parameterIndex = 0; parameterIndex < parameters.size(); parameterIndex++) { |
| 50 | TypeDescriptor param = parameters.get(parameterIndex); | 52 | TypeDescriptor param = parameters.get(parameterIndex); |
| 51 | parameterIndices.put(lvIndex, parameterIndex); | 53 | parameterIndices.put(lvIndex, parameterIndex); |
| @@ -81,6 +83,7 @@ public class LocalVariableFixVisitor extends ClassVisitor { | |||
| 81 | public void visitEnd() { | 83 | public void visitEnd() { |
| 82 | if (!hasParameterTable) { | 84 | if (!hasParameterTable) { |
| 83 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); | 85 | List<TypeDescriptor> arguments = methodEntry.getDesc().getArgumentDescs(); |
| 86 | |||
| 84 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { | 87 | for (int argumentIndex = 0; argumentIndex < arguments.size(); argumentIndex++) { |
| 85 | super.visitParameter(fixParameterName(argumentIndex, null), fixParameterAccess(argumentIndex, 0)); | 88 | super.visitParameter(fixParameterName(argumentIndex, null), fixParameterAccess(argumentIndex, 0)); |
| 86 | } | 89 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java index 2b750eac..51b21a67 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/SourceFixVisitor.java | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.ClassVisitor; | ||
| 4 | import org.objectweb.asm.MethodVisitor; | ||
| 5 | import org.objectweb.asm.Opcodes; | ||
| 6 | |||
| 3 | import cuchaz.enigma.analysis.index.BridgeMethodIndex; | 7 | import cuchaz.enigma.analysis.index.BridgeMethodIndex; |
| 4 | import cuchaz.enigma.analysis.index.JarIndex; | 8 | import cuchaz.enigma.analysis.index.JarIndex; |
| 5 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | 9 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 6 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 10 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 7 | import org.objectweb.asm.ClassVisitor; | ||
| 8 | import org.objectweb.asm.MethodVisitor; | ||
| 9 | import org.objectweb.asm.Opcodes; | ||
| 10 | 11 | ||
| 11 | public class SourceFixVisitor extends ClassVisitor { | 12 | public class SourceFixVisitor extends ClassVisitor { |
| 12 | private final JarIndex index; | 13 | private final JarIndex index; |
| @@ -28,6 +29,7 @@ public class SourceFixVisitor extends ClassVisitor { | |||
| 28 | MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature); | 29 | MethodDefEntry methodEntry = MethodDefEntry.parse(ownerEntry, access, name, descriptor, signature); |
| 29 | 30 | ||
| 30 | BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex(); | 31 | BridgeMethodIndex bridgeIndex = index.getBridgeMethodIndex(); |
| 32 | |||
| 31 | if (bridgeIndex.isBridgeMethod(methodEntry)) { | 33 | if (bridgeIndex.isBridgeMethod(methodEntry)) { |
| 32 | access |= Opcodes.ACC_BRIDGE; | 34 | access |= Opcodes.ACC_BRIDGE; |
| 33 | } else if (bridgeIndex.isSpecializedMethod(methodEntry)) { | 35 | } else if (bridgeIndex.isSpecializedMethod(methodEntry)) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java index cb843ad4..d105e4c6 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationAnnotationVisitor.java | |||
| @@ -1,10 +1,11 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.AnnotationVisitor; | ||
| 4 | |||
| 3 | import cuchaz.enigma.translation.Translator; | 5 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 6 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 5 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 7 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 6 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 8 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 7 | import org.objectweb.asm.AnnotationVisitor; | ||
| 8 | 9 | ||
| 9 | public class TranslationAnnotationVisitor extends AnnotationVisitor { | 10 | public class TranslationAnnotationVisitor extends AnnotationVisitor { |
| 10 | private final Translator translator; | 11 | private final Translator translator; |
| @@ -29,6 +30,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor { | |||
| 29 | @Override | 30 | @Override |
| 30 | public AnnotationVisitor visitAnnotation(String name, String desc) { | 31 | public AnnotationVisitor visitAnnotation(String name, String desc) { |
| 31 | TypeDescriptor type = new TypeDescriptor(desc); | 32 | TypeDescriptor type = new TypeDescriptor(desc); |
| 33 | |||
| 32 | if (name != null) { | 34 | if (name != null) { |
| 33 | FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); | 35 | FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); |
| 34 | return super.visitAnnotation(annotationField.getName(), annotationField.getDesc().toString()); | 36 | return super.visitAnnotation(annotationField.getName(), annotationField.getDesc().toString()); |
| @@ -41,6 +43,7 @@ public class TranslationAnnotationVisitor extends AnnotationVisitor { | |||
| 41 | public void visitEnum(String name, String desc, String value) { | 43 | public void visitEnum(String name, String desc, String value) { |
| 42 | TypeDescriptor type = new TypeDescriptor(desc); | 44 | TypeDescriptor type = new TypeDescriptor(desc); |
| 43 | FieldEntry enumField = translator.translate(new FieldEntry(type.getTypeEntry(), value, type)); | 45 | FieldEntry enumField = translator.translate(new FieldEntry(type.getTypeEntry(), value, type)); |
| 46 | |||
| 44 | if (name != null) { | 47 | if (name != null) { |
| 45 | FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); | 48 | FieldEntry annotationField = translator.translate(new FieldEntry(annotationEntry, name, type)); |
| 46 | super.visitEnum(annotationField.getName(), annotationField.getDesc().toString(), enumField.getName()); | 49 | super.visitEnum(annotationField.getName(), annotationField.getDesc().toString(), enumField.getName()); |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java index 0b2ca9ae..66c8490b 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationClassVisitor.java | |||
| @@ -1,23 +1,33 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.bytecode.translators; | 12 | package cuchaz.enigma.bytecode.translators; |
| 13 | 13 | ||
| 14 | import java.util.Arrays; | ||
| 15 | |||
| 16 | import org.objectweb.asm.AnnotationVisitor; | ||
| 17 | import org.objectweb.asm.ClassVisitor; | ||
| 18 | import org.objectweb.asm.FieldVisitor; | ||
| 19 | import org.objectweb.asm.MethodVisitor; | ||
| 20 | import org.objectweb.asm.RecordComponentVisitor; | ||
| 21 | import org.objectweb.asm.TypePath; | ||
| 22 | |||
| 14 | import cuchaz.enigma.translation.Translator; | 23 | import cuchaz.enigma.translation.Translator; |
| 15 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 24 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 16 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 25 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 17 | import cuchaz.enigma.translation.representation.entry.*; | 26 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 18 | import org.objectweb.asm.*; | 27 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | 28 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | |
| 20 | import java.util.Arrays; | 29 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 30 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 21 | 31 | ||
| 22 | public class TranslationClassVisitor extends ClassVisitor { | 32 | public class TranslationClassVisitor extends ClassVisitor { |
| 23 | private final Translator translator; | 33 | private final Translator translator; |
| @@ -53,9 +63,11 @@ public class TranslationClassVisitor extends ClassVisitor { | |||
| 53 | MethodDefEntry entry = MethodDefEntry.parse(obfClassEntry, access, name, desc, signature); | 63 | MethodDefEntry entry = MethodDefEntry.parse(obfClassEntry, access, name, desc, signature); |
| 54 | MethodDefEntry translatedEntry = translator.translate(entry); | 64 | MethodDefEntry translatedEntry = translator.translate(entry); |
| 55 | String[] translatedExceptions = new String[exceptions.length]; | 65 | String[] translatedExceptions = new String[exceptions.length]; |
| 66 | |||
| 56 | for (int i = 0; i < exceptions.length; i++) { | 67 | for (int i = 0; i < exceptions.length; i++) { |
| 57 | translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName(); | 68 | translatedExceptions[i] = translator.translate(new ClassEntry(exceptions[i])).getFullName(); |
| 58 | } | 69 | } |
| 70 | |||
| 59 | MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions); | 71 | MethodVisitor mv = super.visitMethod(translatedEntry.getAccess().getFlags(), translatedEntry.getName(), translatedEntry.getDesc().toString(), translatedEntry.getSignature().toString(), translatedExceptions); |
| 60 | return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv); | 72 | return new TranslationMethodVisitor(translator, obfClassEntry, entry, api, mv); |
| 61 | } | 73 | } |
| @@ -65,6 +77,7 @@ public class TranslationClassVisitor extends ClassVisitor { | |||
| 65 | ClassDefEntry classEntry = ClassDefEntry.parse(access, name, obfClassEntry.getSignature().toString(), null, new String[0]); | 77 | ClassDefEntry classEntry = ClassDefEntry.parse(access, name, obfClassEntry.getSignature().toString(), null, new String[0]); |
| 66 | ClassDefEntry translatedEntry = translator.translate(classEntry); | 78 | ClassDefEntry translatedEntry = translator.translate(classEntry); |
| 67 | ClassEntry translatedOuterClass = translatedEntry.getOuterClass(); | 79 | ClassEntry translatedOuterClass = translatedEntry.getOuterClass(); |
| 80 | |||
| 68 | if (translatedOuterClass == null) { | 81 | if (translatedOuterClass == null) { |
| 69 | throw new IllegalStateException("Translated inner class did not have outer class"); | 82 | throw new IllegalStateException("Translated inner class did not have outer class"); |
| 70 | } | 83 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java index 28fc199c..d026f159 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationFieldVisitor.java | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.Translator; | ||
| 4 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 5 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 6 | import org.objectweb.asm.AnnotationVisitor; | 3 | import org.objectweb.asm.AnnotationVisitor; |
| 7 | import org.objectweb.asm.FieldVisitor; | 4 | import org.objectweb.asm.FieldVisitor; |
| 8 | import org.objectweb.asm.TypePath; | 5 | import org.objectweb.asm.TypePath; |
| 9 | 6 | ||
| 7 | import cuchaz.enigma.translation.Translator; | ||
| 8 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 9 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 10 | |||
| 10 | public class TranslationFieldVisitor extends FieldVisitor { | 11 | public class TranslationFieldVisitor extends FieldVisitor { |
| 11 | private final FieldDefEntry fieldEntry; | 12 | private final FieldDefEntry fieldEntry; |
| 12 | private final Translator translator; | 13 | private final Translator translator; |
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java index a82df1b0..932c1235 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationMethodVisitor.java | |||
| @@ -1,11 +1,21 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.AnnotationVisitor; | ||
| 4 | import org.objectweb.asm.Handle; | ||
| 5 | import org.objectweb.asm.Label; | ||
| 6 | import org.objectweb.asm.MethodVisitor; | ||
| 7 | import org.objectweb.asm.TypePath; | ||
| 8 | |||
| 3 | import cuchaz.enigma.translation.Translator; | 9 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 10 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 5 | import cuchaz.enigma.translation.representation.Signature; | 11 | import cuchaz.enigma.translation.representation.Signature; |
| 6 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 12 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 7 | import cuchaz.enigma.translation.representation.entry.*; | 13 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 8 | import org.objectweb.asm.*; | 14 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 15 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 17 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 9 | 19 | ||
| 10 | public class TranslationMethodVisitor extends MethodVisitor { | 20 | public class TranslationMethodVisitor extends MethodVisitor { |
| 11 | private final MethodDefEntry methodEntry; | 21 | private final MethodDefEntry methodEntry; |
| @@ -55,13 +65,16 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 55 | if (array == null) { | 65 | if (array == null) { |
| 56 | return null; | 66 | return null; |
| 57 | } | 67 | } |
| 68 | |||
| 58 | for (int i = 0; i < count; i++) { | 69 | for (int i = 0; i < count; i++) { |
| 59 | Object object = array[i]; | 70 | Object object = array[i]; |
| 71 | |||
| 60 | if (object instanceof String) { | 72 | if (object instanceof String) { |
| 61 | String type = (String) object; | 73 | String type = (String) object; |
| 62 | array[i] = translator.translate(new ClassEntry(type)).getFullName(); | 74 | array[i] = translator.translate(new ClassEntry(type)).getFullName(); |
| 63 | } | 75 | } |
| 64 | } | 76 | } |
| 77 | |||
| 65 | return array; | 78 | return array; |
| 66 | } | 79 | } |
| 67 | 80 | ||
| @@ -96,9 +109,11 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 96 | public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { | 109 | public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { |
| 97 | MethodDescriptor translatedMethodDesc = translator.translate(new MethodDescriptor(desc)); | 110 | MethodDescriptor translatedMethodDesc = translator.translate(new MethodDescriptor(desc)); |
| 98 | Object[] translatedBsmArgs = new Object[bsmArgs.length]; | 111 | Object[] translatedBsmArgs = new Object[bsmArgs.length]; |
| 112 | |||
| 99 | for (int i = 0; i < bsmArgs.length; i++) { | 113 | for (int i = 0; i < bsmArgs.length; i++) { |
| 100 | translatedBsmArgs[i] = AsmObjectTranslator.translateValue(translator, bsmArgs[i]); | 114 | translatedBsmArgs[i] = AsmObjectTranslator.translateValue(translator, bsmArgs[i]); |
| 101 | } | 115 | } |
| 116 | |||
| 102 | super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), AsmObjectTranslator.translateHandle(translator, bsm), translatedBsmArgs); | 117 | super.visitInvokeDynamicInsn(name, translatedMethodDesc.toString(), AsmObjectTranslator.translateHandle(translator, bsm), translatedBsmArgs); |
| 103 | } | 118 | } |
| 104 | 119 | ||
| @@ -132,7 +147,7 @@ public class TranslationMethodVisitor extends MethodVisitor { | |||
| 132 | } | 147 | } |
| 133 | 148 | ||
| 134 | private String translateVariableName(int index, String name) { | 149 | private String translateVariableName(int index, String name) { |
| 135 | LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true,null); | 150 | LocalVariableEntry entry = new LocalVariableEntry(methodEntry, index, "", true, null); |
| 136 | LocalVariableEntry translatedEntry = translator.translate(entry); | 151 | LocalVariableEntry translatedEntry = translator.translate(entry); |
| 137 | String translatedName = translatedEntry.getName(); | 152 | String translatedName = translatedEntry.getName(); |
| 138 | 153 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java index 06fd22bb..f7de0f88 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationRecordComponentVisitor.java | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | package cuchaz.enigma.bytecode.translators; | 1 | package cuchaz.enigma.bytecode.translators; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.Translator; | ||
| 4 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 5 | import org.objectweb.asm.AnnotationVisitor; | 3 | import org.objectweb.asm.AnnotationVisitor; |
| 6 | import org.objectweb.asm.RecordComponentVisitor; | 4 | import org.objectweb.asm.RecordComponentVisitor; |
| 7 | import org.objectweb.asm.TypePath; | 5 | import org.objectweb.asm.TypePath; |
| 8 | 6 | ||
| 7 | import cuchaz.enigma.translation.Translator; | ||
| 8 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 9 | |||
| 9 | public class TranslationRecordComponentVisitor extends RecordComponentVisitor { | 10 | public class TranslationRecordComponentVisitor extends RecordComponentVisitor { |
| 10 | private final Translator translator; | 11 | private final Translator translator; |
| 11 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java index 6cab22c7..49350f6b 100644 --- a/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/bytecode/translators/TranslationSignatureVisitor.java | |||
| @@ -29,17 +29,23 @@ public class TranslationSignatureVisitor extends SignatureVisitor { | |||
| 29 | @Override | 29 | @Override |
| 30 | public void visitInnerClassType(String name) { | 30 | public void visitInnerClassType(String name) { |
| 31 | String lastClass = classStack.pop(); | 31 | String lastClass = classStack.pop(); |
| 32 | if (!name.startsWith(lastClass+"$")){//todo see if there's a way to base this on whether there were type params or not | 32 | |
| 33 | name = lastClass+"$"+name; | 33 | if (!name.startsWith(lastClass + "$")) { |
| 34 | //todo see if there's a way to base this on whether there were type params or not | ||
| 35 | name = lastClass + "$" + name; | ||
| 34 | } | 36 | } |
| 37 | |||
| 35 | classStack.push(name); | 38 | classStack.push(name); |
| 36 | String translatedEntry = this.remapper.apply(name); | 39 | String translatedEntry = this.remapper.apply(name); |
| 37 | if (translatedEntry.contains("/")){ | 40 | |
| 38 | translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/")+1); | 41 | if (translatedEntry.contains("/")) { |
| 42 | translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("/") + 1); | ||
| 39 | } | 43 | } |
| 40 | if (translatedEntry.contains("$")){ | 44 | |
| 41 | translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$")+1); | 45 | if (translatedEntry.contains("$")) { |
| 46 | translatedEntry = translatedEntry.substring(translatedEntry.lastIndexOf("$") + 1); | ||
| 42 | } | 47 | } |
| 48 | |||
| 43 | this.sv.visitInnerClassType(translatedEntry); | 49 | this.sv.visitInnerClassType(translatedEntry); |
| 44 | } | 50 | } |
| 45 | 51 | ||
| @@ -120,8 +126,10 @@ public class TranslationSignatureVisitor extends SignatureVisitor { | |||
| 120 | @Override | 126 | @Override |
| 121 | public void visitEnd() { | 127 | public void visitEnd() { |
| 122 | this.sv.visitEnd(); | 128 | this.sv.visitEnd(); |
| 123 | if (!classStack.empty()) | 129 | |
| 130 | if (!classStack.empty()) { | ||
| 124 | classStack.pop(); | 131 | classStack.pop(); |
| 132 | } | ||
| 125 | } | 133 | } |
| 126 | 134 | ||
| 127 | @Override | 135 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java index 326197db..2a1643e9 100644 --- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java +++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandle.java | |||
| @@ -18,7 +18,6 @@ import cuchaz.enigma.utils.Result; | |||
| 18 | * @see ClassHandleProvider | 18 | * @see ClassHandleProvider |
| 19 | */ | 19 | */ |
| 20 | public interface ClassHandle extends AutoCloseable { | 20 | public interface ClassHandle extends AutoCloseable { |
| 21 | |||
| 22 | /** | 21 | /** |
| 23 | * Gets the reference to this class. This is always obfuscated, for example | 22 | * Gets the reference to this class. This is always obfuscated, for example |
| 24 | * {@code net/minecraft/class_1000}. | 23 | * {@code net/minecraft/class_1000}. |
| @@ -104,5 +103,4 @@ public interface ClassHandle extends AutoCloseable { | |||
| 104 | */ | 103 | */ |
| 105 | @Override | 104 | @Override |
| 106 | void close(); | 105 | void close(); |
| 107 | |||
| 108 | } | 106 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java index 20f847ae..ce6b23f8 100644 --- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java +++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleError.java | |||
| @@ -6,7 +6,6 @@ import java.io.PrintStream; | |||
| 6 | import javax.annotation.Nullable; | 6 | import javax.annotation.Nullable; |
| 7 | 7 | ||
| 8 | public final class ClassHandleError { | 8 | public final class ClassHandleError { |
| 9 | |||
| 10 | public final Type type; | 9 | public final Type type; |
| 11 | public final Throwable cause; | 10 | public final Throwable cause; |
| 12 | 11 | ||
| @@ -17,7 +16,10 @@ public final class ClassHandleError { | |||
| 17 | 16 | ||
| 18 | @Nullable | 17 | @Nullable |
| 19 | public String getStackTrace() { | 18 | public String getStackTrace() { |
| 20 | if (cause == null) return null; | 19 | if (cause == null) { |
| 20 | return null; | ||
| 21 | } | ||
| 22 | |||
| 21 | ByteArrayOutputStream os = new ByteArrayOutputStream(); | 23 | ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| 22 | PrintStream ps = new PrintStream(os); | 24 | PrintStream ps = new PrintStream(os); |
| 23 | cause.printStackTrace(ps); | 25 | cause.printStackTrace(ps); |
| @@ -36,5 +38,4 @@ public final class ClassHandleError { | |||
| 36 | DECOMPILE, | 38 | DECOMPILE, |
| 37 | REMAP, | 39 | REMAP, |
| 38 | } | 40 | } |
| 39 | 41 | } | |
| 40 | } \ No newline at end of file | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java index 229d18a8..f18be672 100644 --- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java | |||
| @@ -1,6 +1,15 @@ | |||
| 1 | package cuchaz.enigma.classhandle; | 1 | package cuchaz.enigma.classhandle; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import static cuchaz.enigma.utils.Utils.withLock; |
| 4 | |||
| 5 | import java.util.ArrayList; | ||
| 6 | import java.util.Collections; | ||
| 7 | import java.util.HashMap; | ||
| 8 | import java.util.HashSet; | ||
| 9 | import java.util.List; | ||
| 10 | import java.util.Map; | ||
| 11 | import java.util.Objects; | ||
| 12 | import java.util.Set; | ||
| 4 | import java.util.concurrent.CompletableFuture; | 13 | import java.util.concurrent.CompletableFuture; |
| 5 | import java.util.concurrent.ExecutorService; | 14 | import java.util.concurrent.ExecutorService; |
| 6 | import java.util.concurrent.Executors; | 15 | import java.util.concurrent.Executors; |
| @@ -16,14 +25,16 @@ import cuchaz.enigma.classprovider.CachingClassProvider; | |||
| 16 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; | 25 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; |
| 17 | import cuchaz.enigma.events.ClassHandleListener; | 26 | import cuchaz.enigma.events.ClassHandleListener; |
| 18 | import cuchaz.enigma.events.ClassHandleListener.InvalidationType; | 27 | import cuchaz.enigma.events.ClassHandleListener.InvalidationType; |
| 19 | import cuchaz.enigma.source.*; | 28 | import cuchaz.enigma.source.DecompiledClassSource; |
| 29 | import cuchaz.enigma.source.Decompiler; | ||
| 30 | import cuchaz.enigma.source.DecompilerService; | ||
| 31 | import cuchaz.enigma.source.Source; | ||
| 32 | import cuchaz.enigma.source.SourceIndex; | ||
| 33 | import cuchaz.enigma.source.SourceSettings; | ||
| 20 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 34 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 21 | import cuchaz.enigma.utils.Result; | 35 | import cuchaz.enigma.utils.Result; |
| 22 | 36 | ||
| 23 | import static cuchaz.enigma.utils.Utils.withLock; | ||
| 24 | |||
| 25 | public final class ClassHandleProvider { | 37 | public final class ClassHandleProvider { |
| 26 | |||
| 27 | private final EnigmaProject project; | 38 | private final EnigmaProject project; |
| 28 | 39 | ||
| 29 | private final ExecutorService pool = Executors.newWorkStealingPool(); | 40 | private final ExecutorService pool = Executors.newWorkStealingPool(); |
| @@ -50,7 +61,9 @@ public final class ClassHandleProvider { | |||
| 50 | */ | 61 | */ |
| 51 | @Nullable | 62 | @Nullable |
| 52 | public ClassHandle openClass(ClassEntry entry) { | 63 | public ClassHandle openClass(ClassEntry entry) { |
| 53 | if (!project.getJarIndex().getEntryIndex().hasClass(entry)) return null; | 64 | if (!project.getJarIndex().getEntryIndex().hasClass(entry)) { |
| 65 | return null; | ||
| 66 | } | ||
| 54 | 67 | ||
| 55 | return withLock(lock.writeLock(), () -> { | 68 | return withLock(lock.writeLock(), () -> { |
| 56 | Entry e = handles.computeIfAbsent(entry, entry1 -> new Entry(this, entry1)); | 69 | Entry e = handles.computeIfAbsent(entry, entry1 -> new Entry(this, entry1)); |
| @@ -68,7 +81,9 @@ public final class ClassHandleProvider { | |||
| 68 | * @param ds the decompiler service to use | 81 | * @param ds the decompiler service to use |
| 69 | */ | 82 | */ |
| 70 | public void setDecompilerService(DecompilerService ds) { | 83 | public void setDecompilerService(DecompilerService ds) { |
| 71 | if (this.ds.equals(ds)) return; | 84 | if (this.ds.equals(ds)) { |
| 85 | return; | ||
| 86 | } | ||
| 72 | 87 | ||
| 73 | this.ds = ds; | 88 | this.ds = ds; |
| 74 | this.decompiler = createDecompiler(); | 89 | this.decompiler = createDecompiler(); |
| @@ -111,6 +126,7 @@ public final class ClassHandleProvider { | |||
| 111 | public void invalidateMapped(ClassEntry entry) { | 126 | public void invalidateMapped(ClassEntry entry) { |
| 112 | withLock(lock.readLock(), () -> { | 127 | withLock(lock.readLock(), () -> { |
| 113 | Entry e = handles.get(entry); | 128 | Entry e = handles.get(entry); |
| 129 | |||
| 114 | if (e != null) { | 130 | if (e != null) { |
| 115 | e.invalidateMapped(); | 131 | e.invalidateMapped(); |
| 116 | } | 132 | } |
| @@ -136,6 +152,7 @@ public final class ClassHandleProvider { | |||
| 136 | public void invalidateJavadoc(ClassEntry entry) { | 152 | public void invalidateJavadoc(ClassEntry entry) { |
| 137 | withLock(lock.readLock(), () -> { | 153 | withLock(lock.readLock(), () -> { |
| 138 | Entry e = handles.get(entry); | 154 | Entry e = handles.get(entry); |
| 155 | |||
| 139 | if (e != null) { | 156 | if (e != null) { |
| 140 | e.invalidateJavadoc(); | 157 | e.invalidateJavadoc(); |
| 141 | } | 158 | } |
| @@ -163,6 +180,7 @@ public final class ClassHandleProvider { | |||
| 163 | */ | 180 | */ |
| 164 | public void destroy() { | 181 | public void destroy() { |
| 165 | pool.shutdown(); | 182 | pool.shutdown(); |
| 183 | |||
| 166 | try { | 184 | try { |
| 167 | pool.awaitTermination(30, TimeUnit.SECONDS); | 185 | pool.awaitTermination(30, TimeUnit.SECONDS); |
| 168 | } catch (InterruptedException e) { | 186 | } catch (InterruptedException e) { |
| @@ -176,7 +194,6 @@ public final class ClassHandleProvider { | |||
| 176 | } | 194 | } |
| 177 | 195 | ||
| 178 | private static final class Entry { | 196 | private static final class Entry { |
| 179 | |||
| 180 | private final ClassHandleProvider p; | 197 | private final ClassHandleProvider p; |
| 181 | private final ClassEntry entry; | 198 | private final ClassEntry entry; |
| 182 | private ClassEntry deobfRef; | 199 | private ClassEntry deobfRef; |
| @@ -216,6 +233,7 @@ public final class ClassHandleProvider { | |||
| 216 | 233 | ||
| 217 | private void checkDeobfRefForUpdate() { | 234 | private void checkDeobfRefForUpdate() { |
| 218 | ClassEntry newDeobf = p.project.getMapper().deobfuscate(entry); | 235 | ClassEntry newDeobf = p.project.getMapper().deobfuscate(entry); |
| 236 | |||
| 219 | if (!Objects.equals(deobfRef, newDeobf)) { | 237 | if (!Objects.equals(deobfRef, newDeobf)) { |
| 220 | deobfRef = newDeobf; | 238 | deobfRef = newDeobf; |
| 221 | // copy the list so we don't call event listener code with the lock active | 239 | // copy the list so we don't call event listener code with the lock active |
| @@ -244,7 +262,9 @@ public final class ClassHandleProvider { | |||
| 244 | private CompletableFuture<Result<Source, ClassHandleError>> decompile() { | 262 | private CompletableFuture<Result<Source, ClassHandleError>> decompile() { |
| 245 | int v = decompileVersion.incrementAndGet(); | 263 | int v = decompileVersion.incrementAndGet(); |
| 246 | return CompletableFuture.supplyAsync(() -> { | 264 | return CompletableFuture.supplyAsync(() -> { |
| 247 | if (decompileVersion.get() != v) return null; | 265 | if (decompileVersion.get() != v) { |
| 266 | return null; | ||
| 267 | } | ||
| 248 | 268 | ||
| 249 | Result<Source, ClassHandleError> uncommentedSource = Result.ok(p.decompiler.getSource(entry.getFullName())); | 269 | Result<Source, ClassHandleError> uncommentedSource = Result.ok(p.decompiler.getSource(entry.getFullName())); |
| 250 | Entry.this.uncommentedSource = uncommentedSource; | 270 | Entry.this.uncommentedSource = uncommentedSource; |
| @@ -258,7 +278,10 @@ public final class ClassHandleProvider { | |||
| 258 | private CompletableFuture<Result<Source, ClassHandleError>> continueInsertJavadoc(CompletableFuture<Result<Source, ClassHandleError>> f) { | 278 | private CompletableFuture<Result<Source, ClassHandleError>> continueInsertJavadoc(CompletableFuture<Result<Source, ClassHandleError>> f) { |
| 259 | int v = javadocVersion.incrementAndGet(); | 279 | int v = javadocVersion.incrementAndGet(); |
| 260 | return f.thenApplyAsync(res -> { | 280 | return f.thenApplyAsync(res -> { |
| 261 | if (res == null || javadocVersion.get() != v) return null; | 281 | if (res == null || javadocVersion.get() != v) { |
| 282 | return null; | ||
| 283 | } | ||
| 284 | |||
| 262 | Result<Source, ClassHandleError> jdSource = res.map(s -> s.withJavadocs(p.project.getMapper())); | 285 | Result<Source, ClassHandleError> jdSource = res.map(s -> s.withJavadocs(p.project.getMapper())); |
| 263 | withLock(lock.readLock(), () -> new ArrayList<>(handles)).forEach(h -> h.onDocsChanged(jdSource)); | 286 | withLock(lock.readLock(), () -> new ArrayList<>(handles)).forEach(h -> h.onDocsChanged(jdSource)); |
| 264 | return jdSource; | 287 | return jdSource; |
| @@ -268,7 +291,10 @@ public final class ClassHandleProvider { | |||
| 268 | private CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> continueIndexSource(CompletableFuture<Result<Source, ClassHandleError>> f) { | 291 | private CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> continueIndexSource(CompletableFuture<Result<Source, ClassHandleError>> f) { |
| 269 | int v = indexVersion.incrementAndGet(); | 292 | int v = indexVersion.incrementAndGet(); |
| 270 | return f.thenApplyAsync(res -> { | 293 | return f.thenApplyAsync(res -> { |
| 271 | if (res == null || indexVersion.get() != v) return null; | 294 | if (res == null || indexVersion.get() != v) { |
| 295 | return null; | ||
| 296 | } | ||
| 297 | |||
| 272 | return res.andThen(jdSource -> { | 298 | return res.andThen(jdSource -> { |
| 273 | SourceIndex index = jdSource.index(); | 299 | SourceIndex index = jdSource.index(); |
| 274 | index.resolveReferences(p.project.getMapper().getObfResolver()); | 300 | index.resolveReferences(p.project.getMapper().getObfResolver()); |
| @@ -281,11 +307,20 @@ public final class ClassHandleProvider { | |||
| 281 | private void continueMapSource(CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> f) { | 307 | private void continueMapSource(CompletableFuture<Result<DecompiledClassSource, ClassHandleError>> f) { |
| 282 | int v = mappedVersion.incrementAndGet(); | 308 | int v = mappedVersion.incrementAndGet(); |
| 283 | f.thenApplyAsync(res -> { | 309 | f.thenApplyAsync(res -> { |
| 284 | if (res == null || mappedVersion.get() != v) return null; | 310 | if (res == null || mappedVersion.get() != v) { |
| 311 | return null; | ||
| 312 | } | ||
| 313 | |||
| 285 | return res.andThen(source -> Result.ok(source.remapSource(p.project, p.project.getMapper().getDeobfuscator()))); | 314 | return res.andThen(source -> Result.ok(source.remapSource(p.project, p.project.getMapper().getDeobfuscator()))); |
| 286 | }, p.pool).whenComplete((res, e) -> { | 315 | }, p.pool).whenComplete((res, e) -> { |
| 287 | if (e != null) res = Result.err(ClassHandleError.remap(e)); | 316 | if (e != null) { |
| 288 | if (res == null) return; | 317 | res = Result.err(ClassHandleError.remap(e)); |
| 318 | } | ||
| 319 | |||
| 320 | if (res == null) { | ||
| 321 | return; | ||
| 322 | } | ||
| 323 | |||
| 289 | Entry.this.source = res; | 324 | Entry.this.source = res; |
| 290 | Entry.this.waitingSources.forEach(s -> s.complete(source)); | 325 | Entry.this.waitingSources.forEach(s -> s.complete(source)); |
| 291 | Entry.this.waitingSources.clear(); | 326 | Entry.this.waitingSources.clear(); |
| @@ -297,6 +332,7 @@ public final class ClassHandleProvider { | |||
| 297 | classHandle.destroy(); | 332 | classHandle.destroy(); |
| 298 | withLock(lock.writeLock(), () -> { | 333 | withLock(lock.writeLock(), () -> { |
| 299 | handles.remove(classHandle); | 334 | handles.remove(classHandle); |
| 335 | |||
| 300 | if (handles.isEmpty()) { | 336 | if (handles.isEmpty()) { |
| 301 | p.deleteEntry(this); | 337 | p.deleteEntry(this); |
| 302 | } | 338 | } |
| @@ -332,7 +368,6 @@ public final class ClassHandleProvider { | |||
| 332 | } | 368 | } |
| 333 | 369 | ||
| 334 | private static final class ClassHandleImpl implements ClassHandle { | 370 | private static final class ClassHandleImpl implements ClassHandle { |
| 335 | |||
| 336 | private final Entry entry; | 371 | private final Entry entry; |
| 337 | 372 | ||
| 338 | private boolean valid = true; | 373 | private boolean valid = true; |
| @@ -425,18 +460,20 @@ public final class ClassHandleProvider { | |||
| 425 | 460 | ||
| 426 | @Override | 461 | @Override |
| 427 | public void close() { | 462 | public void close() { |
| 428 | if (valid) entry.closeHandle(this); | 463 | if (valid) { |
| 464 | entry.closeHandle(this); | ||
| 465 | } | ||
| 429 | } | 466 | } |
| 430 | 467 | ||
| 431 | private void checkValid() { | 468 | private void checkValid() { |
| 432 | if (!valid) throw new IllegalStateException("Class handle no longer valid"); | 469 | if (!valid) { |
| 470 | throw new IllegalStateException("Class handle no longer valid"); | ||
| 471 | } | ||
| 433 | } | 472 | } |
| 434 | 473 | ||
| 435 | public void destroy() { | 474 | public void destroy() { |
| 436 | listeners.forEach(l -> l.onDeleted(this)); | 475 | listeners.forEach(l -> l.onDeleted(this)); |
| 437 | valid = false; | 476 | valid = false; |
| 438 | } | 477 | } |
| 439 | |||
| 440 | } | 478 | } |
| 441 | |||
| 442 | } | 479 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java index 47f5eb86..eaba6df2 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java | |||
| @@ -1,36 +1,33 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import com.google.common.cache.Cache; | ||
| 4 | import com.google.common.cache.CacheBuilder; | ||
| 5 | import org.objectweb.asm.tree.ClassNode; | ||
| 6 | |||
| 7 | import javax.annotation.Nullable; | ||
| 8 | import java.util.Optional; | 3 | import java.util.Optional; |
| 9 | import java.util.concurrent.ExecutionException; | 4 | import java.util.concurrent.ExecutionException; |
| 10 | import java.util.concurrent.TimeUnit; | 5 | import java.util.concurrent.TimeUnit; |
| 11 | 6 | ||
| 7 | import javax.annotation.Nullable; | ||
| 8 | |||
| 9 | import com.google.common.cache.Cache; | ||
| 10 | import com.google.common.cache.CacheBuilder; | ||
| 11 | import org.objectweb.asm.tree.ClassNode; | ||
| 12 | |||
| 12 | /** | 13 | /** |
| 13 | * Wraps a ClassProvider to provide caching and synchronization. | 14 | * Wraps a ClassProvider to provide caching and synchronization. |
| 14 | */ | 15 | */ |
| 15 | public class CachingClassProvider implements ClassProvider { | 16 | public class CachingClassProvider implements ClassProvider { |
| 16 | private final ClassProvider classProvider; | 17 | private final ClassProvider classProvider; |
| 17 | private final Cache<String, Optional<ClassNode>> cache = CacheBuilder.newBuilder() | 18 | private final Cache<String, Optional<ClassNode>> cache = CacheBuilder.newBuilder().maximumSize(128).expireAfterAccess(1, TimeUnit.MINUTES).concurrencyLevel(1).build(); |
| 18 | .maximumSize(128) | ||
| 19 | .expireAfterAccess(1, TimeUnit.MINUTES) | ||
| 20 | .concurrencyLevel(1) | ||
| 21 | .build(); | ||
| 22 | 19 | ||
| 23 | public CachingClassProvider(ClassProvider classProvider) { | 20 | public CachingClassProvider(ClassProvider classProvider) { |
| 24 | this.classProvider = classProvider; | 21 | this.classProvider = classProvider; |
| 25 | } | 22 | } |
| 26 | 23 | ||
| 27 | @Override | 24 | @Override |
| 28 | @Nullable | 25 | @Nullable |
| 29 | public ClassNode get(String name) { | 26 | public ClassNode get(String name) { |
| 30 | try { | 27 | try { |
| 31 | return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null); | 28 | return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null); |
| 32 | } catch (ExecutionException e) { | 29 | } catch (ExecutionException e) { |
| 33 | throw new RuntimeException(e); | 30 | throw new RuntimeException(e); |
| 34 | } | 31 | } |
| 35 | } | 32 | } |
| 36 | } | 33 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java index 6e4a665a..6eec0f36 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java | |||
| @@ -1,17 +1,17 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.tree.ClassNode; | ||
| 4 | |||
| 5 | import javax.annotation.Nullable; | 3 | import javax.annotation.Nullable; |
| 6 | 4 | ||
| 5 | import org.objectweb.asm.tree.ClassNode; | ||
| 6 | |||
| 7 | public interface ClassProvider { | 7 | public interface ClassProvider { |
| 8 | /** | 8 | /** |
| 9 | * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result, | 9 | * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result, |
| 10 | * so it's important to not mutate it. | 10 | * so it's important to not mutate it. |
| 11 | * | 11 | * |
| 12 | * @param name the internal name of the class | 12 | * @param name the internal name of the class |
| 13 | * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found | 13 | * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found |
| 14 | */ | 14 | */ |
| 15 | @Nullable | 15 | @Nullable |
| 16 | ClassNode get(String name); | 16 | ClassNode get(String name); |
| 17 | } | 17 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java index e9472fa9..224093f8 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java | |||
| @@ -1,27 +1,30 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.ClassReader; | ||
| 4 | import org.objectweb.asm.tree.ClassNode; | ||
| 5 | |||
| 6 | import javax.annotation.Nullable; | ||
| 7 | import java.io.IOException; | 3 | import java.io.IOException; |
| 8 | import java.io.InputStream; | 4 | import java.io.InputStream; |
| 9 | 5 | ||
| 6 | import javax.annotation.Nullable; | ||
| 7 | |||
| 8 | import org.objectweb.asm.ClassReader; | ||
| 9 | import org.objectweb.asm.tree.ClassNode; | ||
| 10 | |||
| 10 | /** | 11 | /** |
| 11 | * Provides classes by loading them from the classpath. | 12 | * Provides classes by loading them from the classpath. |
| 12 | */ | 13 | */ |
| 13 | public class ClasspathClassProvider implements ClassProvider { | 14 | public class ClasspathClassProvider implements ClassProvider { |
| 14 | @Nullable @Override public ClassNode get(String name) { | 15 | @Nullable |
| 15 | try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) { | 16 | @Override |
| 16 | if (in == null) { | 17 | public ClassNode get(String name) { |
| 17 | return null; | 18 | try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) { |
| 18 | } | 19 | if (in == null) { |
| 20 | return null; | ||
| 21 | } | ||
| 19 | 22 | ||
| 20 | ClassNode node = new ClassNode(); | 23 | ClassNode node = new ClassNode(); |
| 21 | new ClassReader(in).accept(node, 0); | 24 | new ClassReader(in).accept(node, 0); |
| 22 | return node; | 25 | return node; |
| 23 | } catch (IOException e) { | 26 | } catch (IOException e) { |
| 24 | return null; | 27 | return null; |
| 25 | } | 28 | } |
| 26 | } | 29 | } |
| 27 | } | 30 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java index 865464cf..6856540f 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java | |||
| @@ -1,31 +1,31 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.tree.ClassNode; | ||
| 4 | |||
| 5 | import javax.annotation.Nullable; | 3 | import javax.annotation.Nullable; |
| 6 | 4 | ||
| 5 | import org.objectweb.asm.tree.ClassNode; | ||
| 6 | |||
| 7 | /** | 7 | /** |
| 8 | * Combines a list of {@link ClassProvider}s into one, calling each one in a row | 8 | * Combines a list of {@link ClassProvider}s into one, calling each one in a row |
| 9 | * until one can provide the class. | 9 | * until one can provide the class. |
| 10 | */ | 10 | */ |
| 11 | public class CombiningClassProvider implements ClassProvider { | 11 | public class CombiningClassProvider implements ClassProvider { |
| 12 | private final ClassProvider[] classProviders; | 12 | private final ClassProvider[] classProviders; |
| 13 | 13 | ||
| 14 | public CombiningClassProvider(ClassProvider... classProviders) { | 14 | public CombiningClassProvider(ClassProvider... classProviders) { |
| 15 | this.classProviders = classProviders; | 15 | this.classProviders = classProviders; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | @Override | 18 | @Override |
| 19 | @Nullable | 19 | @Nullable |
| 20 | public ClassNode get(String name) { | 20 | public ClassNode get(String name) { |
| 21 | for (ClassProvider cp : classProviders) { | 21 | for (ClassProvider cp : classProviders) { |
| 22 | ClassNode node = cp.get(name); | 22 | ClassNode node = cp.get(name); |
| 23 | 23 | ||
| 24 | if (node != null) { | 24 | if (node != null) { |
| 25 | return node; | 25 | return node; |
| 26 | } | 26 | } |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | return null; | 29 | return null; |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java index c614b0a8..900a0c8b 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java | |||
| @@ -1,10 +1,5 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import com.google.common.collect.ImmutableSet; | ||
| 4 | import cuchaz.enigma.utils.AsmUtil; | ||
| 5 | import org.objectweb.asm.tree.ClassNode; | ||
| 6 | |||
| 7 | import javax.annotation.Nullable; | ||
| 8 | import java.io.IOException; | 3 | import java.io.IOException; |
| 9 | import java.nio.file.FileSystem; | 4 | import java.nio.file.FileSystem; |
| 10 | import java.nio.file.FileSystems; | 5 | import java.nio.file.FileSystems; |
| @@ -12,53 +7,60 @@ import java.nio.file.Files; | |||
| 12 | import java.nio.file.Path; | 7 | import java.nio.file.Path; |
| 13 | import java.util.Set; | 8 | import java.util.Set; |
| 14 | 9 | ||
| 10 | import javax.annotation.Nullable; | ||
| 11 | |||
| 12 | import com.google.common.collect.ImmutableSet; | ||
| 13 | import org.objectweb.asm.tree.ClassNode; | ||
| 14 | |||
| 15 | import cuchaz.enigma.utils.AsmUtil; | ||
| 16 | |||
| 15 | /** | 17 | /** |
| 16 | * Provides classes by loading them from a JAR file. | 18 | * Provides classes by loading them from a JAR file. |
| 17 | */ | 19 | */ |
| 18 | public class JarClassProvider implements AutoCloseable, ClassProvider { | 20 | public class JarClassProvider implements AutoCloseable, ClassProvider { |
| 19 | private final FileSystem fileSystem; | 21 | private final FileSystem fileSystem; |
| 20 | private final Set<String> classNames; | 22 | private final Set<String> classNames; |
| 23 | |||
| 24 | public JarClassProvider(Path jarPath) throws IOException { | ||
| 25 | this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null); | ||
| 26 | this.classNames = collectClassNames(fileSystem); | ||
| 27 | } | ||
| 21 | 28 | ||
| 22 | public JarClassProvider(Path jarPath) throws IOException { | 29 | private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException { |
| 23 | this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null); | 30 | ImmutableSet.Builder<String> classNames = ImmutableSet.builder(); |
| 24 | this.classNames = collectClassNames(fileSystem); | ||
| 25 | } | ||
| 26 | 31 | ||
| 27 | private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException { | 32 | for (Path root : fileSystem.getRootDirectories()) { |
| 28 | ImmutableSet.Builder<String> classNames = ImmutableSet.builder(); | 33 | Files.walk(root).map(Path::toString).forEach(path -> { |
| 29 | for (Path root : fileSystem.getRootDirectories()) { | 34 | if (path.endsWith(".class")) { |
| 30 | Files.walk(root).map(Path::toString) | 35 | String name = path.substring(1, path.length() - ".class".length()); |
| 31 | .forEach(path -> { | 36 | classNames.add(name); |
| 32 | if (path.endsWith(".class")) { | 37 | } |
| 33 | String name = path.substring(1, path.length() - ".class".length()); | 38 | }); |
| 34 | classNames.add(name); | 39 | } |
| 35 | } | ||
| 36 | }); | ||
| 37 | } | ||
| 38 | 40 | ||
| 39 | return classNames.build(); | 41 | return classNames.build(); |
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | public Set<String> getClassNames() { | 44 | public Set<String> getClassNames() { |
| 43 | return classNames; | 45 | return classNames; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | @Nullable | 48 | @Nullable |
| 47 | @Override | 49 | @Override |
| 48 | public ClassNode get(String name) { | 50 | public ClassNode get(String name) { |
| 49 | if (!classNames.contains(name)) { | 51 | if (!classNames.contains(name)) { |
| 50 | return null; | 52 | return null; |
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | try { | 55 | try { |
| 54 | return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class"))); | 56 | return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class"))); |
| 55 | } catch (IOException e) { | 57 | } catch (IOException e) { |
| 56 | throw new RuntimeException(e); | 58 | throw new RuntimeException(e); |
| 57 | } | 59 | } |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | @Override | 62 | @Override |
| 61 | public void close() throws Exception { | 63 | public void close() throws Exception { |
| 62 | fileSystem.close(); | 64 | fileSystem.close(); |
| 63 | } | 65 | } |
| 64 | } | 66 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java index 36236a8d..604bf499 100644 --- a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java | |||
| @@ -1,10 +1,7 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | 1 | package cuchaz.enigma.classprovider; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.Enigma; | 3 | import javax.annotation.Nullable; |
| 4 | import cuchaz.enigma.analysis.index.JarIndex; | 4 | |
| 5 | import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor; | ||
| 6 | import cuchaz.enigma.bytecode.translators.SourceFixVisitor; | ||
| 7 | import cuchaz.enigma.classprovider.ClassProvider; | ||
| 8 | import org.objectweb.asm.ClassVisitor; | 5 | import org.objectweb.asm.ClassVisitor; |
| 9 | import org.objectweb.asm.Opcodes; | 6 | import org.objectweb.asm.Opcodes; |
| 10 | import org.objectweb.asm.tree.AbstractInsnNode; | 7 | import org.objectweb.asm.tree.AbstractInsnNode; |
| @@ -12,7 +9,10 @@ import org.objectweb.asm.tree.ClassNode; | |||
| 12 | import org.objectweb.asm.tree.MethodInsnNode; | 9 | import org.objectweb.asm.tree.MethodInsnNode; |
| 13 | import org.objectweb.asm.tree.MethodNode; | 10 | import org.objectweb.asm.tree.MethodNode; |
| 14 | 11 | ||
| 15 | import javax.annotation.Nullable; | 12 | import cuchaz.enigma.Enigma; |
| 13 | import cuchaz.enigma.analysis.index.JarIndex; | ||
| 14 | import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor; | ||
| 15 | import cuchaz.enigma.bytecode.translators.SourceFixVisitor; | ||
| 16 | 16 | ||
| 17 | /** | 17 | /** |
| 18 | * Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator, | 18 | * Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator, |
| @@ -26,59 +26,63 @@ import javax.annotation.Nullable; | |||
| 26 | * <li>Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier | 26 | * <li>Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier |
| 27 | * <li>"this" parameter which is incorrectly named | 27 | * <li>"this" parameter which is incorrectly named |
| 28 | * </ul> | 28 | * </ul> |
| 29 | * <p> | 29 | * |
| 30 | * These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes. | 30 | * <p>These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes. |
| 31 | */ | 31 | */ |
| 32 | public class ObfuscationFixClassProvider implements ClassProvider { | 32 | public class ObfuscationFixClassProvider implements ClassProvider { |
| 33 | private final ClassProvider classProvider; | 33 | private final ClassProvider classProvider; |
| 34 | private final JarIndex jarIndex; | 34 | private final JarIndex jarIndex; |
| 35 | |||
| 36 | public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) { | ||
| 37 | this.classProvider = classProvider; | ||
| 38 | this.jarIndex = jarIndex; | ||
| 39 | } | ||
| 40 | |||
| 41 | @Override | ||
| 42 | @Nullable | ||
| 43 | public ClassNode get(String name) { | ||
| 44 | ClassNode node = classProvider.get(name); | ||
| 45 | |||
| 46 | if (!jarIndex.isIndexed(name)) { | ||
| 47 | return node; | ||
| 48 | } | ||
| 35 | 49 | ||
| 36 | public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) { | 50 | ClassNode fixedNode = new ClassNode(); |
| 37 | this.classProvider = classProvider; | 51 | ClassVisitor visitor = fixedNode; |
| 38 | this.jarIndex = jarIndex; | 52 | visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor); |
| 39 | } | 53 | visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex); |
| 54 | node.accept(visitor); | ||
| 55 | removeRedundantClassCalls(fixedNode); | ||
| 40 | 56 | ||
| 41 | @Override | 57 | return fixedNode; |
| 42 | @Nullable | 58 | } |
| 43 | public ClassNode get(String name) { | ||
| 44 | ClassNode node = classProvider.get(name); | ||
| 45 | 59 | ||
| 46 | if (!jarIndex.isIndexed(name)) { | 60 | private void removeRedundantClassCalls(ClassNode node) { |
| 47 | return node; | 61 | // Removes .getClass() calls added by Proguard: |
| 48 | } | 62 | // DUP |
| 63 | // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class; | ||
| 64 | // POP | ||
| 65 | for (MethodNode methodNode : node.methods) { | ||
| 66 | AbstractInsnNode insnNode = methodNode.instructions.getFirst(); | ||
| 49 | 67 | ||
| 50 | ClassNode fixedNode = new ClassNode(); | 68 | while (insnNode != null) { |
| 51 | ClassVisitor visitor = fixedNode; | 69 | if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) { |
| 52 | visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor); | 70 | if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) { |
| 53 | visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex); | 71 | AbstractInsnNode previous = methodInsnNode.getPrevious(); |
| 54 | node.accept(visitor); | 72 | AbstractInsnNode next = methodInsnNode.getNext(); |
| 55 | removeRedundantClassCalls(fixedNode); | ||
| 56 | 73 | ||
| 57 | return fixedNode; | 74 | if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) { |
| 58 | } | 75 | //reset the iterator so it gets the new next instruction |
| 76 | insnNode = previous.getPrevious(); | ||
| 77 | methodNode.instructions.remove(previous); | ||
| 78 | methodNode.instructions.remove(methodInsnNode); | ||
| 79 | methodNode.instructions.remove(next); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 59 | 83 | ||
| 60 | private void removeRedundantClassCalls(ClassNode node) { | 84 | insnNode = insnNode.getNext(); |
| 61 | // Removes .getClass() calls added by Proguard: | 85 | } |
| 62 | // DUP | 86 | } |
| 63 | // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class; | 87 | } |
| 64 | // POP | ||
| 65 | for (MethodNode methodNode : node.methods) { | ||
| 66 | AbstractInsnNode insnNode = methodNode.instructions.getFirst(); | ||
| 67 | while (insnNode != null) { | ||
| 68 | if (insnNode instanceof MethodInsnNode methodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) { | ||
| 69 | if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) { | ||
| 70 | AbstractInsnNode previous = methodInsnNode.getPrevious(); | ||
| 71 | AbstractInsnNode next = methodInsnNode.getNext(); | ||
| 72 | if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) { | ||
| 73 | insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction | ||
| 74 | methodNode.instructions.remove(previous); | ||
| 75 | methodNode.instructions.remove(methodInsnNode); | ||
| 76 | methodNode.instructions.remove(next); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | insnNode = insnNode.getNext(); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | 88 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java index cb9cbc2e..fd078a2d 100644 --- a/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java +++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigContainer.java | |||
| @@ -8,7 +8,6 @@ import java.util.Deque; | |||
| 8 | import java.util.LinkedList; | 8 | import java.util.LinkedList; |
| 9 | 9 | ||
| 10 | public class ConfigContainer { | 10 | public class ConfigContainer { |
| 11 | |||
| 12 | private Path configPath; | 11 | private Path configPath; |
| 13 | private boolean existsOnDisk; | 12 | private boolean existsOnDisk; |
| 14 | 13 | ||
| @@ -19,7 +18,10 @@ public class ConfigContainer { | |||
| 19 | } | 18 | } |
| 20 | 19 | ||
| 21 | public void save() { | 20 | public void save() { |
| 22 | if (this.configPath == null) throw new IllegalStateException("File has no config path set!"); | 21 | if (this.configPath == null) { |
| 22 | throw new IllegalStateException("File has no config path set!"); | ||
| 23 | } | ||
| 24 | |||
| 23 | try { | 25 | try { |
| 24 | Files.createDirectories(this.configPath.getParent()); | 26 | Files.createDirectories(this.configPath.getParent()); |
| 25 | Files.write(this.configPath, this.serialize().getBytes(StandardCharsets.UTF_8)); | 27 | Files.write(this.configPath, this.serialize().getBytes(StandardCharsets.UTF_8)); |
| @@ -52,6 +54,7 @@ public class ConfigContainer { | |||
| 52 | 54 | ||
| 53 | public static ConfigContainer getOrCreate(Path path) { | 55 | public static ConfigContainer getOrCreate(Path path) { |
| 54 | ConfigContainer cc = null; | 56 | ConfigContainer cc = null; |
| 57 | |||
| 55 | try { | 58 | try { |
| 56 | if (Files.exists(path)) { | 59 | if (Files.exists(path)) { |
| 57 | String s = String.join("\n", Files.readAllLines(path)); | 60 | String s = String.join("\n", Files.readAllLines(path)); |
| @@ -93,5 +96,4 @@ public class ConfigContainer { | |||
| 93 | }); | 96 | }); |
| 94 | return cc; | 97 | return cc; |
| 95 | } | 98 | } |
| 96 | |||
| 97 | } | 99 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java index b3f3d0c7..6d9d304a 100644 --- a/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java +++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigPaths.java | |||
| @@ -6,7 +6,6 @@ import java.nio.file.Paths; | |||
| 6 | import cuchaz.enigma.utils.Os; | 6 | import cuchaz.enigma.utils.Os; |
| 7 | 7 | ||
| 8 | public class ConfigPaths { | 8 | public class ConfigPaths { |
| 9 | |||
| 10 | public static Path getConfigFilePath(String name) { | 9 | public static Path getConfigFilePath(String name) { |
| 11 | String fileName = Os.getOs() == Os.LINUX ? String.format("%src", name) : String.format("%s.ini", name); | 10 | String fileName = Os.getOs() == Os.LINUX ? String.format("%src", name) : String.format("%s.ini", name); |
| 12 | return getConfigPathRoot().resolve(fileName); | 11 | return getConfigPathRoot().resolve(fileName); |
| @@ -14,27 +13,30 @@ public class ConfigPaths { | |||
| 14 | 13 | ||
| 15 | public static Path getConfigPathRoot() { | 14 | public static Path getConfigPathRoot() { |
| 16 | switch (Os.getOs()) { | 15 | switch (Os.getOs()) { |
| 17 | case LINUX: | 16 | case LINUX: |
| 18 | String configHome = System.getenv("XDG_CONFIG_HOME"); | 17 | String configHome = System.getenv("XDG_CONFIG_HOME"); |
| 19 | if (configHome == null) { | 18 | |
| 20 | return getUserHomeUnix().resolve(".config"); | 19 | if (configHome == null) { |
| 21 | } | 20 | return getUserHomeUnix().resolve(".config"); |
| 22 | return Paths.get(configHome); | 21 | } |
| 23 | case MAC: | 22 | |
| 24 | return getUserHomeUnix().resolve("Library").resolve("Application Support"); | 23 | return Paths.get(configHome); |
| 25 | case WINDOWS: | 24 | case MAC: |
| 26 | return Paths.get(System.getenv("LOCALAPPDATA")); | 25 | return getUserHomeUnix().resolve("Library").resolve("Application Support"); |
| 27 | default: | 26 | case WINDOWS: |
| 28 | return Paths.get(System.getProperty("user.dir")); | 27 | return Paths.get(System.getenv("LOCALAPPDATA")); |
| 28 | default: | ||
| 29 | return Paths.get(System.getProperty("user.dir")); | ||
| 29 | } | 30 | } |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | private static Path getUserHomeUnix() { | 33 | private static Path getUserHomeUnix() { |
| 33 | String userHome = System.getenv("HOME"); | 34 | String userHome = System.getenv("HOME"); |
| 35 | |||
| 34 | if (userHome == null) { | 36 | if (userHome == null) { |
| 35 | userHome = System.getProperty("user.dir"); | 37 | userHome = System.getProperty("user.dir"); |
| 36 | } | 38 | } |
| 39 | |||
| 37 | return Paths.get(userHome); | 40 | return Paths.get(userHome); |
| 38 | } | 41 | } |
| 39 | |||
| 40 | } | 42 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java index 3e7bf6d4..fba7da3b 100644 --- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java +++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSection.java | |||
| @@ -1,10 +1,16 @@ | |||
| 1 | package cuchaz.enigma.config; | 1 | package cuchaz.enigma.config; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.Arrays; |
| 4 | import java.util.Collections; | ||
| 5 | import java.util.HashMap; | ||
| 6 | import java.util.Map; | ||
| 7 | import java.util.Objects; | ||
| 8 | import java.util.Optional; | ||
| 9 | import java.util.OptionalDouble; | ||
| 10 | import java.util.OptionalInt; | ||
| 4 | import java.util.function.Function; | 11 | import java.util.function.Function; |
| 5 | 12 | ||
| 6 | public class ConfigSection { | 13 | public class ConfigSection { |
| 7 | |||
| 8 | private final Map<String, String> values; | 14 | private final Map<String, String> values; |
| 9 | private final Map<String, ConfigSection> sections; | 15 | private final Map<String, ConfigSection> sections; |
| 10 | 16 | ||
| @@ -163,11 +169,16 @@ public class ConfigSection { | |||
| 163 | 169 | ||
| 164 | @Override | 170 | @Override |
| 165 | public boolean equals(Object o) { | 171 | public boolean equals(Object o) { |
| 166 | if (this == o) return true; | 172 | if (this == o) { |
| 167 | if (!(o instanceof ConfigSection)) return false; | 173 | return true; |
| 174 | } | ||
| 175 | |||
| 176 | if (!(o instanceof ConfigSection)) { | ||
| 177 | return false; | ||
| 178 | } | ||
| 179 | |||
| 168 | ConfigSection that = (ConfigSection) o; | 180 | ConfigSection that = (ConfigSection) o; |
| 169 | return values.equals(that.values) && | 181 | return values.equals(that.values) && sections.equals(that.sections); |
| 170 | sections.equals(that.sections); | ||
| 171 | } | 182 | } |
| 172 | 183 | ||
| 173 | @Override | 184 | @Override |
| @@ -179,5 +190,4 @@ public class ConfigSection { | |||
| 179 | public String toString() { | 190 | public String toString() { |
| 180 | return String.format("ConfigSection { values: %s, sections: %s }", values, sections); | 191 | return String.format("ConfigSection { values: %s, sections: %s }", values, sections); |
| 181 | } | 192 | } |
| 182 | |||
| 183 | } | 193 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java index dccb5858..a1e3e55c 100644 --- a/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java +++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigSerializer.java | |||
| @@ -1,13 +1,17 @@ | |||
| 1 | package cuchaz.enigma.config; | 1 | package cuchaz.enigma.config; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.ArrayList; |
| 4 | import java.util.Arrays; | ||
| 5 | import java.util.List; | ||
| 4 | import java.util.Map.Entry; | 6 | import java.util.Map.Entry; |
| 7 | import java.util.Optional; | ||
| 8 | import java.util.OptionalDouble; | ||
| 9 | import java.util.OptionalInt; | ||
| 5 | import java.util.function.Function; | 10 | import java.util.function.Function; |
| 6 | import java.util.regex.Pattern; | 11 | import java.util.regex.Pattern; |
| 7 | import java.util.stream.Collectors; | 12 | import java.util.stream.Collectors; |
| 8 | 13 | ||
| 9 | public final class ConfigSerializer { | 14 | public final class ConfigSerializer { |
| 10 | |||
| 11 | private static final Pattern FULL_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{6}"); | 15 | private static final Pattern FULL_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{6}"); |
| 12 | private static final Pattern MIN_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{3}"); | 16 | private static final Pattern MIN_RGB_COLOR = Pattern.compile("#[0-9A-Fa-f]{3}"); |
| 13 | 17 | ||
| @@ -19,6 +23,7 @@ public final class ConfigSerializer { | |||
| 19 | 23 | ||
| 20 | // join escaped newlines | 24 | // join escaped newlines |
| 21 | int len = lines.length; | 25 | int len = lines.length; |
| 26 | |||
| 22 | for (int i = len - 2; i >= 0; i--) { | 27 | for (int i = len - 2; i >= 0; i--) { |
| 23 | if (lines[i].endsWith("\\")) { | 28 | if (lines[i].endsWith("\\")) { |
| 24 | lines[i] = String.format("%s\n%s", lines[i], lines[i + 1]); | 29 | lines[i] = String.format("%s\n%s", lines[i], lines[i + 1]); |
| @@ -31,24 +36,30 @@ public final class ConfigSerializer { | |||
| 31 | String line = lines[i]; | 36 | String line = lines[i]; |
| 32 | 37 | ||
| 33 | // skip empty lines and comment lines | 38 | // skip empty lines and comment lines |
| 34 | if (line.trim().isEmpty() || line.trim().startsWith(";")) continue; | 39 | if (line.trim().isEmpty() || line.trim().startsWith(";")) { |
| 40 | continue; | ||
| 41 | } | ||
| 35 | 42 | ||
| 36 | int r; | 43 | int r; |
| 37 | boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH && | 44 | boolean fail = (r = parseSectionLine(line, 0, visitor)) == NO_MATCH && (r = parseKeyValue(line, 0, visitor)) == NO_MATCH; |
| 38 | (r = parseKeyValue(line, 0, visitor)) == NO_MATCH; | ||
| 39 | } | 45 | } |
| 40 | } | 46 | } |
| 41 | 47 | ||
| 42 | private static int parseSectionLine(String v, int idx, ConfigStructureVisitor visitor) { | 48 | private static int parseSectionLine(String v, int idx, ConfigStructureVisitor visitor) { |
| 43 | if (v.startsWith("[")) { | 49 | if (v.startsWith("[")) { |
| 44 | List<String> path = new ArrayList<>(); | 50 | List<String> path = new ArrayList<>(); |
| 51 | |||
| 45 | while (idx < v.length() && v.charAt(idx) == '[') { | 52 | while (idx < v.length() && v.charAt(idx) == '[') { |
| 46 | idx = parseSection(v, idx, path); | 53 | idx = parseSection(v, idx, path); |
| 47 | if (idx == UNEXPECTED_TOKEN) return UNEXPECTED_TOKEN; | 54 | |
| 55 | if (idx == UNEXPECTED_TOKEN) { | ||
| 56 | return UNEXPECTED_TOKEN; | ||
| 57 | } | ||
| 48 | } | 58 | } |
| 49 | 59 | ||
| 50 | if (!path.isEmpty()) { | 60 | if (!path.isEmpty()) { |
| 51 | visitor.jumpToRootSection(); | 61 | visitor.jumpToRootSection(); |
| 62 | |||
| 52 | for (String s : path) { | 63 | for (String s : path) { |
| 53 | visitor.visitSection(s); | 64 | visitor.visitSection(s); |
| 54 | } | 65 | } |
| @@ -63,10 +74,12 @@ public final class ConfigSerializer { | |||
| 63 | private static int parseSection(String v, int idx, List<String> path) { | 74 | private static int parseSection(String v, int idx, List<String> path) { |
| 64 | idx += 1; // skip leading [ | 75 | idx += 1; // skip leading [ |
| 65 | StringBuilder sb = new StringBuilder(); | 76 | StringBuilder sb = new StringBuilder(); |
| 77 | |||
| 66 | while (idx < v.length()) { | 78 | while (idx < v.length()) { |
| 67 | int nextCloseBracket = v.indexOf(']', idx); | 79 | int nextCloseBracket = v.indexOf(']', idx); |
| 68 | int nextEscape = v.indexOf('\\', idx); | 80 | int nextEscape = v.indexOf('\\', idx); |
| 69 | int next = optMin(nextCloseBracket, nextEscape); | 81 | int next = optMin(nextCloseBracket, nextEscape); |
| 82 | |||
| 70 | if (next == -1) { | 83 | if (next == -1) { |
| 71 | // unexpected | 84 | // unexpected |
| 72 | return UNEXPECTED_TOKEN; | 85 | return UNEXPECTED_TOKEN; |
| @@ -79,16 +92,19 @@ public final class ConfigSerializer { | |||
| 79 | idx = parseEscape(v, nextEscape, sb); | 92 | idx = parseEscape(v, nextEscape, sb); |
| 80 | } | 93 | } |
| 81 | } | 94 | } |
| 95 | |||
| 82 | return idx; | 96 | return idx; |
| 83 | } | 97 | } |
| 84 | 98 | ||
| 85 | private static int parseKeyValue(String v, int idx, ConfigStructureVisitor visitor) { | 99 | private static int parseKeyValue(String v, int idx, ConfigStructureVisitor visitor) { |
| 86 | StringBuilder sb = new StringBuilder(); | 100 | StringBuilder sb = new StringBuilder(); |
| 87 | String k = null; | 101 | String k = null; |
| 102 | |||
| 88 | while (idx < v.length()) { | 103 | while (idx < v.length()) { |
| 89 | int nextEq = v.indexOf('=', idx); | 104 | int nextEq = v.indexOf('=', idx); |
| 90 | int nextEscape = v.indexOf('\\', idx); | 105 | int nextEscape = v.indexOf('\\', idx); |
| 91 | int next = optMin(nextEq, nextEscape); | 106 | int next = optMin(nextEq, nextEscape); |
| 107 | |||
| 92 | if (next == -1) { | 108 | if (next == -1) { |
| 93 | break; | 109 | break; |
| 94 | } else if (next == nextEq) { | 110 | } else if (next == nextEq) { |
| @@ -102,8 +118,10 @@ public final class ConfigSerializer { | |||
| 102 | idx = parseEscape(v, nextEscape, sb); | 118 | idx = parseEscape(v, nextEscape, sb); |
| 103 | } | 119 | } |
| 104 | } | 120 | } |
| 121 | |||
| 105 | while (idx < v.length()) { | 122 | while (idx < v.length()) { |
| 106 | int nextEscape = v.indexOf('\\', idx); | 123 | int nextEscape = v.indexOf('\\', idx); |
| 124 | |||
| 107 | if (nextEscape != -1) { | 125 | if (nextEscape != -1) { |
| 108 | sb.append(v, idx, nextEscape); | 126 | sb.append(v, idx, nextEscape); |
| 109 | idx = parseEscape(v, nextEscape, sb); | 127 | idx = parseEscape(v, nextEscape, sb); |
| @@ -111,8 +129,13 @@ public final class ConfigSerializer { | |||
| 111 | break; | 129 | break; |
| 112 | } | 130 | } |
| 113 | } | 131 | } |
| 132 | |||
| 114 | sb.append(v, idx, v.length()); | 133 | sb.append(v, idx, v.length()); |
| 115 | if (k == null) return NO_MATCH; | 134 | |
| 135 | if (k == null) { | ||
| 136 | return NO_MATCH; | ||
| 137 | } | ||
| 138 | |||
| 116 | visitor.visitKeyValue(k, sb.toString()); | 139 | visitor.visitKeyValue(k, sb.toString()); |
| 117 | return idx; | 140 | return idx; |
| 118 | } | 141 | } |
| @@ -122,11 +145,14 @@ public final class ConfigSerializer { | |||
| 122 | if (v.charAt(idx + 1) == 'u') { | 145 | if (v.charAt(idx + 1) == 'u') { |
| 123 | if (idx + 5 < v.length()) { | 146 | if (idx + 5 < v.length()) { |
| 124 | String codePoint = v.substring(idx + 2, idx + 6); | 147 | String codePoint = v.substring(idx + 2, idx + 6); |
| 148 | |||
| 125 | try { | 149 | try { |
| 126 | int c = Integer.parseUnsignedInt(codePoint, 16); | 150 | int c = Integer.parseUnsignedInt(codePoint, 16); |
| 127 | sb.append((char) c); | 151 | sb.append((char) c); |
| 128 | } catch (NumberFormatException ignored) { | 152 | } catch (NumberFormatException ignored) { |
| 153 | // ignored | ||
| 129 | } | 154 | } |
| 155 | |||
| 130 | idx = idx + 6; | 156 | idx = idx + 6; |
| 131 | } | 157 | } |
| 132 | } else if (v.charAt(idx + 1) == 'n') { | 158 | } else if (v.charAt(idx + 1) == 'n') { |
| @@ -139,6 +165,7 @@ public final class ConfigSerializer { | |||
| 139 | } else { | 165 | } else { |
| 140 | idx = idx + 1; | 166 | idx = idx + 1; |
| 141 | } | 167 | } |
| 168 | |||
| 142 | return idx; | 169 | return idx; |
| 143 | } | 170 | } |
| 144 | 171 | ||
| @@ -150,12 +177,17 @@ public final class ConfigSerializer { | |||
| 150 | 177 | ||
| 151 | private static void structureToString(ConfigSection section, StringBuilder sb, List<String> pathStack) { | 178 | private static void structureToString(ConfigSection section, StringBuilder sb, List<String> pathStack) { |
| 152 | if (!section.values().isEmpty()) { | 179 | if (!section.values().isEmpty()) { |
| 153 | if (sb.length() > 0) sb.append('\n'); | 180 | if (sb.length() > 0) { |
| 181 | sb.append('\n'); | ||
| 182 | } | ||
| 183 | |||
| 154 | pathStack.forEach(n -> sb.append('[').append(escapeSection(n)).append(']')); | 184 | pathStack.forEach(n -> sb.append('[').append(escapeSection(n)).append(']')); |
| 155 | if (!pathStack.isEmpty()) sb.append('\n'); | 185 | |
| 156 | section.values().entrySet().stream() | 186 | if (!pathStack.isEmpty()) { |
| 157 | .sorted(Entry.comparingByKey()) | 187 | sb.append('\n'); |
| 158 | .forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n')); | 188 | } |
| 189 | |||
| 190 | section.values().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> sb.append(escapeKey(e.getKey())).append('=').append(escapeValue(e.getValue())).append('\n')); | ||
| 159 | } | 191 | } |
| 160 | 192 | ||
| 161 | section.sections().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> { | 193 | section.sections().entrySet().stream().sorted(Entry.comparingByKey()).forEach(e -> { |
| @@ -166,43 +198,37 @@ public final class ConfigSerializer { | |||
| 166 | } | 198 | } |
| 167 | 199 | ||
| 168 | private static String escapeSection(String s) { | 200 | private static String escapeSection(String s) { |
| 169 | return s | 201 | return s.replace("\\", "\\\\").replace("\n", "\\n").replace("]", "\\]").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); |
| 170 | .replace("\\", "\\\\") | ||
| 171 | .replace("\n", "\\n") | ||
| 172 | .replace("]", "\\]") | ||
| 173 | .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); | ||
| 174 | } | 202 | } |
| 175 | 203 | ||
| 176 | private static String escapeKey(String s) { | 204 | private static String escapeKey(String s) { |
| 177 | return s | 205 | return s.replace("\\", "\\\\").replace("[", "\\[").replace("\n", "\\n").replace("=", "\\=").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); |
| 178 | .replace("\\", "\\\\") | ||
| 179 | .replace("[", "\\[") | ||
| 180 | .replace("\n", "\\n") | ||
| 181 | .replace("=", "\\=") | ||
| 182 | .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); | ||
| 183 | } | 206 | } |
| 184 | 207 | ||
| 185 | private static String escapeValue(String s) { | 208 | private static String escapeValue(String s) { |
| 186 | return s | 209 | return s.replace("\\", "\\\\").replace("\n", "\\n").chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); |
| 187 | .replace("\\", "\\\\") | ||
| 188 | .replace("\n", "\\n") | ||
| 189 | .chars().mapToObj(c -> c >= 32 && c < 127 ? Character.toString((char) c) : String.format("\\u%04x", c)).collect(Collectors.joining()); | ||
| 190 | } | 210 | } |
| 191 | 211 | ||
| 192 | public static Optional<Boolean> parseBool(String v) { | 212 | public static Optional<Boolean> parseBool(String v) { |
| 193 | if (v == null) return Optional.empty(); | 213 | if (v == null) { |
| 214 | return Optional.empty(); | ||
| 215 | } | ||
| 216 | |||
| 194 | switch (v) { | 217 | switch (v) { |
| 195 | case "true": | 218 | case "true": |
| 196 | return Optional.of(true); | 219 | return Optional.of(true); |
| 197 | case "false": | 220 | case "false": |
| 198 | return Optional.of(false); | 221 | return Optional.of(false); |
| 199 | default: | 222 | default: |
| 200 | return Optional.empty(); | 223 | return Optional.empty(); |
| 201 | } | 224 | } |
| 202 | } | 225 | } |
| 203 | 226 | ||
| 204 | public static OptionalInt parseInt(String v) { | 227 | public static OptionalInt parseInt(String v) { |
| 205 | if (v == null) return OptionalInt.empty(); | 228 | if (v == null) { |
| 229 | return OptionalInt.empty(); | ||
| 230 | } | ||
| 231 | |||
| 206 | try { | 232 | try { |
| 207 | return OptionalInt.of(Integer.parseInt(v)); | 233 | return OptionalInt.of(Integer.parseInt(v)); |
| 208 | } catch (NumberFormatException e) { | 234 | } catch (NumberFormatException e) { |
| @@ -211,7 +237,10 @@ public final class ConfigSerializer { | |||
| 211 | } | 237 | } |
| 212 | 238 | ||
| 213 | public static OptionalDouble parseDouble(String v) { | 239 | public static OptionalDouble parseDouble(String v) { |
| 214 | if (v == null) return OptionalDouble.empty(); | 240 | if (v == null) { |
| 241 | return OptionalDouble.empty(); | ||
| 242 | } | ||
| 243 | |||
| 215 | try { | 244 | try { |
| 216 | return OptionalDouble.of(Double.parseDouble(v)); | 245 | return OptionalDouble.of(Double.parseDouble(v)); |
| 217 | } catch (NumberFormatException e) { | 246 | } catch (NumberFormatException e) { |
| @@ -220,7 +249,10 @@ public final class ConfigSerializer { | |||
| 220 | } | 249 | } |
| 221 | 250 | ||
| 222 | public static OptionalInt parseRgbColor(String v) { | 251 | public static OptionalInt parseRgbColor(String v) { |
| 223 | if (v == null) return OptionalInt.empty(); | 252 | if (v == null) { |
| 253 | return OptionalInt.empty(); | ||
| 254 | } | ||
| 255 | |||
| 224 | try { | 256 | try { |
| 225 | if (FULL_RGB_COLOR.matcher(v).matches()) { | 257 | if (FULL_RGB_COLOR.matcher(v).matches()) { |
| 226 | return OptionalInt.of(Integer.parseUnsignedInt(v.substring(1), 16)); | 258 | return OptionalInt.of(Integer.parseUnsignedInt(v.substring(1), 16)); |
| @@ -241,6 +273,7 @@ public final class ConfigSerializer { | |||
| 241 | public static String rgbColorToString(int color) { | 273 | public static String rgbColorToString(int color) { |
| 242 | color = color & 0xFFFFFF; | 274 | color = color & 0xFFFFFF; |
| 243 | boolean isShort = ((color & 0xF0F0F0) >> 4 ^ color & 0x0F0F0F) == 0; | 275 | boolean isShort = ((color & 0xF0F0F0) >> 4 ^ color & 0x0F0F0F) == 0; |
| 276 | |||
| 244 | if (isShort) { | 277 | if (isShort) { |
| 245 | int packed = color & 0x0F0F0F; | 278 | int packed = color & 0x0F0F0F; |
| 246 | packed = packed & 0xF | packed >> 4; | 279 | packed = packed & 0xF | packed >> 4; |
| @@ -252,14 +285,19 @@ public final class ConfigSerializer { | |||
| 252 | } | 285 | } |
| 253 | 286 | ||
| 254 | public static Optional<String[]> parseArray(String v) { | 287 | public static Optional<String[]> parseArray(String v) { |
| 255 | if (v == null) return Optional.empty(); | 288 | if (v == null) { |
| 289 | return Optional.empty(); | ||
| 290 | } | ||
| 291 | |||
| 256 | List<String> l = new ArrayList<>(); | 292 | List<String> l = new ArrayList<>(); |
| 257 | int idx = 0; | 293 | int idx = 0; |
| 258 | StringBuilder cur = new StringBuilder(); | 294 | StringBuilder cur = new StringBuilder(); |
| 295 | |||
| 259 | while (true) { | 296 | while (true) { |
| 260 | int nextSep = v.indexOf(',', idx); | 297 | int nextSep = v.indexOf(',', idx); |
| 261 | int nextEsc = v.indexOf('\\', idx); | 298 | int nextEsc = v.indexOf('\\', idx); |
| 262 | int next = optMin(nextSep, nextEsc); | 299 | int next = optMin(nextSep, nextEsc); |
| 300 | |||
| 263 | if (next == -1) { | 301 | if (next == -1) { |
| 264 | cur.append(v, idx, v.length()); | 302 | cur.append(v, idx, v.length()); |
| 265 | l.add(cur.toString()); | 303 | l.add(cur.toString()); |
| @@ -271,22 +309,25 @@ public final class ConfigSerializer { | |||
| 271 | idx = nextSep + 1; | 309 | idx = nextSep + 1; |
| 272 | } else if (next == nextEsc) { | 310 | } else if (next == nextEsc) { |
| 273 | cur.append(v, idx, nextEsc); | 311 | cur.append(v, idx, nextEsc); |
| 312 | |||
| 274 | if (nextEsc + 1 < v.length()) { | 313 | if (nextEsc + 1 < v.length()) { |
| 275 | cur.append(v.charAt(nextEsc + 1)); | 314 | cur.append(v.charAt(nextEsc + 1)); |
| 276 | } | 315 | } |
| 316 | |||
| 277 | idx = nextEsc + 2; | 317 | idx = nextEsc + 2; |
| 278 | } | 318 | } |
| 279 | } | 319 | } |
| 280 | } | 320 | } |
| 281 | 321 | ||
| 282 | public static String arrayToString(String[] values) { | 322 | public static String arrayToString(String[] values) { |
| 283 | return Arrays.stream(values) | 323 | return Arrays.stream(values).map(s -> s.replace("\\", "\\\\").replace(",", "\\,")).collect(Collectors.joining(",")); |
| 284 | .map(s -> s.replace("\\", "\\\\").replace(",", "\\,")) | ||
| 285 | .collect(Collectors.joining(",")); | ||
| 286 | } | 324 | } |
| 287 | 325 | ||
| 288 | public static <T extends Enum<T>> Optional<T> parseEnum(Function<String, T> byName, String v) { | 326 | public static <T extends Enum<T>> Optional<T> parseEnum(Function<String, T> byName, String v) { |
| 289 | if (v == null) return Optional.empty(); | 327 | if (v == null) { |
| 328 | return Optional.empty(); | ||
| 329 | } | ||
| 330 | |||
| 290 | try { | 331 | try { |
| 291 | return Optional.of(byName.apply(v)); | 332 | return Optional.of(byName.apply(v)); |
| 292 | } catch (IllegalArgumentException e) { | 333 | } catch (IllegalArgumentException e) { |
| @@ -295,9 +336,14 @@ public final class ConfigSerializer { | |||
| 295 | } | 336 | } |
| 296 | 337 | ||
| 297 | private static int optMin(int v1, int v2) { | 338 | private static int optMin(int v1, int v2) { |
| 298 | if (v1 == -1) return v2; | 339 | if (v1 == -1) { |
| 299 | if (v2 == -1) return v1; | 340 | return v2; |
| 341 | } | ||
| 342 | |||
| 343 | if (v2 == -1) { | ||
| 344 | return v1; | ||
| 345 | } | ||
| 346 | |||
| 300 | return Math.min(v1, v2); | 347 | return Math.min(v1, v2); |
| 301 | } | 348 | } |
| 302 | |||
| 303 | } | 349 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java index 12d7ec4e..53743143 100644 --- a/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/config/ConfigStructureVisitor.java | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | package cuchaz.enigma.config; | 1 | package cuchaz.enigma.config; |
| 2 | 2 | ||
| 3 | public interface ConfigStructureVisitor { | 3 | public interface ConfigStructureVisitor { |
| 4 | |||
| 5 | void visitKeyValue(String key, String value); | 4 | void visitKeyValue(String key, String value); |
| 6 | 5 | ||
| 7 | void visitSection(String section); | 6 | void visitSection(String section); |
| 8 | 7 | ||
| 9 | void jumpToRootSection(); | 8 | void jumpToRootSection(); |
| 10 | |||
| 11 | } | 9 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java index 61fea4ea..22be2e02 100644 --- a/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java +++ b/enigma/src/main/java/cuchaz/enigma/events/ClassHandleListener.java | |||
| @@ -8,7 +8,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 8 | import cuchaz.enigma.utils.Result; | 8 | import cuchaz.enigma.utils.Result; |
| 9 | 9 | ||
| 10 | public interface ClassHandleListener { | 10 | public interface ClassHandleListener { |
| 11 | |||
| 12 | default void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) { | 11 | default void onDeobfRefChanged(ClassHandle h, ClassEntry deobfRef) { |
| 13 | } | 12 | } |
| 14 | 13 | ||
| @@ -32,5 +31,4 @@ public interface ClassHandleListener { | |||
| 32 | JAVADOC, | 31 | JAVADOC, |
| 33 | MAPPINGS, | 32 | MAPPINGS, |
| 34 | } | 33 | } |
| 35 | |||
| 36 | } | 34 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java index 5f371a58..9475d743 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/DecompiledClassSource.java | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.Collection; |
| 4 | import java.util.Iterator; | ||
| 5 | import java.util.List; | ||
| 6 | import java.util.Map; | ||
| 7 | import java.util.Optional; | ||
| 4 | 8 | ||
| 5 | import javax.annotation.Nullable; | 9 | import javax.annotation.Nullable; |
| 6 | 10 | ||
| @@ -62,6 +66,7 @@ public class DecompiledClassSource { | |||
| 62 | return translatedEntry.getValue().getSourceRemapName(); | 66 | return translatedEntry.getValue().getSourceRemapName(); |
| 63 | } else { | 67 | } else { |
| 64 | Optional<String> proposedName = proposeName(project, entry); | 68 | Optional<String> proposedName = proposeName(project, entry); |
| 69 | |||
| 65 | if (proposedName.isPresent()) { | 70 | if (proposedName.isPresent()) { |
| 66 | target.add(RenamableTokenType.PROPOSED, movedToken); | 71 | target.add(RenamableTokenType.PROPOSED, movedToken); |
| 67 | return proposedName.get(); | 72 | return proposedName.get(); |
| @@ -72,6 +77,7 @@ public class DecompiledClassSource { | |||
| 72 | } | 77 | } |
| 73 | 78 | ||
| 74 | String defaultName = generateDefaultName(translatedEntry.getValue()); | 79 | String defaultName = generateDefaultName(translatedEntry.getValue()); |
| 80 | |||
| 75 | if (defaultName != null) { | 81 | if (defaultName != null) { |
| 76 | return defaultName; | 82 | return defaultName; |
| 77 | } | 83 | } |
| @@ -86,10 +92,7 @@ public class DecompiledClassSource { | |||
| 86 | EntryRemapper mapper = project.getMapper(); | 92 | EntryRemapper mapper = project.getMapper(); |
| 87 | Collection<Entry<?>> resolved = mapper.getObfResolver().resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT); | 93 | Collection<Entry<?>> resolved = mapper.getObfResolver().resolveEntry(entry, ResolutionStrategy.RESOLVE_ROOT); |
| 88 | 94 | ||
| 89 | return resolved.stream() | 95 | return resolved.stream().map(e -> nameProposalService.proposeName(e, mapper)).filter(Optional::isPresent).map(Optional::get); |
| 90 | .map(e -> nameProposalService.proposeName(e, mapper)) | ||
| 91 | .filter(Optional::isPresent) | ||
| 92 | .map(Optional::get); | ||
| 93 | }).findFirst(); | 96 | }).findFirst(); |
| 94 | } | 97 | } |
| 95 | 98 | ||
| @@ -99,6 +102,7 @@ public class DecompiledClassSource { | |||
| 99 | LocalVariableDefEntry localVariable = (LocalVariableDefEntry) entry; | 102 | LocalVariableDefEntry localVariable = (LocalVariableDefEntry) entry; |
| 100 | 103 | ||
| 101 | int index = localVariable.getIndex(); | 104 | int index = localVariable.getIndex(); |
| 105 | |||
| 102 | if (localVariable.isArgument()) { | 106 | if (localVariable.isArgument()) { |
| 103 | List<TypeDescriptor> arguments = localVariable.getParent().getDesc().getArgumentDescs(); | 107 | List<TypeDescriptor> arguments = localVariable.getParent().getDesc().getArgumentDescs(); |
| 104 | return LocalNameGenerator.generateArgumentName(index, localVariable.getDesc(), arguments); | 108 | return LocalNameGenerator.generateArgumentName(index, localVariable.getDesc(), arguments); |
| @@ -139,9 +143,11 @@ public class DecompiledClassSource { | |||
| 139 | 143 | ||
| 140 | Iterator<Token> fromTokenItr = fromIndex.referenceTokens().iterator(); | 144 | Iterator<Token> fromTokenItr = fromIndex.referenceTokens().iterator(); |
| 141 | Iterator<Token> toTokenItr = toIndex.referenceTokens().iterator(); | 145 | Iterator<Token> toTokenItr = toIndex.referenceTokens().iterator(); |
| 146 | |||
| 142 | while (fromTokenItr.hasNext() && toTokenItr.hasNext()) { | 147 | while (fromTokenItr.hasNext() && toTokenItr.hasNext()) { |
| 143 | Token fromToken = fromTokenItr.next(); | 148 | Token fromToken = fromTokenItr.next(); |
| 144 | Token toToken = toTokenItr.next(); | 149 | Token toToken = toTokenItr.next(); |
| 150 | |||
| 145 | if (fromToken.end > fromOffset) { | 151 | if (fromToken.end > fromOffset) { |
| 146 | break; | 152 | break; |
| 147 | } | 153 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java index 938a7362..b31dcc43 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/Decompiler.java | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 4 | import org.checkerframework.checker.nullness.qual.Nullable; | 3 | import org.checkerframework.checker.nullness.qual.Nullable; |
| 5 | 4 | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 6 | |||
| 6 | public interface Decompiler { | 7 | public interface Decompiler { |
| 7 | @Deprecated // use remapper specific one for easy doc inclusion | 8 | @Deprecated // use remapper specific one for easy doc inclusion |
| 8 | default Source getSource(String className) { | 9 | default Source getSource(String className) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java index 638498f7..a87fc98c 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java +++ b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.classprovider.ClassProvider; | ||
| 4 | import cuchaz.enigma.api.service.EnigmaService; | 3 | import cuchaz.enigma.api.service.EnigmaService; |
| 5 | import cuchaz.enigma.api.service.EnigmaServiceType; | 4 | import cuchaz.enigma.api.service.EnigmaServiceType; |
| 5 | import cuchaz.enigma.classprovider.ClassProvider; | ||
| 6 | 6 | ||
| 7 | public interface DecompilerService extends EnigmaService { | 7 | public interface DecompilerService extends EnigmaService { |
| 8 | EnigmaServiceType<DecompilerService> TYPE = EnigmaServiceType.create("decompiler"); | 8 | EnigmaServiceType<DecompilerService> TYPE = EnigmaServiceType.create("decompiler"); |
| 9 | 9 | ||
| 10 | Decompiler create(ClassProvider classProvider, SourceSettings settings); | 10 | Decompiler create(ClassProvider classProvider, SourceSettings settings); |
| 11 | } | 11 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java index 643ea7a6..0e3244db 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java +++ b/enigma/src/main/java/cuchaz/enigma/source/Decompilers.java | |||
| @@ -5,7 +5,7 @@ import cuchaz.enigma.source.cfr.CfrDecompiler; | |||
| 5 | import cuchaz.enigma.source.procyon.ProcyonDecompiler; | 5 | import cuchaz.enigma.source.procyon.ProcyonDecompiler; |
| 6 | 6 | ||
| 7 | public class Decompilers { | 7 | public class Decompilers { |
| 8 | public static final DecompilerService PROCYON = ProcyonDecompiler::new; | 8 | public static final DecompilerService PROCYON = ProcyonDecompiler::new; |
| 9 | public static final DecompilerService CFR = CfrDecompiler::new; | 9 | public static final DecompilerService CFR = CfrDecompiler::new; |
| 10 | public static final DecompilerService BYTECODE = BytecodeDecompiler::new; | 10 | public static final DecompilerService BYTECODE = BytecodeDecompiler::new; |
| 11 | } | 11 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Source.java b/enigma/src/main/java/cuchaz/enigma/source/Source.java index 6ecce7c5..fe458055 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/Source.java +++ b/enigma/src/main/java/cuchaz/enigma/source/Source.java | |||
| @@ -3,9 +3,9 @@ package cuchaz.enigma.source; | |||
| 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 3 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 4 | 4 | ||
| 5 | public interface Source { | 5 | public interface Source { |
| 6 | String asString(); | 6 | String asString(); |
| 7 | 7 | ||
| 8 | Source withJavadocs(EntryRemapper remapper); | 8 | Source withJavadocs(EntryRemapper remapper); |
| 9 | 9 | ||
| 10 | SourceIndex index(); | 10 | SourceIndex index(); |
| 11 | } | 11 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java index 971252e2..e9d928e9 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java +++ b/enigma/src/main/java/cuchaz/enigma/source/SourceIndex.java | |||
| @@ -1,172 +1,170 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.List; | ||
| 5 | import java.util.Map; | ||
| 6 | import java.util.TreeMap; | ||
| 7 | |||
| 3 | import com.google.common.collect.HashMultimap; | 8 | import com.google.common.collect.HashMultimap; |
| 4 | import com.google.common.collect.Lists; | 9 | import com.google.common.collect.Lists; |
| 5 | import com.google.common.collect.Maps; | 10 | import com.google.common.collect.Maps; |
| 6 | import com.google.common.collect.Multimap; | 11 | import com.google.common.collect.Multimap; |
| 12 | |||
| 7 | import cuchaz.enigma.analysis.EntryReference; | 13 | import cuchaz.enigma.analysis.EntryReference; |
| 8 | import cuchaz.enigma.translation.mapping.EntryResolver; | 14 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 9 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 15 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 10 | import cuchaz.enigma.translation.representation.entry.Entry; | 16 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 11 | 17 | ||
| 12 | import java.util.Collection; | ||
| 13 | import java.util.List; | ||
| 14 | import java.util.Map; | ||
| 15 | import java.util.TreeMap; | ||
| 16 | |||
| 17 | public class SourceIndex { | 18 | public class SourceIndex { |
| 18 | private String source; | 19 | private String source; |
| 19 | private List<Integer> lineOffsets; | 20 | private List<Integer> lineOffsets; |
| 20 | private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference; | 21 | private final TreeMap<Token, EntryReference<Entry<?>, Entry<?>>> tokenToReference; |
| 21 | private final Multimap<EntryReference<Entry<?>, Entry<?>>, Token> referenceToTokens; | 22 | private final Multimap<EntryReference<Entry<?>, Entry<?>>, Token> referenceToTokens; |
| 22 | private final Map<Entry<?>, Token> declarationToToken; | 23 | private final Map<Entry<?>, Token> declarationToToken; |
| 23 | 24 | ||
| 24 | public SourceIndex() { | 25 | public SourceIndex() { |
| 25 | tokenToReference = new TreeMap<>(); | 26 | tokenToReference = new TreeMap<>(); |
| 26 | referenceToTokens = HashMultimap.create(); | 27 | referenceToTokens = HashMultimap.create(); |
| 27 | declarationToToken = Maps.newHashMap(); | 28 | declarationToToken = Maps.newHashMap(); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | public SourceIndex(String source) { | 31 | public SourceIndex(String source) { |
| 31 | this(); | 32 | this(); |
| 32 | setSource(source); | 33 | setSource(source); |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | public void setSource(String source) { | 36 | public void setSource(String source) { |
| 36 | this.source = source; | 37 | this.source = source; |
| 37 | lineOffsets = Lists.newArrayList(); | 38 | lineOffsets = Lists.newArrayList(); |
| 38 | lineOffsets.add(0); | 39 | lineOffsets.add(0); |
| 39 | 40 | ||
| 40 | for (int i = 0; i < this.source.length(); i++) { | 41 | for (int i = 0; i < this.source.length(); i++) { |
| 41 | if (this.source.charAt(i) == '\n') { | 42 | if (this.source.charAt(i) == '\n') { |
| 42 | lineOffsets.add(i + 1); | 43 | lineOffsets.add(i + 1); |
| 43 | } | 44 | } |
| 44 | } | 45 | } |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | public String getSource() { | 48 | public String getSource() { |
| 48 | return source; | 49 | return source; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | public int getLineNumber(int position) { | 52 | public int getLineNumber(int position) { |
| 52 | int line = 0; | 53 | int line = 0; |
| 53 | 54 | ||
| 54 | for (int offset : lineOffsets) { | 55 | for (int offset : lineOffsets) { |
| 55 | if (offset > position) { | 56 | if (offset > position) { |
| 56 | break; | 57 | break; |
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | line++; | 60 | line++; |
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | return line; | 63 | return line; |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | public int getColumnNumber(int position) { | 66 | public int getColumnNumber(int position) { |
| 66 | return position - lineOffsets.get(getLineNumber(position) - 1) + 1; | 67 | return position - lineOffsets.get(getLineNumber(position) - 1) + 1; |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | public int getPosition(int line, int column) { | 70 | public int getPosition(int line, int column) { |
| 70 | return lineOffsets.get(line - 1) + column - 1; | 71 | return lineOffsets.get(line - 1) + column - 1; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | public Iterable<Entry<?>> declarations() { | 74 | public Iterable<Entry<?>> declarations() { |
| 74 | return declarationToToken.keySet(); | 75 | return declarationToToken.keySet(); |
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | public Iterable<Token> declarationTokens() { | 78 | public Iterable<Token> declarationTokens() { |
| 78 | return declarationToToken.values(); | 79 | return declarationToToken.values(); |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | public Token getDeclarationToken(Entry<?> entry) { | 82 | public Token getDeclarationToken(Entry<?> entry) { |
| 82 | return declarationToToken.get(entry); | 83 | return declarationToToken.get(entry); |
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | public void addDeclaration(Token token, Entry<?> deobfEntry) { | 86 | public void addDeclaration(Token token, Entry<?> deobfEntry) { |
| 86 | if (token != null) { | 87 | if (token != null) { |
| 87 | EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text); | 88 | EntryReference<Entry<?>, Entry<?>> reference = new EntryReference<>(deobfEntry, token.text); |
| 88 | tokenToReference.put(token, reference); | 89 | tokenToReference.put(token, reference); |
| 89 | referenceToTokens.put(reference, token); | 90 | referenceToTokens.put(reference, token); |
| 90 | referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token); | 91 | referenceToTokens.put(EntryReference.declaration(deobfEntry, token.text), token); |
| 91 | declarationToToken.put(deobfEntry, token); | 92 | declarationToToken.put(deobfEntry, token); |
| 92 | } | 93 | } |
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | public Iterable<EntryReference<Entry<?>, Entry<?>>> references() { | 96 | public Iterable<EntryReference<Entry<?>, Entry<?>>> references() { |
| 96 | return referenceToTokens.keySet(); | 97 | return referenceToTokens.keySet(); |
| 97 | } | 98 | } |
| 98 | 99 | ||
| 99 | public EntryReference<Entry<?>, Entry<?>> getReference(Token token) { | 100 | public EntryReference<Entry<?>, Entry<?>> getReference(Token token) { |
| 100 | if (token == null) { | 101 | if (token == null) { |
| 101 | return null; | 102 | return null; |
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | return tokenToReference.get(token); | 105 | return tokenToReference.get(token); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| 107 | public Iterable<Token> referenceTokens() { | 108 | public Iterable<Token> referenceTokens() { |
| 108 | return tokenToReference.keySet(); | 109 | return tokenToReference.keySet(); |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | public Token getReferenceToken(int pos) { | 112 | public Token getReferenceToken(int pos) { |
| 112 | Token token = tokenToReference.floorKey(new Token(pos, pos, null)); | 113 | Token token = tokenToReference.floorKey(new Token(pos, pos, null)); |
| 113 | 114 | ||
| 114 | if (token != null && token.contains(pos)) { | 115 | if (token != null && token.contains(pos)) { |
| 115 | return token; | 116 | return token; |
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | return null; | 119 | return null; |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | public Collection<Token> getReferenceTokens(EntryReference<Entry<?>, Entry<?>> deobfReference) { | 122 | public Collection<Token> getReferenceTokens(EntryReference<Entry<?>, Entry<?>> deobfReference) { |
| 122 | return referenceToTokens.get(deobfReference); | 123 | return referenceToTokens.get(deobfReference); |
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | public void addReference(Token token, Entry<?> deobfEntry, Entry<?> deobfContext) { | 126 | public void addReference(Token token, Entry<?> deobfEntry, Entry<?> deobfContext) { |
| 126 | if (token != null) { | 127 | if (token != null) { |
| 127 | EntryReference<Entry<?>, Entry<?>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); | 128 | EntryReference<Entry<?>, Entry<?>> deobfReference = new EntryReference<>(deobfEntry, token.text, deobfContext); |
| 128 | tokenToReference.put(token, deobfReference); | 129 | tokenToReference.put(token, deobfReference); |
| 129 | referenceToTokens.put(deobfReference, token); | 130 | referenceToTokens.put(deobfReference, token); |
| 130 | } | 131 | } |
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | public void resolveReferences(EntryResolver resolver) { | 134 | public void resolveReferences(EntryResolver resolver) { |
| 134 | // resolve all the classes in the source references | 135 | // resolve all the classes in the source references |
| 135 | for (Token token : Lists.newArrayList(referenceToTokens.values())) { | 136 | for (Token token : Lists.newArrayList(referenceToTokens.values())) { |
| 136 | EntryReference<Entry<?>, Entry<?>> reference = tokenToReference.get(token); | 137 | EntryReference<Entry<?>, Entry<?>> reference = tokenToReference.get(token); |
| 137 | EntryReference<Entry<?>, Entry<?>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); | 138 | EntryReference<Entry<?>, Entry<?>> resolvedReference = resolver.resolveFirstReference(reference, ResolutionStrategy.RESOLVE_CLOSEST); |
| 138 | 139 | ||
| 139 | // replace the reference | 140 | // replace the reference |
| 140 | tokenToReference.replace(token, resolvedReference); | 141 | tokenToReference.replace(token, resolvedReference); |
| 141 | 142 | ||
| 142 | Collection<Token> tokens = referenceToTokens.removeAll(reference); | 143 | Collection<Token> tokens = referenceToTokens.removeAll(reference); |
| 143 | referenceToTokens.putAll(resolvedReference, tokens); | 144 | referenceToTokens.putAll(resolvedReference, tokens); |
| 144 | } | 145 | } |
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | public SourceIndex remapTo(SourceRemapper.Result result) { | 148 | public SourceIndex remapTo(SourceRemapper.Result result) { |
| 148 | SourceIndex remapped = new SourceIndex(result.getSource()); | 149 | SourceIndex remapped = new SourceIndex(result.getSource()); |
| 149 | 150 | ||
| 150 | for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) { | 151 | for (Map.Entry<Entry<?>, Token> entry : declarationToToken.entrySet()) { |
| 151 | remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); | 152 | remapped.declarationToToken.put(entry.getKey(), result.getRemappedToken(entry.getValue())); |
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.asMap().entrySet()) { | 155 | for (Map.Entry<EntryReference<Entry<?>, Entry<?>>, Collection<Token>> entry : referenceToTokens.asMap().entrySet()) { |
| 155 | EntryReference<Entry<?>, Entry<?>> reference = entry.getKey(); | 156 | EntryReference<Entry<?>, Entry<?>> reference = entry.getKey(); |
| 156 | Collection<Token> oldTokens = entry.getValue(); | 157 | Collection<Token> oldTokens = entry.getValue(); |
| 157 | 158 | ||
| 158 | Collection<Token> newTokens = oldTokens | 159 | Collection<Token> newTokens = oldTokens.stream().map(result::getRemappedToken).toList(); |
| 159 | .stream() | 160 | |
| 160 | .map(result::getRemappedToken) | 161 | remapped.referenceToTokens.putAll(reference, newTokens); |
| 161 | .toList(); | 162 | } |
| 162 | 163 | ||
| 163 | remapped.referenceToTokens.putAll(reference, newTokens); | 164 | for (Map.Entry<Token, EntryReference<Entry<?>, Entry<?>>> entry : tokenToReference.entrySet()) { |
| 164 | } | 165 | remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue()); |
| 165 | 166 | } | |
| 166 | for (Map.Entry<Token, EntryReference<Entry<?>, Entry<?>>> entry : tokenToReference.entrySet()) { | 167 | |
| 167 | remapped.tokenToReference.put(result.getRemappedToken(entry.getKey()), entry.getValue()); | 168 | return remapped; |
| 168 | } | 169 | } |
| 169 | |||
| 170 | return remapped; | ||
| 171 | } | ||
| 172 | } | 170 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java index b5f80063..f12c3875 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java +++ b/enigma/src/main/java/cuchaz/enigma/source/SourceRemapper.java | |||
| @@ -17,10 +17,12 @@ public class SourceRemapper { | |||
| 17 | Map<Token, Token> remappedTokens = new HashMap<>(); | 17 | Map<Token, Token> remappedTokens = new HashMap<>(); |
| 18 | 18 | ||
| 19 | int accumulatedOffset = 0; | 19 | int accumulatedOffset = 0; |
| 20 | |||
| 20 | for (Token token : tokens) { | 21 | for (Token token : tokens) { |
| 21 | Token movedToken = token.move(accumulatedOffset); | 22 | Token movedToken = token.move(accumulatedOffset); |
| 22 | 23 | ||
| 23 | String remappedName = remapper.remap(token, movedToken); | 24 | String remappedName = remapper.remap(token, movedToken); |
| 25 | |||
| 24 | if (remappedName != null) { | 26 | if (remappedName != null) { |
| 25 | accumulatedOffset += movedToken.getRenameOffset(remappedName); | 27 | accumulatedOffset += movedToken.getRenameOffset(remappedName); |
| 26 | movedToken.rename(remappedSource, remappedName); | 28 | movedToken.rename(remappedSource, remappedName); |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java index f6c68e98..17547706 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java +++ b/enigma/src/main/java/cuchaz/enigma/source/SourceSettings.java | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | public class SourceSettings { | 3 | public class SourceSettings { |
| 4 | public final boolean removeImports; | 4 | public final boolean removeImports; |
| 5 | public final boolean removeVariableFinal; | 5 | public final boolean removeVariableFinal; |
| 6 | 6 | ||
| 7 | public SourceSettings(boolean removeImports, boolean removeVariableFinal) { | 7 | public SourceSettings(boolean removeImports, boolean removeVariableFinal) { |
| 8 | this.removeImports = removeImports; | 8 | this.removeImports = removeImports; |
| 9 | this.removeVariableFinal = removeVariableFinal; | 9 | this.removeVariableFinal = removeVariableFinal; |
| 10 | } | 10 | } |
| 11 | } | 11 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/Token.java b/enigma/src/main/java/cuchaz/enigma/source/Token.java index 7d729abb..5c14234c 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/Token.java +++ b/enigma/src/main/java/cuchaz/enigma/source/Token.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.source; | 12 | package cuchaz.enigma.source; |
| 13 | 13 | ||
| 14 | public class Token implements Comparable<Token> { | 14 | public class Token implements Comparable<Token> { |
| 15 | |||
| 16 | public int start; | 15 | public int start; |
| 17 | public int end; | 16 | public int end; |
| 18 | public String text; | 17 | public String text; |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java index f32d918c..179eeceb 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java +++ b/enigma/src/main/java/cuchaz/enigma/source/TokenStore.java | |||
| @@ -1,9 +1,14 @@ | |||
| 1 | package cuchaz.enigma.source; | 1 | package cuchaz.enigma.source; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.Collections; |
| 4 | import java.util.Comparator; | ||
| 5 | import java.util.EnumMap; | ||
| 6 | import java.util.Iterator; | ||
| 7 | import java.util.Map; | ||
| 8 | import java.util.NavigableSet; | ||
| 9 | import java.util.TreeSet; | ||
| 4 | 10 | ||
| 5 | public final class TokenStore { | 11 | public final class TokenStore { |
| 6 | |||
| 7 | private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null); | 12 | private static final TokenStore EMPTY = new TokenStore(Collections.emptyNavigableSet(), Collections.emptyMap(), null); |
| 8 | 13 | ||
| 9 | private final NavigableSet<Token> tokens; | 14 | private final NavigableSet<Token> tokens; |
| @@ -18,9 +23,11 @@ public final class TokenStore { | |||
| 18 | 23 | ||
| 19 | public static TokenStore create(SourceIndex obfuscatedIndex) { | 24 | public static TokenStore create(SourceIndex obfuscatedIndex) { |
| 20 | EnumMap<RenamableTokenType, NavigableSet<Token>> map = new EnumMap<>(RenamableTokenType.class); | 25 | EnumMap<RenamableTokenType, NavigableSet<Token>> map = new EnumMap<>(RenamableTokenType.class); |
| 26 | |||
| 21 | for (RenamableTokenType value : RenamableTokenType.values()) { | 27 | for (RenamableTokenType value : RenamableTokenType.values()) { |
| 22 | map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start))); | 28 | map.put(value, new TreeSet<>(Comparator.comparing(t -> t.start))); |
| 23 | } | 29 | } |
| 30 | |||
| 24 | return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource()); | 31 | return new TokenStore(new TreeSet<>(Comparator.comparing(t -> t.start)), Collections.unmodifiableMap(map), obfuscatedIndex.getSource()); |
| 25 | } | 32 | } |
| 26 | 33 | ||
| @@ -34,22 +41,25 @@ public final class TokenStore { | |||
| 34 | } | 41 | } |
| 35 | 42 | ||
| 36 | public boolean isCompatible(TokenStore other) { | 43 | public boolean isCompatible(TokenStore other) { |
| 37 | return this.obfSource != null && other.obfSource != null && | 44 | return this.obfSource != null && other.obfSource != null && this.obfSource.equals(other.obfSource) && this.tokens.size() == other.tokens.size(); |
| 38 | this.obfSource.equals(other.obfSource) && | ||
| 39 | this.tokens.size() == other.tokens.size(); | ||
| 40 | } | 45 | } |
| 41 | 46 | ||
| 42 | public int mapPosition(TokenStore to, int position) { | 47 | public int mapPosition(TokenStore to, int position) { |
| 43 | if (!this.isCompatible(to)) return 0; | 48 | if (!this.isCompatible(to)) { |
| 49 | return 0; | ||
| 50 | } | ||
| 44 | 51 | ||
| 45 | int newPos = position; | 52 | int newPos = position; |
| 46 | Iterator<Token> thisIter = this.tokens.iterator(); | 53 | Iterator<Token> thisIter = this.tokens.iterator(); |
| 47 | Iterator<Token> toIter = to.tokens.iterator(); | 54 | Iterator<Token> toIter = to.tokens.iterator(); |
| 55 | |||
| 48 | while (thisIter.hasNext()) { | 56 | while (thisIter.hasNext()) { |
| 49 | Token token = thisIter.next(); | 57 | Token token = thisIter.next(); |
| 50 | Token newToken = toIter.next(); | 58 | Token newToken = toIter.next(); |
| 51 | 59 | ||
| 52 | if (position < token.start) break; | 60 | if (position < token.start) { |
| 61 | break; | ||
| 62 | } | ||
| 53 | 63 | ||
| 54 | // if we're inside the token and the text changed, | 64 | // if we're inside the token and the text changed, |
| 55 | // snap the cursor to the beginning | 65 | // snap the cursor to the beginning |
| @@ -67,5 +77,4 @@ public final class TokenStore { | |||
| 67 | public Map<RenamableTokenType, NavigableSet<Token>> getByType() { | 77 | public Map<RenamableTokenType, NavigableSet<Token>> getByType() { |
| 68 | return byType; | 78 | return byType; |
| 69 | } | 79 | } |
| 70 | |||
| 71 | } | 80 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java index 97d2969b..6461d20e 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeDecompiler.java | |||
| @@ -1,21 +1,22 @@ | |||
| 1 | package cuchaz.enigma.source.bytecode; | 1 | package cuchaz.enigma.source.bytecode; |
| 2 | 2 | ||
| 3 | import org.checkerframework.checker.nullness.qual.Nullable; | ||
| 4 | |||
| 3 | import cuchaz.enigma.classprovider.ClassProvider; | 5 | import cuchaz.enigma.classprovider.ClassProvider; |
| 4 | import cuchaz.enigma.source.Decompiler; | 6 | import cuchaz.enigma.source.Decompiler; |
| 5 | import cuchaz.enigma.source.Source; | 7 | import cuchaz.enigma.source.Source; |
| 6 | import cuchaz.enigma.source.SourceSettings; | 8 | import cuchaz.enigma.source.SourceSettings; |
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 9 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 8 | import org.checkerframework.checker.nullness.qual.Nullable; | ||
| 9 | 10 | ||
| 10 | public class BytecodeDecompiler implements Decompiler { | 11 | public class BytecodeDecompiler implements Decompiler { |
| 11 | private final ClassProvider classProvider; | 12 | private final ClassProvider classProvider; |
| 12 | 13 | ||
| 13 | public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) { | 14 | public BytecodeDecompiler(ClassProvider classProvider, SourceSettings settings) { |
| 14 | this.classProvider = classProvider; | 15 | this.classProvider = classProvider; |
| 15 | } | 16 | } |
| 16 | 17 | ||
| 17 | @Override | 18 | @Override |
| 18 | public Source getSource(String className, @Nullable EntryRemapper remapper) { | 19 | public Source getSource(String className, @Nullable EntryRemapper remapper) { |
| 19 | return new BytecodeSource(classProvider.get(className), remapper); | 20 | return new BytecodeSource(classProvider.get(className), remapper); |
| 20 | } | 21 | } |
| 21 | } | 22 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java index 4364b408..bcb54552 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/BytecodeSource.java | |||
| @@ -1,56 +1,57 @@ | |||
| 1 | package cuchaz.enigma.source.bytecode; | 1 | package cuchaz.enigma.source.bytecode; |
| 2 | 2 | ||
| 3 | import java.io.PrintWriter; | ||
| 4 | import java.io.StringWriter; | ||
| 5 | |||
| 6 | import org.objectweb.asm.tree.ClassNode; | ||
| 7 | import org.objectweb.asm.util.TraceClassVisitor; | ||
| 8 | |||
| 3 | import cuchaz.enigma.Enigma; | 9 | import cuchaz.enigma.Enigma; |
| 4 | import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; | 10 | import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; |
| 5 | import cuchaz.enigma.source.Source; | 11 | import cuchaz.enigma.source.Source; |
| 6 | import cuchaz.enigma.source.SourceIndex; | 12 | import cuchaz.enigma.source.SourceIndex; |
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 13 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 8 | import org.objectweb.asm.tree.ClassNode; | ||
| 9 | import org.objectweb.asm.util.TraceClassVisitor; | ||
| 10 | |||
| 11 | import java.io.PrintWriter; | ||
| 12 | import java.io.StringWriter; | ||
| 13 | 14 | ||
| 14 | public class BytecodeSource implements Source { | 15 | public class BytecodeSource implements Source { |
| 15 | private final ClassNode classNode; | 16 | private final ClassNode classNode; |
| 16 | private final EntryRemapper remapper; | 17 | private final EntryRemapper remapper; |
| 17 | 18 | ||
| 18 | public BytecodeSource(ClassNode classNode, EntryRemapper remapper) { | 19 | public BytecodeSource(ClassNode classNode, EntryRemapper remapper) { |
| 19 | this.classNode = classNode; | 20 | this.classNode = classNode; |
| 20 | this.remapper = remapper; | 21 | this.remapper = remapper; |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | @Override | 24 | @Override |
| 24 | public String asString() { | 25 | public String asString() { |
| 25 | return index().getSource(); | 26 | return index().getSource(); |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | @Override | 29 | @Override |
| 29 | public Source withJavadocs(EntryRemapper remapper) { | 30 | public Source withJavadocs(EntryRemapper remapper) { |
| 30 | return new BytecodeSource(classNode, remapper); | 31 | return new BytecodeSource(classNode, remapper); |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | @Override | 34 | @Override |
| 34 | public SourceIndex index() { | 35 | public SourceIndex index() { |
| 35 | SourceIndex index = new SourceIndex(); | 36 | SourceIndex index = new SourceIndex(); |
| 36 | 37 | ||
| 37 | EnigmaTextifier textifier = new EnigmaTextifier(index); | 38 | EnigmaTextifier textifier = new EnigmaTextifier(index); |
| 38 | StringWriter out = new StringWriter(); | 39 | StringWriter out = new StringWriter(); |
| 39 | PrintWriter writer = new PrintWriter(out); | 40 | PrintWriter writer = new PrintWriter(out); |
| 40 | 41 | ||
| 41 | TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer); | 42 | TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, textifier, writer); |
| 42 | 43 | ||
| 43 | ClassNode node = this.classNode; | 44 | ClassNode node = this.classNode; |
| 44 | 45 | ||
| 45 | if (remapper != null) { | 46 | if (remapper != null) { |
| 46 | ClassNode translatedNode = new ClassNode(); | 47 | ClassNode translatedNode = new ClassNode(); |
| 47 | node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode)); | 48 | node.accept(new TranslationClassVisitor(remapper.getDeobfuscator(), Enigma.ASM_VERSION, translatedNode)); |
| 48 | node = translatedNode; | 49 | node = translatedNode; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | node.accept(traceClassVisitor); | 52 | node.accept(traceClassVisitor); |
| 52 | index.setSource(out.toString()); | 53 | index.setSource(out.toString()); |
| 53 | 54 | ||
| 54 | return index; | 55 | return index; |
| 55 | } | 56 | } |
| 56 | } | 57 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java index 2f3fcf2b..f1586ee9 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java +++ b/enigma/src/main/java/cuchaz/enigma/source/bytecode/EnigmaTextifier.java | |||
| @@ -1,14 +1,15 @@ | |||
| 1 | package cuchaz.enigma.source.bytecode; | 1 | package cuchaz.enigma.source.bytecode; |
| 2 | 2 | ||
| 3 | import org.objectweb.asm.util.Textifier; | ||
| 4 | |||
| 3 | import cuchaz.enigma.Enigma; | 5 | import cuchaz.enigma.Enigma; |
| 4 | import cuchaz.enigma.source.SourceIndex; | 6 | import cuchaz.enigma.source.SourceIndex; |
| 5 | import org.objectweb.asm.util.Textifier; | ||
| 6 | 7 | ||
| 7 | public class EnigmaTextifier extends Textifier { | 8 | public class EnigmaTextifier extends Textifier { |
| 8 | private final SourceIndex sourceIndex; | 9 | private final SourceIndex sourceIndex; |
| 9 | 10 | ||
| 10 | public EnigmaTextifier(SourceIndex sourceIndex) { | 11 | public EnigmaTextifier(SourceIndex sourceIndex) { |
| 11 | super(Enigma.ASM_VERSION); | 12 | super(Enigma.ASM_VERSION); |
| 12 | this.sourceIndex = sourceIndex; | 13 | this.sourceIndex = sourceIndex; |
| 13 | } | 14 | } |
| 14 | } | 15 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java index cd7b2aa2..55312364 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java | |||
| @@ -1,11 +1,8 @@ | |||
| 1 | package cuchaz.enigma.source.cfr; | 1 | package cuchaz.enigma.source.cfr; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.classprovider.ClassProvider; | 3 | import java.util.Collection; |
| 4 | import cuchaz.enigma.source.Decompiler; | 4 | import java.util.Map; |
| 5 | import cuchaz.enigma.source.Source; | 5 | |
| 6 | import cuchaz.enigma.source.SourceSettings; | ||
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 8 | import cuchaz.enigma.utils.AsmUtil; | ||
| 9 | import org.benf.cfr.reader.apiunreleased.ClassFileSource2; | 6 | import org.benf.cfr.reader.apiunreleased.ClassFileSource2; |
| 10 | import org.benf.cfr.reader.apiunreleased.JarContent; | 7 | import org.benf.cfr.reader.apiunreleased.JarContent; |
| 11 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; | 8 | import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; |
| @@ -15,55 +12,59 @@ import org.benf.cfr.reader.util.getopt.OptionsImpl; | |||
| 15 | import org.checkerframework.checker.nullness.qual.Nullable; | 12 | import org.checkerframework.checker.nullness.qual.Nullable; |
| 16 | import org.objectweb.asm.tree.ClassNode; | 13 | import org.objectweb.asm.tree.ClassNode; |
| 17 | 14 | ||
| 18 | import java.util.Collection; | 15 | import cuchaz.enigma.classprovider.ClassProvider; |
| 19 | import java.util.Map; | 16 | import cuchaz.enigma.source.Decompiler; |
| 17 | import cuchaz.enigma.source.Source; | ||
| 18 | import cuchaz.enigma.source.SourceSettings; | ||
| 19 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 20 | import cuchaz.enigma.utils.AsmUtil; | ||
| 20 | 21 | ||
| 21 | public class CfrDecompiler implements Decompiler { | 22 | public class CfrDecompiler implements Decompiler { |
| 22 | // cfr doesn't add final on params so final setting is ignored | 23 | // cfr doesn't add final on params so final setting is ignored |
| 23 | private final SourceSettings settings; | 24 | private final SourceSettings settings; |
| 24 | private final Options options; | 25 | private final Options options; |
| 25 | private final ClassFileSource2 classFileSource; | 26 | private final ClassFileSource2 classFileSource; |
| 26 | 27 | ||
| 27 | public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { | 28 | public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) { |
| 28 | this.options = OptionsImpl.getFactory().create( Map.of("trackbytecodeloc", "true")); | 29 | this.options = OptionsImpl.getFactory().create(Map.of("trackbytecodeloc", "true")); |
| 29 | this.settings = sourceSettings; | 30 | this.settings = sourceSettings; |
| 30 | this.classFileSource = new ClassFileSource(classProvider); | 31 | this.classFileSource = new ClassFileSource(classProvider); |
| 31 | } | 32 | } |
| 32 | 33 | ||
| 33 | @Override | 34 | @Override |
| 34 | public Source getSource(String className, @Nullable EntryRemapper mapper) { | 35 | public Source getSource(String className, @Nullable EntryRemapper mapper) { |
| 35 | return new CfrSource(className, settings, this.options, this.classFileSource, mapper); | 36 | return new CfrSource(className, settings, this.options, this.classFileSource, mapper); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 { | 39 | private record ClassFileSource(ClassProvider classProvider) implements ClassFileSource2 { |
| 39 | @Override | 40 | @Override |
| 40 | public JarContent addJarContent(String s, AnalysisType analysisType) { | 41 | public JarContent addJarContent(String s, AnalysisType analysisType) { |
| 41 | return null; | 42 | return null; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | @Override | 45 | @Override |
| 45 | public void informAnalysisRelativePathDetail(String usePath, String classFilePath) { | 46 | public void informAnalysisRelativePathDetail(String usePath, String classFilePath) { |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | @Override | 49 | @Override |
| 49 | public Collection<String> addJar(String jarPath) { | 50 | public Collection<String> addJar(String jarPath) { |
| 50 | return null; | 51 | return null; |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | @Override | 54 | @Override |
| 54 | public String getPossiblyRenamedPath(String path) { | 55 | public String getPossiblyRenamedPath(String path) { |
| 55 | return path; | 56 | return path; |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | @Override | 59 | @Override |
| 59 | public Pair<byte[], String> getClassFileContent(String path) { | 60 | public Pair<byte[], String> getClassFileContent(String path) { |
| 60 | ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.'))); | 61 | ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.'))); |
| 61 | 62 | ||
| 62 | if (node == null) { | 63 | if (node == null) { |
| 63 | return null; | 64 | return null; |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | return new Pair<>(AsmUtil.nodeToBytes(node), path); | 67 | return new Pair<>(AsmUtil.nodeToBytes(node), path); |
| 67 | } | 68 | } |
| 68 | } | 69 | } |
| 69 | } | 70 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java index fb44ef9a..70b43ac3 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java | |||
| @@ -1,9 +1,5 @@ | |||
| 1 | package cuchaz.enigma.source.cfr; | 1 | package cuchaz.enigma.source.cfr; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.source.Source; | ||
| 4 | import cuchaz.enigma.source.SourceIndex; | ||
| 5 | import cuchaz.enigma.source.SourceSettings; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 7 | import org.benf.cfr.reader.apiunreleased.ClassFileSource2; | 3 | import org.benf.cfr.reader.apiunreleased.ClassFileSource2; |
| 8 | import org.benf.cfr.reader.entities.ClassFile; | 4 | import org.benf.cfr.reader.entities.ClassFile; |
| 9 | import org.benf.cfr.reader.mapping.MappingFactory; | 5 | import org.benf.cfr.reader.mapping.MappingFactory; |
| @@ -17,71 +13,77 @@ import org.benf.cfr.reader.util.getopt.Options; | |||
| 17 | import org.benf.cfr.reader.util.getopt.OptionsImpl; | 13 | import org.benf.cfr.reader.util.getopt.OptionsImpl; |
| 18 | import org.checkerframework.checker.nullness.qual.Nullable; | 14 | import org.checkerframework.checker.nullness.qual.Nullable; |
| 19 | 15 | ||
| 16 | import cuchaz.enigma.source.Source; | ||
| 17 | import cuchaz.enigma.source.SourceIndex; | ||
| 18 | import cuchaz.enigma.source.SourceSettings; | ||
| 19 | import cuchaz.enigma.translation.mapping.EntryRemapper; | ||
| 20 | |||
| 20 | public class CfrSource implements Source { | 21 | public class CfrSource implements Source { |
| 21 | private final String className; | 22 | private final String className; |
| 22 | private final SourceSettings settings; | 23 | private final SourceSettings settings; |
| 23 | private final Options options; | 24 | private final Options options; |
| 24 | private final ClassFileSource2 classFileSource; | 25 | private final ClassFileSource2 classFileSource; |
| 25 | private final EntryRemapper mapper; | 26 | private final EntryRemapper mapper; |
| 26 | 27 | ||
| 27 | private SourceIndex index; | 28 | private SourceIndex index; |
| 28 | 29 | ||
| 29 | public CfrSource(String className, SourceSettings settings, Options options, ClassFileSource2 classFileSource, @Nullable EntryRemapper mapper) { | 30 | public CfrSource(String className, SourceSettings settings, Options options, ClassFileSource2 classFileSource, @Nullable EntryRemapper mapper) { |
| 30 | this.className = className; | 31 | this.className = className; |
| 31 | this.settings = settings; | 32 | this.settings = settings; |
| 32 | this.options = options; | 33 | this.options = options; |
| 33 | this.classFileSource = classFileSource; | 34 | this.classFileSource = classFileSource; |
| 34 | this.mapper = mapper; | 35 | this.mapper = mapper; |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | @Override | 38 | @Override |
| 38 | public Source withJavadocs(EntryRemapper mapper) { | 39 | public Source withJavadocs(EntryRemapper mapper) { |
| 39 | return new CfrSource(className, settings, options, classFileSource, mapper); | 40 | return new CfrSource(className, settings, options, classFileSource, mapper); |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | @Override | 43 | @Override |
| 43 | public SourceIndex index() { | 44 | public SourceIndex index() { |
| 44 | ensureDecompiled(); | 45 | ensureDecompiled(); |
| 45 | return index; | 46 | return index; |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | @Override | 49 | @Override |
| 49 | public String asString() { | 50 | public String asString() { |
| 50 | ensureDecompiled(); | 51 | ensureDecompiled(); |
| 51 | return index.getSource(); | 52 | return index.getSource(); |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | private void ensureDecompiled() { | 55 | private void ensureDecompiled() { |
| 55 | if (index != null) { | 56 | if (index != null) { |
| 56 | return; | 57 | return; |
| 57 | } | 58 | } |
| 58 | 59 | ||
| 59 | DCCommonState commonState = new DCCommonState(options, classFileSource); | 60 | DCCommonState commonState = new DCCommonState(options, classFileSource); |
| 60 | ObfuscationMapping mapping = MappingFactory.get(options, commonState); | 61 | ObfuscationMapping mapping = MappingFactory.get(options, commonState); |
| 61 | DCCommonState state = new DCCommonState(commonState, mapping); | 62 | DCCommonState state = new DCCommonState(commonState, mapping); |
| 62 | ClassFile tree = state.getClassFileMaybePath(className); | 63 | ClassFile tree = state.getClassFileMaybePath(className); |
| 63 | 64 | ||
| 64 | state.configureWith(tree); | 65 | state.configureWith(tree); |
| 65 | 66 | ||
| 66 | // To make sure we're analysing the cached version | 67 | // To make sure we're analysing the cached version |
| 67 | try { | 68 | try { |
| 68 | tree = state.getClassFile(tree.getClassType()); | 69 | tree = state.getClassFile(tree.getClassType()); |
| 69 | } catch (CannotLoadClassException ignored) { | 70 | } catch (CannotLoadClassException ignored) { |
| 70 | } | 71 | // ignored |
| 71 | 72 | } | |
| 72 | if (options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)) { | 73 | |
| 73 | tree.loadInnerClasses(state); | 74 | if (options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)) { |
| 74 | } | 75 | tree.loadInnerClasses(state); |
| 75 | 76 | } | |
| 76 | if (options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)) { | 77 | |
| 77 | MemberNameResolver.resolveNames(state, ListFactory.newList(state.getClassCache().getLoadedTypes())); | 78 | if (options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)) { |
| 78 | } | 79 | MemberNameResolver.resolveNames(state, ListFactory.newList(state.getClassCache().getLoadedTypes())); |
| 79 | 80 | } | |
| 80 | TypeUsageCollectingDumper typeUsageCollector = new TypeUsageCollectingDumper(options, tree); | 81 | |
| 81 | tree.analyseTop(state, typeUsageCollector); | 82 | TypeUsageCollectingDumper typeUsageCollector = new TypeUsageCollectingDumper(options, tree); |
| 82 | 83 | tree.analyseTop(state, typeUsageCollector); | |
| 83 | EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsageCollector.getRealTypeUsageInformation(), options, mapper); | 84 | |
| 84 | tree.dump(state.getObfuscationMapping().wrap(dumper)); | 85 | EnigmaDumper dumper = new EnigmaDumper(new StringBuilder(), settings, typeUsageCollector.getRealTypeUsageInformation(), options, mapper); |
| 85 | index = dumper.getIndex(); | 86 | tree.dump(state.getObfuscationMapping().wrap(dumper)); |
| 86 | } | 87 | index = dumper.getIndex(); |
| 88 | } | ||
| 87 | } | 89 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java index 14fd1684..93cc64f2 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java +++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java | |||
| @@ -1,17 +1,13 @@ | |||
| 1 | package cuchaz.enigma.source.cfr; | 1 | package cuchaz.enigma.source.cfr; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.source.SourceIndex; | 3 | import java.util.ArrayList; |
| 4 | import cuchaz.enigma.source.SourceSettings; | 4 | import java.util.Arrays; |
| 5 | import cuchaz.enigma.source.Token; | 5 | import java.util.Collection; |
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | 6 | import java.util.HashMap; |
| 7 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 7 | import java.util.LinkedList; |
| 8 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 8 | import java.util.List; |
| 9 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 9 | import java.util.Map; |
| 10 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 10 | |
| 11 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 12 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 13 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc; | 11 | import org.benf.cfr.reader.bytecode.analysis.loc.HasByteCodeLoc; |
| 16 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; | 12 | import org.benf.cfr.reader.bytecode.analysis.types.JavaRefTypeInstance; |
| 17 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; | 13 | import org.benf.cfr.reader.bytecode.analysis.types.JavaTypeInstance; |
| @@ -31,371 +27,404 @@ import org.benf.cfr.reader.util.output.StringStreamDumper; | |||
| 31 | import org.benf.cfr.reader.util.output.TypeContext; | 27 | import org.benf.cfr.reader.util.output.TypeContext; |
| 32 | import org.checkerframework.checker.nullness.qual.Nullable; | 28 | import org.checkerframework.checker.nullness.qual.Nullable; |
| 33 | 29 | ||
| 34 | import java.util.ArrayList; | 30 | import cuchaz.enigma.source.SourceIndex; |
| 35 | import java.util.Arrays; | 31 | import cuchaz.enigma.source.SourceSettings; |
| 36 | import java.util.Collection; | 32 | import cuchaz.enigma.source.Token; |
| 37 | import java.util.HashMap; | 33 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 38 | import java.util.LinkedList; | 34 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 39 | import java.util.List; | 35 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 40 | import java.util.Map; | 36 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 37 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 38 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 39 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 40 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 41 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 41 | 42 | ||
| 42 | public class EnigmaDumper extends StringStreamDumper { | 43 | public class EnigmaDumper extends StringStreamDumper { |
| 43 | private final StringBuilder sb; | 44 | private final StringBuilder sb; |
| 44 | private final SourceSettings sourceSettings; | 45 | private final SourceSettings sourceSettings; |
| 45 | private final SourceIndex index; | 46 | private final SourceIndex index; |
| 46 | private final @Nullable EntryRemapper mapper; | 47 | private final @Nullable EntryRemapper mapper; |
| 47 | private final Map<Object, Entry<?>> refs = new HashMap<>(); | 48 | private final Map<Object, Entry<?>> refs = new HashMap<>(); |
| 48 | private final TypeUsageInformation typeUsage; | 49 | private final TypeUsageInformation typeUsage; |
| 49 | private final MovableDumperContext dumperContext; | 50 | private final MovableDumperContext dumperContext; |
| 50 | private boolean muteLine = false; | 51 | private boolean muteLine = false; |
| 51 | private MethodEntry contextMethod = null; | 52 | private MethodEntry contextMethod = null; |
| 52 | 53 | ||
| 53 | public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, | 54 | public EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper) { |
| 54 | @Nullable EntryRemapper mapper) { | 55 | this(sb, sourceSettings, typeUsage, options, mapper, new SourceIndex(), new MovableDumperContext()); |
| 55 | this(sb, sourceSettings, typeUsage, options, mapper, new SourceIndex(), new MovableDumperContext()); | 56 | } |
| 56 | } | 57 | |
| 57 | 58 | protected EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, @Nullable EntryRemapper mapper, SourceIndex index, MovableDumperContext context) { | |
| 58 | protected EnigmaDumper(StringBuilder sb, SourceSettings sourceSettings, TypeUsageInformation typeUsage, Options options, | 59 | super((m, e) -> { |
| 59 | @Nullable EntryRemapper mapper, SourceIndex index, MovableDumperContext context) { | 60 | }, sb, typeUsage, options, IllegalIdentifierDump.Nop.getInstance(), context); |
| 60 | super((m, e) -> { | 61 | this.sb = sb; |
| 61 | }, sb, typeUsage, options, IllegalIdentifierDump.Nop.getInstance(), context); | 62 | this.sourceSettings = sourceSettings; |
| 62 | this.sb = sb; | 63 | this.typeUsage = typeUsage; |
| 63 | this.sourceSettings = sourceSettings; | 64 | this.mapper = mapper; |
| 64 | this.typeUsage = typeUsage; | 65 | this.dumperContext = context; |
| 65 | this.mapper = mapper; | 66 | this.index = index; |
| 66 | this.dumperContext = context; | 67 | } |
| 67 | this.index = index; | 68 | |
| 68 | } | 69 | private MethodEntry getMethodEntry(MethodPrototype method) { |
| 69 | 70 | if (method == null || method.getOwner() == null) { | |
| 70 | private MethodEntry getMethodEntry(MethodPrototype method) { | 71 | return null; |
| 71 | if (method == null || method.getOwner() == null) { | 72 | } |
| 72 | return null; | 73 | |
| 73 | } | 74 | MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); |
| 74 | 75 | ||
| 75 | MethodDescriptor desc = new MethodDescriptor(method.getOriginalDescriptor()); | 76 | return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc); |
| 76 | 77 | } | |
| 77 | return new MethodEntry(getClassEntry(method.getOwner()), method.getName(), desc); | 78 | |
| 78 | } | 79 | private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { |
| 79 | 80 | MethodEntry owner = getMethodEntry(method); | |
| 80 | private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) { | 81 | |
| 81 | MethodEntry owner = getMethodEntry(method); | 82 | // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet |
| 82 | // params may be not computed if cfr creates a lambda expression fallback, e.g. in PointOfInterestSet | 83 | if (owner == null || !method.parametersComputed()) { |
| 83 | if (owner == null || !method.parametersComputed()) { | 84 | return null; |
| 84 | return null; | 85 | } |
| 85 | } | 86 | |
| 86 | 87 | int variableIndex = method.getParameterLValues().get(parameterIndex).localVariable.getIdx(); | |
| 87 | int variableIndex = method.getParameterLValues().get(parameterIndex).localVariable.getIdx(); | 88 | |
| 88 | 89 | return new LocalVariableEntry(owner, variableIndex, name, true, null); | |
| 89 | return new LocalVariableEntry(owner, variableIndex, name, true, null); | 90 | } |
| 90 | } | 91 | |
| 91 | 92 | private FieldEntry getFieldEntry(JavaTypeInstance owner, String name, String desc) { | |
| 92 | private FieldEntry getFieldEntry(JavaTypeInstance owner, String name, String desc) { | 93 | return new FieldEntry(getClassEntry(owner), name, new TypeDescriptor(desc)); |
| 93 | return new FieldEntry(getClassEntry(owner), name, new TypeDescriptor(desc)); | 94 | } |
| 94 | } | 95 | |
| 95 | 96 | private ClassEntry getClassEntry(JavaTypeInstance type) { | |
| 96 | private ClassEntry getClassEntry(JavaTypeInstance type) { | 97 | return new ClassEntry(type.getRawName().replace('.', '/')); |
| 97 | return new ClassEntry(type.getRawName().replace('.', '/')); | 98 | } |
| 98 | } | 99 | |
| 99 | 100 | @Override | |
| 100 | @Override | 101 | public Dumper packageName(JavaRefTypeInstance t) { |
| 101 | public Dumper packageName(JavaRefTypeInstance t) { | 102 | if (sourceSettings.removeImports) { |
| 102 | if (sourceSettings.removeImports) { | 103 | return this; |
| 103 | return this; | 104 | } |
| 104 | } | 105 | |
| 105 | return super.packageName(t); | 106 | return super.packageName(t); |
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | @Override | 109 | @Override |
| 109 | public Dumper keyword(String s) { | 110 | public Dumper keyword(String s) { |
| 110 | if (sourceSettings.removeImports && s.startsWith("import")) { | 111 | if (sourceSettings.removeImports && s.startsWith("import")) { |
| 111 | muteLine = true; | 112 | muteLine = true; |
| 112 | return this; | 113 | return this; |
| 113 | } | 114 | } |
| 114 | return super.keyword(s); | 115 | |
| 115 | } | 116 | return super.keyword(s); |
| 116 | 117 | } | |
| 117 | @Override | 118 | |
| 118 | public Dumper endCodeln() { | 119 | @Override |
| 119 | if (muteLine) { | 120 | public Dumper endCodeln() { |
| 120 | muteLine = false; | 121 | if (muteLine) { |
| 121 | return this; | 122 | muteLine = false; |
| 122 | } | 123 | return this; |
| 123 | return super.endCodeln(); | 124 | } |
| 124 | } | 125 | |
| 125 | 126 | return super.endCodeln(); | |
| 126 | @Override | 127 | } |
| 127 | public Dumper print(String s) { | 128 | |
| 128 | if (muteLine) { | 129 | @Override |
| 129 | return this; | 130 | public Dumper print(String s) { |
| 130 | } | 131 | if (muteLine) { |
| 131 | return super.print(s); | 132 | return this; |
| 132 | } | 133 | } |
| 133 | 134 | ||
| 134 | @Override | 135 | return super.print(s); |
| 135 | public Dumper dumpClassDoc(JavaTypeInstance owner) { | 136 | } |
| 136 | if (mapper != null) { | 137 | |
| 137 | List<String> recordComponentDocs = new LinkedList<>(); | 138 | @Override |
| 138 | 139 | public Dumper dumpClassDoc(JavaTypeInstance owner) { | |
| 139 | if (isRecord(owner)) { | 140 | if (mapper != null) { |
| 140 | ClassFile classFile = ((JavaRefTypeInstance) owner).getClassFile(); | 141 | List<String> recordComponentDocs = new LinkedList<>(); |
| 141 | for (ClassFileField field : classFile.getFields()) { | 142 | |
| 142 | if (field.getField().testAccessFlag(AccessFlag.ACC_STATIC)) { | 143 | if (isRecord(owner)) { |
| 143 | continue; | 144 | ClassFile classFile = ((JavaRefTypeInstance) owner).getClassFile(); |
| 144 | } | 145 | |
| 145 | 146 | for (ClassFileField field : classFile.getFields()) { | |
| 146 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getField().getDescriptor())); | 147 | if (field.getField().testAccessFlag(AccessFlag.ACC_STATIC)) { |
| 147 | if (mapping == null) { | 148 | continue; |
| 148 | continue; | 149 | } |
| 149 | } | 150 | |
| 150 | 151 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getField().getDescriptor())); | |
| 151 | String javaDoc = mapping.javadoc(); | 152 | |
| 152 | if (javaDoc != null) { | 153 | if (mapping == null) { |
| 153 | recordComponentDocs.add(String.format("@param %s %s", mapping.targetName(), javaDoc)); | 154 | continue; |
| 154 | } | 155 | } |
| 155 | } | 156 | |
| 156 | } | 157 | String javaDoc = mapping.javadoc(); |
| 157 | 158 | ||
| 158 | EntryMapping mapping = mapper.getDeobfMapping(getClassEntry(owner)); | 159 | if (javaDoc != null) { |
| 159 | 160 | recordComponentDocs.add(String.format("@param %s %s", mapping.targetName(), javaDoc)); | |
| 160 | String javadoc = null; | 161 | } |
| 161 | if (mapping != null) { | 162 | } |
| 162 | javadoc = mapping.javadoc(); | 163 | } |
| 163 | } | 164 | |
| 164 | 165 | EntryMapping mapping = mapper.getDeobfMapping(getClassEntry(owner)); | |
| 165 | if (javadoc != null || !recordComponentDocs.isEmpty()) { | 166 | |
| 166 | print("/**").newln(); | 167 | String javadoc = null; |
| 167 | if (javadoc != null) { | 168 | |
| 168 | for (String line : javadoc.split("\\R")) { | 169 | if (mapping != null) { |
| 169 | print(" * ").print(line).newln(); | 170 | javadoc = mapping.javadoc(); |
| 170 | } | 171 | } |
| 171 | 172 | ||
| 172 | if (!recordComponentDocs.isEmpty()) { | 173 | if (javadoc != null || !recordComponentDocs.isEmpty()) { |
| 173 | print(" * ").newln(); | 174 | print("/**").newln(); |
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | for (String componentDoc : recordComponentDocs) { | ||
| 178 | print(" * ").print(componentDoc).newln(); | ||
| 179 | } | ||
| 180 | |||
| 181 | print(" */").newln(); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | return this; | ||
| 185 | } | ||
| 186 | |||
| 187 | @Override | ||
| 188 | public Dumper dumpMethodDoc(MethodPrototype method) { | ||
| 189 | if (mapper != null) { | ||
| 190 | List<String> lines = new ArrayList<>(); | ||
| 191 | MethodEntry methodEntry = getMethodEntry(method); | ||
| 192 | EntryMapping mapping = mapper.getDeobfMapping(methodEntry); | ||
| 193 | if (mapping != null) { | ||
| 194 | String javadoc = mapping.javadoc(); | ||
| 195 | if (javadoc != null) { | ||
| 196 | lines.addAll(Arrays.asList(javadoc.split("\\R"))); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | Collection<Entry<?>> children = mapper.getObfChildren(methodEntry); | ||
| 201 | |||
| 202 | if (children != null && !children.isEmpty()) { | ||
| 203 | for (Entry<?> each : children) { | ||
| 204 | if (each instanceof LocalVariableEntry) { | ||
| 205 | EntryMapping paramMapping = mapper.getDeobfMapping(each); | ||
| 206 | if (paramMapping != null) { | ||
| 207 | String javadoc = paramMapping.javadoc(); | ||
| 208 | if (javadoc != null) { | ||
| 209 | lines.addAll(Arrays.asList(("@param " + paramMapping.targetName() + " " + javadoc).split("\\R"))); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | if (!lines.isEmpty()) { | ||
| 217 | print("/**").newln(); | ||
| 218 | for (String line : lines) { | ||
| 219 | print(" * ").print(line).newln(); | ||
| 220 | } | ||
| 221 | print(" */").newln(); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | return this; | ||
| 225 | } | ||
| 226 | |||
| 227 | @Override | ||
| 228 | public Dumper dumpFieldDoc(Field field, JavaTypeInstance owner) { | ||
| 229 | boolean recordComponent = isRecord(owner) && !field.testAccessFlag(AccessFlag.ACC_STATIC); | ||
| 230 | if (mapper != null && !recordComponent) { | ||
| 231 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor())); | ||
| 232 | if (mapping != null) { | ||
| 233 | String javadoc = mapping.javadoc(); | ||
| 234 | if (javadoc != null) { | ||
| 235 | print("/**").newln(); | ||
| 236 | for (String line : javadoc.split("\\R")) { | ||
| 237 | print(" * ").print(line).newln(); | ||
| 238 | } | ||
| 239 | print(" */").newln(); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | } | ||
| 243 | return this; | ||
| 244 | } | ||
| 245 | |||
| 246 | @Override | ||
| 247 | public Dumper methodName(String name, MethodPrototype method, boolean special, boolean defines) { | ||
| 248 | Entry<?> entry = getMethodEntry(method); | ||
| 249 | super.methodName(name, method, special, defines); | ||
| 250 | int now = sb.length(); | ||
| 251 | Token token = new Token(now - name.length(), now, name); | ||
| 252 | |||
| 253 | if (entry != null) { | ||
| 254 | if (defines) { | ||
| 255 | index.addDeclaration(token, entry); // override as cfr reuses local vars | ||
| 256 | } else { | ||
| 257 | index.addReference(token, entry, contextMethod); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | return this; | ||
| 262 | } | ||
| 263 | |||
| 264 | @Override | ||
| 265 | public Dumper parameterName(String name, Object ref, MethodPrototype method, int index, boolean defines) { | ||
| 266 | super.parameterName(name, ref, method, index, defines); | ||
| 267 | int now = sb.length(); | ||
| 268 | Token token = new Token(now - name.length(), now, name); | ||
| 269 | Entry<?> entry; | ||
| 270 | if (defines) { | ||
| 271 | refs.put(ref, entry = getParameterEntry(method, index, name)); | ||
| 272 | } else { | ||
| 273 | entry = refs.get(ref); | ||
| 274 | } | ||
| 275 | |||
| 276 | if (entry != null) { | ||
| 277 | if (defines) { | ||
| 278 | this.index.addDeclaration(token, entry); | ||
| 279 | } else { | ||
| 280 | this.index.addReference(token, entry, contextMethod); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | return this; | ||
| 285 | } | ||
| 286 | |||
| 287 | @Override | ||
| 288 | public Dumper variableName(String name, NamedVariable variable, boolean defines) { | ||
| 289 | // todo catch var declarations in the future | ||
| 290 | return super.variableName(name, variable, defines); | ||
| 291 | } | ||
| 292 | |||
| 293 | @Override | ||
| 294 | public Dumper identifier(String name, Object ref, boolean defines) { | ||
| 295 | super.identifier(name, ref, defines); | ||
| 296 | Entry<?> entry; | ||
| 297 | if (defines) { | ||
| 298 | refs.remove(ref); | ||
| 299 | return this; | ||
| 300 | } | ||
| 301 | if ((entry = refs.get(ref)) == null) { | ||
| 302 | return this; | ||
| 303 | } | ||
| 304 | int now = sb.length(); | ||
| 305 | Token token = new Token(now - name.length(), now, name); | ||
| 306 | index.addReference(token, entry, contextMethod); | ||
| 307 | return this; | ||
| 308 | } | ||
| 309 | |||
| 310 | @Override | ||
| 311 | public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) { | ||
| 312 | super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines); | ||
| 313 | int now = sb.length(); | ||
| 314 | Token token = new Token(now - name.length(), now, name); | ||
| 315 | if (descriptor != null) { | ||
| 316 | Entry<?> entry = getFieldEntry(owner, name, descriptor); | ||
| 317 | |||
| 318 | if (defines) { | ||
| 319 | index.addDeclaration(token, entry); | ||
| 320 | } else { | ||
| 321 | index.addReference(token, entry, contextMethod); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | return this; | ||
| 326 | } | ||
| 327 | |||
| 328 | @Override | ||
| 329 | public Dumper dump(JavaTypeInstance type) { | ||
| 330 | dumpClass(TypeContext.None, type, false); | ||
| 331 | return this; | ||
| 332 | } | ||
| 333 | |||
| 334 | @Override | ||
| 335 | public Dumper dump(JavaTypeInstance type, boolean defines) { | ||
| 336 | dumpClass(TypeContext.None, type, defines); | ||
| 337 | return this; | ||
| 338 | } | ||
| 339 | |||
| 340 | @Override | ||
| 341 | public Dumper dump(JavaTypeInstance type, TypeContext context) { | ||
| 342 | dumpClass(context, type, false); | ||
| 343 | return this; | ||
| 344 | } | ||
| 345 | |||
| 346 | private void dumpClass(TypeContext context, JavaTypeInstance type, boolean defines) { | ||
| 347 | if (type instanceof JavaRefTypeInstance) { | ||
| 348 | type.dumpInto(this, typeUsage, context); | ||
| 349 | String name = typeUsage.getName(type, context); // the actually used name, dump will indent | ||
| 350 | int now = sb.length(); | ||
| 351 | Token token = new Token(now - name.length(), now, name); | ||
| 352 | |||
| 353 | if (defines) { | ||
| 354 | index.addDeclaration(token, getClassEntry(type)); | ||
| 355 | } else { | ||
| 356 | index.addReference(token, getClassEntry(type), contextMethod); | ||
| 357 | } | ||
| 358 | return; | ||
| 359 | } | ||
| 360 | |||
| 361 | type.dumpInto(this, typeUsage, context); | ||
| 362 | } | ||
| 363 | |||
| 364 | /** | ||
| 365 | * {@inheritDoc} | ||
| 366 | * | ||
| 367 | * <p>Otherwise the type usage override dumper will not go through the type instance dump | ||
| 368 | * we have here. | ||
| 369 | */ | ||
| 370 | @Override | ||
| 371 | public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) { | ||
| 372 | return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext); | ||
| 373 | } | ||
| 374 | |||
| 375 | @Override | ||
| 376 | public void informBytecodeLoc(HasByteCodeLoc loc) { | ||
| 377 | Collection<Method> methods = loc.getLoc().getMethods(); | ||
| 378 | if (!methods.isEmpty()) { | ||
| 379 | this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype()); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | public SourceIndex getIndex() { | ||
| 384 | index.setSource(getString()); | ||
| 385 | return index; | ||
| 386 | } | ||
| 387 | |||
| 388 | public String getString() { | ||
| 389 | return sb.toString(); | ||
| 390 | } | ||
| 391 | |||
| 392 | private boolean isRecord(JavaTypeInstance javaTypeInstance) { | ||
| 393 | if (javaTypeInstance instanceof JavaRefTypeInstance) { | ||
| 394 | ClassFile classFile = ((JavaRefTypeInstance) javaTypeInstance).getClassFile(); | ||
| 395 | return classFile.getClassSignature().getSuperClass().getRawName().equals("java.lang.Record"); | ||
| 396 | } | ||
| 397 | |||
| 398 | return false; | ||
| 399 | } | ||
| 400 | 175 | ||
| 176 | if (javadoc != null) { | ||
| 177 | for (String line : javadoc.split("\\R")) { | ||
| 178 | print(" * ").print(line).newln(); | ||
| 179 | } | ||
| 180 | |||
| 181 | if (!recordComponentDocs.isEmpty()) { | ||
| 182 | print(" * ").newln(); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | for (String componentDoc : recordComponentDocs) { | ||
| 187 | print(" * ").print(componentDoc).newln(); | ||
| 188 | } | ||
| 189 | |||
| 190 | print(" */").newln(); | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | return this; | ||
| 195 | } | ||
| 196 | |||
| 197 | @Override | ||
| 198 | public Dumper dumpMethodDoc(MethodPrototype method) { | ||
| 199 | if (mapper != null) { | ||
| 200 | List<String> lines = new ArrayList<>(); | ||
| 201 | MethodEntry methodEntry = getMethodEntry(method); | ||
| 202 | EntryMapping mapping = mapper.getDeobfMapping(methodEntry); | ||
| 203 | |||
| 204 | if (mapping != null) { | ||
| 205 | String javadoc = mapping.javadoc(); | ||
| 206 | |||
| 207 | if (javadoc != null) { | ||
| 208 | lines.addAll(Arrays.asList(javadoc.split("\\R"))); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | Collection<Entry<?>> children = mapper.getObfChildren(methodEntry); | ||
| 213 | |||
| 214 | if (children != null && !children.isEmpty()) { | ||
| 215 | for (Entry<?> each : children) { | ||
| 216 | if (each instanceof LocalVariableEntry) { | ||
| 217 | EntryMapping paramMapping = mapper.getDeobfMapping(each); | ||
| 218 | |||
| 219 | if (paramMapping != null) { | ||
| 220 | String javadoc = paramMapping.javadoc(); | ||
| 221 | |||
| 222 | if (javadoc != null) { | ||
| 223 | lines.addAll(Arrays.asList(("@param " + paramMapping.targetName() + " " + javadoc).split("\\R"))); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | if (!lines.isEmpty()) { | ||
| 231 | print("/**").newln(); | ||
| 232 | |||
| 233 | for (String line : lines) { | ||
| 234 | print(" * ").print(line).newln(); | ||
| 235 | } | ||
| 236 | |||
| 237 | print(" */").newln(); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | return this; | ||
| 242 | } | ||
| 243 | |||
| 244 | @Override | ||
| 245 | public Dumper dumpFieldDoc(Field field, JavaTypeInstance owner) { | ||
| 246 | boolean recordComponent = isRecord(owner) && !field.testAccessFlag(AccessFlag.ACC_STATIC); | ||
| 247 | |||
| 248 | if (mapper != null && !recordComponent) { | ||
| 249 | EntryMapping mapping = mapper.getDeobfMapping(getFieldEntry(owner, field.getFieldName(), field.getDescriptor())); | ||
| 250 | |||
| 251 | if (mapping != null) { | ||
| 252 | String javadoc = mapping.javadoc(); | ||
| 253 | |||
| 254 | if (javadoc != null) { | ||
| 255 | print("/**").newln(); | ||
| 256 | |||
| 257 | for (String line : javadoc.split("\\R")) { | ||
| 258 | print(" * ").print(line).newln(); | ||
| 259 | } | ||
| 260 | |||
| 261 | print(" */").newln(); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | return this; | ||
| 267 | } | ||
| 268 | |||
| 269 | @Override | ||
| 270 | public Dumper methodName(String name, MethodPrototype method, boolean special, boolean defines) { | ||
| 271 | Entry<?> entry = getMethodEntry(method); | ||
| 272 | super.methodName(name, method, special, defines); | ||
| 273 | int now = sb.length(); | ||
| 274 | Token token = new Token(now - name.length(), now, name); | ||
| 275 | |||
| 276 | if (entry != null) { | ||
| 277 | if (defines) { | ||
| 278 | index.addDeclaration(token, entry); // override as cfr reuses local vars | ||
| 279 | } else { | ||
| 280 | index.addReference(token, entry, contextMethod); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | return this; | ||
| 285 | } | ||
| 286 | |||
| 287 | @Override | ||
| 288 | public Dumper parameterName(String name, Object ref, MethodPrototype method, int index, boolean defines) { | ||
| 289 | super.parameterName(name, ref, method, index, defines); | ||
| 290 | int now = sb.length(); | ||
| 291 | Token token = new Token(now - name.length(), now, name); | ||
| 292 | Entry<?> entry; | ||
| 293 | |||
| 294 | if (defines) { | ||
| 295 | refs.put(ref, entry = getParameterEntry(method, index, name)); | ||
| 296 | } else { | ||
| 297 | entry = refs.get(ref); | ||
| 298 | } | ||
| 299 | |||
| 300 | if (entry != null) { | ||
| 301 | if (defines) { | ||
| 302 | this.index.addDeclaration(token, entry); | ||
| 303 | } else { | ||
| 304 | this.index.addReference(token, entry, contextMethod); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | return this; | ||
| 309 | } | ||
| 310 | |||
| 311 | @Override | ||
| 312 | public Dumper variableName(String name, NamedVariable variable, boolean defines) { | ||
| 313 | // todo catch var declarations in the future | ||
| 314 | return super.variableName(name, variable, defines); | ||
| 315 | } | ||
| 316 | |||
| 317 | @Override | ||
| 318 | public Dumper identifier(String name, Object ref, boolean defines) { | ||
| 319 | super.identifier(name, ref, defines); | ||
| 320 | Entry<?> entry; | ||
| 321 | |||
| 322 | if (defines) { | ||
| 323 | refs.remove(ref); | ||
| 324 | return this; | ||
| 325 | } | ||
| 326 | |||
| 327 | if ((entry = refs.get(ref)) == null) { | ||
| 328 | return this; | ||
| 329 | } | ||
| 330 | |||
| 331 | int now = sb.length(); | ||
| 332 | Token token = new Token(now - name.length(), now, name); | ||
| 333 | index.addReference(token, entry, contextMethod); | ||
| 334 | return this; | ||
| 335 | } | ||
| 336 | |||
| 337 | @Override | ||
| 338 | public Dumper fieldName(String name, String descriptor, JavaTypeInstance owner, boolean hiddenDeclaration, boolean isStatic, boolean defines) { | ||
| 339 | super.fieldName(name, descriptor, owner, hiddenDeclaration, isStatic, defines); | ||
| 340 | int now = sb.length(); | ||
| 341 | Token token = new Token(now - name.length(), now, name); | ||
| 342 | |||
| 343 | if (descriptor != null) { | ||
| 344 | Entry<?> entry = getFieldEntry(owner, name, descriptor); | ||
| 345 | |||
| 346 | if (defines) { | ||
| 347 | index.addDeclaration(token, entry); | ||
| 348 | } else { | ||
| 349 | index.addReference(token, entry, contextMethod); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | return this; | ||
| 354 | } | ||
| 355 | |||
| 356 | @Override | ||
| 357 | public Dumper dump(JavaTypeInstance type) { | ||
| 358 | dumpClass(TypeContext.None, type, false); | ||
| 359 | return this; | ||
| 360 | } | ||
| 361 | |||
| 362 | @Override | ||
| 363 | public Dumper dump(JavaTypeInstance type, boolean defines) { | ||
| 364 | dumpClass(TypeContext.None, type, defines); | ||
| 365 | return this; | ||
| 366 | } | ||
| 367 | |||
| 368 | @Override | ||
| 369 | public Dumper dump(JavaTypeInstance type, TypeContext context) { | ||
| 370 | dumpClass(context, type, false); | ||
| 371 | return this; | ||
| 372 | } | ||
| 373 | |||
| 374 | private void dumpClass(TypeContext context, JavaTypeInstance type, boolean defines) { | ||
| 375 | if (type instanceof JavaRefTypeInstance) { | ||
| 376 | type.dumpInto(this, typeUsage, context); | ||
| 377 | String name = typeUsage.getName(type, context); // the actually used name, dump will indent | ||
| 378 | int now = sb.length(); | ||
| 379 | Token token = new Token(now - name.length(), now, name); | ||
| 380 | |||
| 381 | if (defines) { | ||
| 382 | index.addDeclaration(token, getClassEntry(type)); | ||
| 383 | } else { | ||
| 384 | index.addReference(token, getClassEntry(type), contextMethod); | ||
| 385 | } | ||
| 386 | |||
| 387 | return; | ||
| 388 | } | ||
| 389 | |||
| 390 | type.dumpInto(this, typeUsage, context); | ||
| 391 | } | ||
| 392 | |||
| 393 | /** | ||
| 394 | * {@inheritDoc} | ||
| 395 | * | ||
| 396 | * <p>Otherwise the type usage override dumper will not go through the type instance dump | ||
| 397 | * we have here. | ||
| 398 | */ | ||
| 399 | @Override | ||
| 400 | public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) { | ||
| 401 | return new EnigmaDumper(this.sb, sourceSettings, innerclassTypeUsageInformation, options, mapper, index, dumperContext); | ||
| 402 | } | ||
| 403 | |||
| 404 | @Override | ||
| 405 | public void informBytecodeLoc(HasByteCodeLoc loc) { | ||
| 406 | Collection<Method> methods = loc.getLoc().getMethods(); | ||
| 407 | |||
| 408 | if (!methods.isEmpty()) { | ||
| 409 | this.contextMethod = getMethodEntry(methods.iterator().next().getMethodPrototype()); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | public SourceIndex getIndex() { | ||
| 414 | index.setSource(getString()); | ||
| 415 | return index; | ||
| 416 | } | ||
| 417 | |||
| 418 | public String getString() { | ||
| 419 | return sb.toString(); | ||
| 420 | } | ||
| 421 | |||
| 422 | private boolean isRecord(JavaTypeInstance javaTypeInstance) { | ||
| 423 | if (javaTypeInstance instanceof JavaRefTypeInstance) { | ||
| 424 | ClassFile classFile = ((JavaRefTypeInstance) javaTypeInstance).getClassFile(); | ||
| 425 | return classFile.getClassSignature().getSuperClass().getRawName().equals("java.lang.Record"); | ||
| 426 | } | ||
| 427 | |||
| 428 | return false; | ||
| 429 | } | ||
| 401 | } | 430 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java index 2fae61a6..dade7c6c 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/EntryParser.java | |||
| @@ -4,6 +4,7 @@ import com.strobel.assembler.metadata.FieldDefinition; | |||
| 4 | import com.strobel.assembler.metadata.MethodDefinition; | 4 | import com.strobel.assembler.metadata.MethodDefinition; |
| 5 | import com.strobel.assembler.metadata.TypeDefinition; | 5 | import com.strobel.assembler.metadata.TypeDefinition; |
| 6 | import com.strobel.assembler.metadata.TypeReference; | 6 | import com.strobel.assembler.metadata.TypeReference; |
| 7 | |||
| 7 | import cuchaz.enigma.translation.representation.AccessFlags; | 8 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 8 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 9 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 9 | import cuchaz.enigma.translation.representation.Signature; | 10 | import cuchaz.enigma.translation.representation.Signature; |
| @@ -14,36 +15,36 @@ import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | |||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 15 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 15 | 16 | ||
| 16 | public class EntryParser { | 17 | public class EntryParser { |
| 17 | public static FieldDefEntry parse(FieldDefinition definition) { | 18 | public static FieldDefEntry parse(FieldDefinition definition) { |
| 18 | ClassEntry owner = parse(definition.getDeclaringType()); | 19 | ClassEntry owner = parse(definition.getDeclaringType()); |
| 19 | TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature()); | 20 | TypeDescriptor descriptor = new TypeDescriptor(definition.getErasedSignature()); |
| 20 | Signature signature = Signature.createTypedSignature(definition.getSignature()); | 21 | Signature signature = Signature.createTypedSignature(definition.getSignature()); |
| 21 | AccessFlags access = new AccessFlags(definition.getModifiers()); | 22 | AccessFlags access = new AccessFlags(definition.getModifiers()); |
| 22 | return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null); | 23 | return new FieldDefEntry(owner, definition.getName(), descriptor, signature, access, null); |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | public static ClassDefEntry parse(TypeDefinition def) { | 26 | public static ClassDefEntry parse(TypeDefinition def) { |
| 26 | String name = def.getInternalName(); | 27 | String name = def.getInternalName(); |
| 27 | Signature signature = Signature.createSignature(def.getSignature()); | 28 | Signature signature = Signature.createSignature(def.getSignature()); |
| 28 | AccessFlags access = new AccessFlags(def.getModifiers()); | 29 | AccessFlags access = new AccessFlags(def.getModifiers()); |
| 29 | ClassEntry superClass = def.getBaseType() != null ? parse(def.getBaseType()) : null; | 30 | ClassEntry superClass = def.getBaseType() != null ? parse(def.getBaseType()) : null; |
| 30 | ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(EntryParser::parse).toArray(ClassEntry[]::new); | 31 | ClassEntry[] interfaces = def.getExplicitInterfaces().stream().map(EntryParser::parse).toArray(ClassEntry[]::new); |
| 31 | return new ClassDefEntry(name, signature, access, superClass, interfaces); | 32 | return new ClassDefEntry(name, signature, access, superClass, interfaces); |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | public static ClassEntry parse(TypeReference typeReference) { | 35 | public static ClassEntry parse(TypeReference typeReference) { |
| 35 | return new ClassEntry(typeReference.getInternalName()); | 36 | return new ClassEntry(typeReference.getInternalName()); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | public static MethodDefEntry parse(MethodDefinition definition) { | 39 | public static MethodDefEntry parse(MethodDefinition definition) { |
| 39 | ClassEntry classEntry = parse(definition.getDeclaringType()); | 40 | ClassEntry classEntry = parse(definition.getDeclaringType()); |
| 40 | MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature()); | 41 | MethodDescriptor descriptor = new MethodDescriptor(definition.getErasedSignature()); |
| 41 | Signature signature = Signature.createSignature(definition.getSignature()); | 42 | Signature signature = Signature.createSignature(definition.getSignature()); |
| 42 | AccessFlags access = new AccessFlags(definition.getModifiers()); | 43 | AccessFlags access = new AccessFlags(definition.getModifiers()); |
| 43 | return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null); | 44 | return new MethodDefEntry(classEntry, definition.getName(), descriptor, signature, access, null); |
| 44 | } | 45 | } |
| 45 | 46 | ||
| 46 | public static TypeDescriptor parseTypeDescriptor(TypeReference type) { | 47 | public static TypeDescriptor parseTypeDescriptor(TypeReference type) { |
| 47 | return new TypeDescriptor(type.getErasedSignature()); | 48 | return new TypeDescriptor(type.getErasedSignature()); |
| 48 | } | 49 | } |
| 49 | } | 50 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java index bc3d0725..3ba112ff 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java | |||
| @@ -11,15 +11,23 @@ import com.strobel.decompiler.languages.java.JavaFormattingOptions; | |||
| 11 | import com.strobel.decompiler.languages.java.ast.AstBuilder; | 11 | import com.strobel.decompiler.languages.java.ast.AstBuilder; |
| 12 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | 12 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; |
| 13 | import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; | 13 | import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; |
| 14 | import org.checkerframework.checker.nullness.qual.Nullable; | ||
| 15 | import org.objectweb.asm.tree.ClassNode; | ||
| 16 | |||
| 14 | import cuchaz.enigma.classprovider.ClassProvider; | 17 | import cuchaz.enigma.classprovider.ClassProvider; |
| 15 | import cuchaz.enigma.source.Source; | ||
| 16 | import cuchaz.enigma.source.Decompiler; | 18 | import cuchaz.enigma.source.Decompiler; |
| 19 | import cuchaz.enigma.source.Source; | ||
| 17 | import cuchaz.enigma.source.SourceSettings; | 20 | import cuchaz.enigma.source.SourceSettings; |
| 18 | import cuchaz.enigma.source.procyon.transformers.*; | 21 | import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform; |
| 22 | import cuchaz.enigma.source.procyon.transformers.DropImportAstTransform; | ||
| 23 | import cuchaz.enigma.source.procyon.transformers.DropVarModifiersAstTransform; | ||
| 24 | import cuchaz.enigma.source.procyon.transformers.InvalidIdentifierFix; | ||
| 25 | import cuchaz.enigma.source.procyon.transformers.Java8Generics; | ||
| 26 | import cuchaz.enigma.source.procyon.transformers.ObfuscatedEnumSwitchRewriterTransform; | ||
| 27 | import cuchaz.enigma.source.procyon.transformers.RemoveObjectCasts; | ||
| 28 | import cuchaz.enigma.source.procyon.transformers.VarargsFixer; | ||
| 19 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 29 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 20 | import cuchaz.enigma.utils.AsmUtil; | 30 | import cuchaz.enigma.utils.AsmUtil; |
| 21 | import org.checkerframework.checker.nullness.qual.Nullable; | ||
| 22 | import org.objectweb.asm.tree.ClassNode; | ||
| 23 | 31 | ||
| 24 | public class ProcyonDecompiler implements Decompiler { | 32 | public class ProcyonDecompiler implements Decompiler { |
| 25 | private final SourceSettings settings; | 33 | private final SourceSettings settings; |
| @@ -63,6 +71,7 @@ public class ProcyonDecompiler implements Decompiler { | |||
| 63 | @Override | 71 | @Override |
| 64 | public Source getSource(String className, @Nullable EntryRemapper remapper) { | 72 | public Source getSource(String className, @Nullable EntryRemapper remapper) { |
| 65 | TypeReference type = metadataSystem.lookupType(className); | 73 | TypeReference type = metadataSystem.lookupType(className); |
| 74 | |||
| 66 | if (type == null) { | 75 | if (type == null) { |
| 67 | throw new Error(String.format("Unable to find desc: %s", className)); | 76 | throw new Error(String.format("Unable to find desc: %s", className)); |
| 68 | } | 77 | } |
| @@ -83,8 +92,15 @@ public class ProcyonDecompiler implements Decompiler { | |||
| 83 | new RemoveObjectCasts(context).run(source); | 92 | new RemoveObjectCasts(context).run(source); |
| 84 | new Java8Generics().run(source); | 93 | new Java8Generics().run(source); |
| 85 | new InvalidIdentifierFix().run(source); | 94 | new InvalidIdentifierFix().run(source); |
| 86 | if (settings.removeImports) DropImportAstTransform.INSTANCE.run(source); | 95 | |
| 87 | if (settings.removeVariableFinal) DropVarModifiersAstTransform.INSTANCE.run(source); | 96 | if (settings.removeImports) { |
| 97 | DropImportAstTransform.INSTANCE.run(source); | ||
| 98 | } | ||
| 99 | |||
| 100 | if (settings.removeVariableFinal) { | ||
| 101 | DropVarModifiersAstTransform.INSTANCE.run(source); | ||
| 102 | } | ||
| 103 | |||
| 88 | source.acceptVisitor(new InsertParenthesesVisitor(), null); | 104 | source.acceptVisitor(new InsertParenthesesVisitor(), null); |
| 89 | 105 | ||
| 90 | if (remapper != null) { | 106 | if (remapper != null) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java index 5b5b70e8..a3f878b8 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonSource.java | |||
| @@ -1,49 +1,50 @@ | |||
| 1 | package cuchaz.enigma.source.procyon; | 1 | package cuchaz.enigma.source.procyon; |
| 2 | 2 | ||
| 3 | import java.io.StringWriter; | ||
| 4 | |||
| 3 | import com.strobel.decompiler.DecompilerSettings; | 5 | import com.strobel.decompiler.DecompilerSettings; |
| 4 | import com.strobel.decompiler.PlainTextOutput; | 6 | import com.strobel.decompiler.PlainTextOutput; |
| 5 | import com.strobel.decompiler.languages.java.JavaOutputVisitor; | 7 | import com.strobel.decompiler.languages.java.JavaOutputVisitor; |
| 6 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | 8 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; |
| 9 | |||
| 7 | import cuchaz.enigma.source.Source; | 10 | import cuchaz.enigma.source.Source; |
| 8 | import cuchaz.enigma.source.SourceIndex; | 11 | import cuchaz.enigma.source.SourceIndex; |
| 9 | import cuchaz.enigma.source.procyon.index.SourceIndexVisitor; | 12 | import cuchaz.enigma.source.procyon.index.SourceIndexVisitor; |
| 10 | import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform; | 13 | import cuchaz.enigma.source.procyon.transformers.AddJavadocsAstTransform; |
| 11 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 14 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 12 | 15 | ||
| 13 | import java.io.StringWriter; | ||
| 14 | |||
| 15 | public class ProcyonSource implements Source { | 16 | public class ProcyonSource implements Source { |
| 16 | private final DecompilerSettings settings; | 17 | private final DecompilerSettings settings; |
| 17 | private final CompilationUnit tree; | 18 | private final CompilationUnit tree; |
| 18 | private String string; | 19 | private String string; |
| 19 | 20 | ||
| 20 | public ProcyonSource(CompilationUnit tree, DecompilerSettings settings) { | 21 | public ProcyonSource(CompilationUnit tree, DecompilerSettings settings) { |
| 21 | this.settings = settings; | 22 | this.settings = settings; |
| 22 | this.tree = tree; | 23 | this.tree = tree; |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | @Override | 26 | @Override |
| 26 | public SourceIndex index() { | 27 | public SourceIndex index() { |
| 27 | SourceIndex index = new SourceIndex(asString()); | 28 | SourceIndex index = new SourceIndex(asString()); |
| 28 | tree.acceptVisitor(new SourceIndexVisitor(), index); | 29 | tree.acceptVisitor(new SourceIndexVisitor(), index); |
| 29 | return index; | 30 | return index; |
| 30 | } | 31 | } |
| 31 | 32 | ||
| 32 | @Override | 33 | @Override |
| 33 | public String asString() { | 34 | public String asString() { |
| 34 | if (string == null) { | 35 | if (string == null) { |
| 35 | StringWriter writer = new StringWriter(); | 36 | StringWriter writer = new StringWriter(); |
| 36 | tree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); | 37 | tree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(writer), settings), null); |
| 37 | string = writer.toString(); | 38 | string = writer.toString(); |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | return string; | 41 | return string; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | @Override | 44 | @Override |
| 44 | public Source withJavadocs(EntryRemapper remapper) { | 45 | public Source withJavadocs(EntryRemapper remapper) { |
| 45 | CompilationUnit remappedTree = (CompilationUnit) tree.clone(); | 46 | CompilationUnit remappedTree = (CompilationUnit) tree.clone(); |
| 46 | new AddJavadocsAstTransform(remapper).run(remappedTree); | 47 | new AddJavadocsAstTransform(remapper).run(remappedTree); |
| 47 | return new ProcyonSource(remappedTree, settings); | 48 | return new ProcyonSource(remappedTree, settings); |
| 48 | } | 49 | } |
| 49 | } | 50 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java index f6eeb159..174431f6 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexClassVisitor.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.source.procyon.index; | 12 | package cuchaz.enigma.source.procyon.index; |
| 13 | 13 | ||
| @@ -16,10 +16,22 @@ import com.strobel.assembler.metadata.MethodDefinition; | |||
| 16 | import com.strobel.assembler.metadata.TypeDefinition; | 16 | import com.strobel.assembler.metadata.TypeDefinition; |
| 17 | import com.strobel.assembler.metadata.TypeReference; | 17 | import com.strobel.assembler.metadata.TypeReference; |
| 18 | import com.strobel.decompiler.languages.TextLocation; | 18 | import com.strobel.decompiler.languages.TextLocation; |
| 19 | import com.strobel.decompiler.languages.java.ast.*; | 19 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 20 | import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; | ||
| 21 | import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; | ||
| 22 | import com.strobel.decompiler.languages.java.ast.FieldDeclaration; | ||
| 23 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 24 | import com.strobel.decompiler.languages.java.ast.MethodDeclaration; | ||
| 25 | import com.strobel.decompiler.languages.java.ast.SimpleType; | ||
| 26 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | ||
| 27 | import com.strobel.decompiler.languages.java.ast.VariableInitializer; | ||
| 28 | |||
| 20 | import cuchaz.enigma.source.SourceIndex; | 29 | import cuchaz.enigma.source.SourceIndex; |
| 21 | import cuchaz.enigma.source.procyon.EntryParser; | 30 | import cuchaz.enigma.source.procyon.EntryParser; |
| 22 | import cuchaz.enigma.translation.representation.entry.*; | 31 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| 32 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 33 | import cuchaz.enigma.translation.representation.entry.FieldDefEntry; | ||
| 34 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | ||
| 23 | 35 | ||
| 24 | public class SourceIndexClassVisitor extends SourceIndexVisitor { | 36 | public class SourceIndexClassVisitor extends SourceIndexVisitor { |
| 25 | private ClassDefEntry classEntry; | 37 | private ClassDefEntry classEntry; |
| @@ -33,6 +45,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { | |||
| 33 | // is this this class, or a subtype? | 45 | // is this this class, or a subtype? |
| 34 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); | 46 | TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); |
| 35 | ClassDefEntry classEntry = EntryParser.parse(def); | 47 | ClassDefEntry classEntry = EntryParser.parse(def); |
| 48 | |||
| 36 | if (!classEntry.equals(this.classEntry)) { | 49 | if (!classEntry.equals(this.classEntry)) { |
| 37 | // it's a subtype, recurse | 50 | // it's a subtype, recurse |
| 38 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry); | 51 | index.addDeclaration(TokenFactory.createToken(index, node.getNameToken()), classEntry); |
| @@ -45,6 +58,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { | |||
| 45 | @Override | 58 | @Override |
| 46 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | 59 | public Void visitSimpleType(SimpleType node, SourceIndex index) { |
| 47 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | 60 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); |
| 61 | |||
| 48 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | 62 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { |
| 49 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | 63 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); |
| 50 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.classEntry); | 64 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.classEntry); |
| @@ -58,10 +72,12 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { | |||
| 58 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | 72 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); |
| 59 | MethodDefEntry methodEntry = EntryParser.parse(def); | 73 | MethodDefEntry methodEntry = EntryParser.parse(def); |
| 60 | AstNode tokenNode = node.getNameToken(); | 74 | AstNode tokenNode = node.getNameToken(); |
| 75 | |||
| 61 | if (methodEntry.isConstructor() && methodEntry.getName().equals("<clinit>")) { | 76 | if (methodEntry.isConstructor() && methodEntry.getName().equals("<clinit>")) { |
| 62 | // for static initializers, check elsewhere for the token node | 77 | // for static initializers, check elsewhere for the token node |
| 63 | tokenNode = node.getModifiers().firstOrNullObject(); | 78 | tokenNode = node.getModifiers().firstOrNullObject(); |
| 64 | } | 79 | } |
| 80 | |||
| 65 | index.addDeclaration(TokenFactory.createToken(index, tokenNode), methodEntry); | 81 | index.addDeclaration(TokenFactory.createToken(index, tokenNode), methodEntry); |
| 66 | return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); | 82 | return node.acceptVisitor(new SourceIndexMethodVisitor(methodEntry), index); |
| 67 | } | 83 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java index 8fc8e82a..12dca73e 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexMethodVisitor.java | |||
| @@ -1,31 +1,56 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.source.procyon.index; | 12 | package cuchaz.enigma.source.procyon.index; |
| 13 | 13 | ||
| 14 | import java.util.HashMap; | ||
| 15 | import java.util.Map; | ||
| 16 | |||
| 14 | import com.google.common.collect.HashMultimap; | 17 | import com.google.common.collect.HashMultimap; |
| 15 | import com.google.common.collect.Multimap; | 18 | import com.google.common.collect.Multimap; |
| 16 | import com.strobel.assembler.metadata.*; | 19 | import com.strobel.assembler.metadata.FieldReference; |
| 20 | import com.strobel.assembler.metadata.MemberReference; | ||
| 21 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 22 | import com.strobel.assembler.metadata.MethodReference; | ||
| 23 | import com.strobel.assembler.metadata.ParameterDefinition; | ||
| 24 | import com.strobel.assembler.metadata.TypeReference; | ||
| 25 | import com.strobel.assembler.metadata.VariableDefinition; | ||
| 17 | import com.strobel.decompiler.ast.Variable; | 26 | import com.strobel.decompiler.ast.Variable; |
| 18 | import com.strobel.decompiler.languages.TextLocation; | 27 | import com.strobel.decompiler.languages.TextLocation; |
| 19 | import com.strobel.decompiler.languages.java.ast.*; | 28 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 29 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; | ||
| 30 | import com.strobel.decompiler.languages.java.ast.Identifier; | ||
| 31 | import com.strobel.decompiler.languages.java.ast.IdentifierExpression; | ||
| 32 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | ||
| 33 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 34 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; | ||
| 35 | import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; | ||
| 36 | import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; | ||
| 37 | import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; | ||
| 38 | import com.strobel.decompiler.languages.java.ast.SimpleType; | ||
| 39 | import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; | ||
| 40 | import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; | ||
| 41 | import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; | ||
| 42 | import com.strobel.decompiler.languages.java.ast.VariableInitializer; | ||
| 43 | |||
| 20 | import cuchaz.enigma.source.SourceIndex; | 44 | import cuchaz.enigma.source.SourceIndex; |
| 21 | import cuchaz.enigma.source.procyon.EntryParser; | 45 | import cuchaz.enigma.source.procyon.EntryParser; |
| 22 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 46 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 23 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 47 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 24 | import cuchaz.enigma.translation.representation.entry.*; | 48 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 25 | 49 | import cuchaz.enigma.translation.representation.entry.Entry; | |
| 26 | import java.lang.Error; | 50 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 27 | import java.util.HashMap; | 51 | import cuchaz.enigma.translation.representation.entry.LocalVariableDefEntry; |
| 28 | import java.util.Map; | 52 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 53 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 29 | 54 | ||
| 30 | public class SourceIndexMethodVisitor extends SourceIndexVisitor { | 55 | public class SourceIndexMethodVisitor extends SourceIndexVisitor { |
| 31 | private final MethodDefEntry methodEntry; | 56 | private final MethodDefEntry methodEntry; |
| @@ -45,12 +70,15 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 45 | // get the behavior entry | 70 | // get the behavior entry |
| 46 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 71 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 47 | MethodEntry methodEntry = null; | 72 | MethodEntry methodEntry = null; |
| 73 | |||
| 48 | if (ref instanceof MethodReference) { | 74 | if (ref instanceof MethodReference) { |
| 49 | methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); | 75 | methodEntry = new MethodEntry(classEntry, ref.getName(), new MethodDescriptor(ref.getErasedSignature())); |
| 50 | } | 76 | } |
| 77 | |||
| 51 | if (methodEntry != null) { | 78 | if (methodEntry != null) { |
| 52 | // get the node for the token | 79 | // get the node for the token |
| 53 | AstNode tokenNode = null; | 80 | AstNode tokenNode = null; |
| 81 | |||
| 54 | if (node.getTarget() instanceof MemberReferenceExpression) { | 82 | if (node.getTarget() instanceof MemberReferenceExpression) { |
| 55 | tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); | 83 | tokenNode = ((MemberReferenceExpression) node.getTarget()).getMemberNameToken(); |
| 56 | } else if (node.getTarget() instanceof SuperReferenceExpression) { | 84 | } else if (node.getTarget() instanceof SuperReferenceExpression) { |
| @@ -58,6 +86,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 58 | } else if (node.getTarget() instanceof ThisReferenceExpression) { | 86 | } else if (node.getTarget() instanceof ThisReferenceExpression) { |
| 59 | tokenNode = node.getTarget(); | 87 | tokenNode = node.getTarget(); |
| 60 | } | 88 | } |
| 89 | |||
| 61 | if (tokenNode != null) { | 90 | if (tokenNode != null) { |
| 62 | index.addReference(TokenFactory.createToken(index, tokenNode), methodEntry, this.methodEntry); | 91 | index.addReference(TokenFactory.createToken(index, tokenNode), methodEntry, this.methodEntry); |
| 63 | } | 92 | } |
| @@ -65,17 +94,18 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 65 | } | 94 | } |
| 66 | 95 | ||
| 67 | // Check for identifier | 96 | // Check for identifier |
| 68 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) | 97 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression).forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); |
| 69 | .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); | ||
| 70 | return visitChildren(node, index); | 98 | return visitChildren(node, index); |
| 71 | } | 99 | } |
| 72 | 100 | ||
| 73 | @Override | 101 | @Override |
| 74 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { | 102 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { |
| 75 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 103 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 104 | |||
| 76 | if (ref instanceof FieldReference) { | 105 | if (ref instanceof FieldReference) { |
| 77 | // make sure this is actually a field | 106 | // make sure this is actually a field |
| 78 | String erasedSignature = ref.getErasedSignature(); | 107 | String erasedSignature = ref.getErasedSignature(); |
| 108 | |||
| 79 | if (erasedSignature.indexOf('(') >= 0) { | 109 | if (erasedSignature.indexOf('(') >= 0) { |
| 80 | throw new Error("Expected a field here! got " + ref); | 110 | throw new Error("Expected a field here! got " + ref); |
| 81 | } | 111 | } |
| @@ -91,6 +121,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 91 | @Override | 121 | @Override |
| 92 | public Void visitSimpleType(SimpleType node, SourceIndex index) { | 122 | public Void visitSimpleType(SimpleType node, SourceIndex index) { |
| 93 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); | 123 | TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); |
| 124 | |||
| 94 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { | 125 | if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { |
| 95 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); | 126 | ClassEntry classEntry = new ClassEntry(ref.getInternalName()); |
| 96 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.methodEntry); | 127 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), classEntry, this.methodEntry); |
| @@ -106,6 +137,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 106 | 137 | ||
| 107 | if (parameterIndex >= 0) { | 138 | if (parameterIndex >= 0) { |
| 108 | MethodDefEntry ownerMethod = methodEntry; | 139 | MethodDefEntry ownerMethod = methodEntry; |
| 140 | |||
| 109 | if (def.getMethod() instanceof MethodDefinition) { | 141 | if (def.getMethod() instanceof MethodDefinition) { |
| 110 | ownerMethod = EntryParser.parse((MethodDefinition) def.getMethod()); | 142 | ownerMethod = EntryParser.parse((MethodDefinition) def.getMethod()); |
| 111 | } | 143 | } |
| @@ -124,36 +156,46 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 124 | @Override | 156 | @Override |
| 125 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { | 157 | public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { |
| 126 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 158 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 159 | |||
| 127 | if (ref != null) { | 160 | if (ref != null) { |
| 128 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 161 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| 129 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature())); | 162 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new TypeDescriptor(ref.getErasedSignature())); |
| 130 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), fieldEntry, this.methodEntry); | 163 | index.addReference(TokenFactory.createToken(index, node.getIdentifierToken()), fieldEntry, this.methodEntry); |
| 131 | } else | 164 | } else { |
| 132 | this.checkIdentifier(node, index); | 165 | this.checkIdentifier(node, index); |
| 166 | } | ||
| 167 | |||
| 133 | return visitChildren(node, index); | 168 | return visitChildren(node, index); |
| 134 | } | 169 | } |
| 135 | 170 | ||
| 136 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) { | 171 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) { |
| 137 | if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | 172 | if (identifierEntryCache.containsKey(node.getIdentifier())) { |
| 173 | // If it's in the argument cache, create a token! | ||
| 138 | index.addDeclaration(TokenFactory.createToken(index, node.getIdentifierToken()), identifierEntryCache.get(node.getIdentifier())); | 174 | index.addDeclaration(TokenFactory.createToken(index, node.getIdentifierToken()), identifierEntryCache.get(node.getIdentifier())); |
| 139 | else | 175 | } else { |
| 140 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! | 176 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! |
| 177 | } | ||
| 141 | } | 178 | } |
| 142 | 179 | ||
| 143 | private void addDeclarationToUnmatched(String key, SourceIndex index) { | 180 | private void addDeclarationToUnmatched(String key, SourceIndex index) { |
| 144 | Entry<?> entry = identifierEntryCache.get(key); | 181 | Entry<?> entry = identifierEntryCache.get(key); |
| 145 | 182 | ||
| 146 | // This cannot happened in theory | 183 | // This cannot happened in theory |
| 147 | if (entry == null) | 184 | if (entry == null) { |
| 148 | return; | 185 | return; |
| 149 | for (Identifier identifier : unmatchedIdentifier.get(key)) | 186 | } |
| 187 | |||
| 188 | for (Identifier identifier : unmatchedIdentifier.get(key)) { | ||
| 150 | index.addDeclaration(TokenFactory.createToken(index, identifier), entry); | 189 | index.addDeclaration(TokenFactory.createToken(index, identifier), entry); |
| 190 | } | ||
| 191 | |||
| 151 | unmatchedIdentifier.removeAll(key); | 192 | unmatchedIdentifier.removeAll(key); |
| 152 | } | 193 | } |
| 153 | 194 | ||
| 154 | @Override | 195 | @Override |
| 155 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { | 196 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { |
| 156 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 197 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| 198 | |||
| 157 | if (ref != null && node.getType() instanceof SimpleType) { | 199 | if (ref != null && node.getType() instanceof SimpleType) { |
| 158 | SimpleType simpleTypeNode = (SimpleType) node.getType(); | 200 | SimpleType simpleTypeNode = (SimpleType) node.getType(); |
| 159 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); | 201 | ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); |
| @@ -171,13 +213,17 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 171 | // Single assignation | 213 | // Single assignation |
| 172 | if (variables.size() == 1) { | 214 | if (variables.size() == 1) { |
| 173 | VariableInitializer initializer = variables.firstOrNullObject(); | 215 | VariableInitializer initializer = variables.firstOrNullObject(); |
| 216 | |||
| 174 | if (initializer != null && node.getType() instanceof SimpleType) { | 217 | if (initializer != null && node.getType() instanceof SimpleType) { |
| 175 | Identifier identifier = initializer.getNameToken(); | 218 | Identifier identifier = initializer.getNameToken(); |
| 176 | Variable variable = initializer.getUserData(Keys.VARIABLE); | 219 | Variable variable = initializer.getUserData(Keys.VARIABLE); |
| 220 | |||
| 177 | if (variable != null) { | 221 | if (variable != null) { |
| 178 | VariableDefinition originalVariable = variable.getOriginalVariable(); | 222 | VariableDefinition originalVariable = variable.getOriginalVariable(); |
| 223 | |||
| 179 | if (originalVariable != null) { | 224 | if (originalVariable != null) { |
| 180 | int variableIndex = originalVariable.getSlot(); | 225 | int variableIndex = originalVariable.getSlot(); |
| 226 | |||
| 181 | if (variableIndex >= 0) { | 227 | if (variableIndex >= 0) { |
| 182 | MethodDefEntry ownerMethod = EntryParser.parse(originalVariable.getDeclaringMethod()); | 228 | MethodDefEntry ownerMethod = EntryParser.parse(originalVariable.getDeclaringMethod()); |
| 183 | TypeDescriptor variableType = EntryParser.parseTypeDescriptor(originalVariable.getVariableType()); | 229 | TypeDescriptor variableType = EntryParser.parseTypeDescriptor(originalVariable.getVariableType()); |
| @@ -190,6 +236,7 @@ public class SourceIndexMethodVisitor extends SourceIndexVisitor { | |||
| 190 | } | 236 | } |
| 191 | } | 237 | } |
| 192 | } | 238 | } |
| 239 | |||
| 193 | return visitChildren(node, index); | 240 | return visitChildren(node, index); |
| 194 | } | 241 | } |
| 195 | 242 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java index dad505f7..56450c77 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/SourceIndexVisitor.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.source.procyon.index; | 12 | package cuchaz.enigma.source.procyon.index; |
| 13 | 13 | ||
| @@ -16,6 +16,7 @@ import com.strobel.decompiler.languages.java.ast.AstNode; | |||
| 16 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | 16 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; |
| 17 | import com.strobel.decompiler.languages.java.ast.Keys; | 17 | import com.strobel.decompiler.languages.java.ast.Keys; |
| 18 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | 18 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; |
| 19 | |||
| 19 | import cuchaz.enigma.source.SourceIndex; | 20 | import cuchaz.enigma.source.SourceIndex; |
| 20 | import cuchaz.enigma.source.procyon.EntryParser; | 21 | import cuchaz.enigma.source.procyon.EntryParser; |
| 21 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; | 22 | import cuchaz.enigma.translation.representation.entry.ClassDefEntry; |
| @@ -35,6 +36,7 @@ public class SourceIndexVisitor extends DepthFirstAstVisitor<SourceIndex, Void> | |||
| 35 | for (final AstNode child : node.getChildren()) { | 36 | for (final AstNode child : node.getChildren()) { |
| 36 | child.acceptVisitor(this, index); | 37 | child.acceptVisitor(this, index); |
| 37 | } | 38 | } |
| 39 | |||
| 38 | return null; | 40 | return null; |
| 39 | } | 41 | } |
| 40 | } | 42 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java index dc36865a..6f87895b 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/index/TokenFactory.java | |||
| @@ -1,46 +1,44 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.index; | 1 | package cuchaz.enigma.source.procyon.index; |
| 2 | 2 | ||
| 3 | import java.util.regex.Pattern; | ||
| 4 | |||
| 3 | import com.strobel.decompiler.languages.Region; | 5 | import com.strobel.decompiler.languages.Region; |
| 4 | import com.strobel.decompiler.languages.java.ast.AstNode; | 6 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 5 | import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; | 7 | import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; |
| 6 | import com.strobel.decompiler.languages.java.ast.Identifier; | 8 | import com.strobel.decompiler.languages.java.ast.Identifier; |
| 7 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | 9 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; |
| 8 | import cuchaz.enigma.source.Token; | ||
| 9 | import cuchaz.enigma.source.SourceIndex; | ||
| 10 | 10 | ||
| 11 | import java.util.regex.Pattern; | 11 | import cuchaz.enigma.source.SourceIndex; |
| 12 | import cuchaz.enigma.source.Token; | ||
| 12 | 13 | ||
| 13 | public class TokenFactory { | 14 | public class TokenFactory { |
| 14 | private static final Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$"); | 15 | private static final Pattern ANONYMOUS_INNER = Pattern.compile("\\$\\d+$"); |
| 15 | 16 | ||
| 16 | public static Token createToken(SourceIndex index, AstNode node) { | 17 | public static Token createToken(SourceIndex index, AstNode node) { |
| 17 | String name = node instanceof Identifier ? ((Identifier) node).getName() : ""; | 18 | String name = node instanceof Identifier ? ((Identifier) node).getName() : ""; |
| 18 | Region region = node.getRegion(); | 19 | Region region = node.getRegion(); |
| 19 | 20 | ||
| 20 | if (region.getBeginLine() == 0) { | 21 | if (region.getBeginLine() == 0) { |
| 21 | System.err.println("Got bad region from Procyon for node " + node); | 22 | System.err.println("Got bad region from Procyon for node " + node); |
| 22 | return null; | 23 | return null; |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | int start = index.getPosition(region.getBeginLine(), region.getBeginColumn()); | 26 | int start = index.getPosition(region.getBeginLine(), region.getBeginColumn()); |
| 26 | int end = index.getPosition(region.getEndLine(), region.getEndColumn()); | 27 | int end = index.getPosition(region.getEndLine(), region.getEndColumn()); |
| 27 | String text = index.getSource().substring(start, end); | 28 | String text = index.getSource().substring(start, end); |
| 28 | Token token = new Token(start, end, text); | 29 | Token token = new Token(start, end, text); |
| 29 | 30 | ||
| 30 | boolean isAnonymousInner = | 31 | boolean isAnonymousInner = node instanceof Identifier && name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && name.lastIndexOf('$') >= 0 && !ANONYMOUS_INNER.matcher(name).matches(); |
| 31 | node instanceof Identifier && | 32 | |
| 32 | name.indexOf('$') >= 0 && node.getParent() instanceof ConstructorDeclaration && | 33 | if (isAnonymousInner) { |
| 33 | name.lastIndexOf('$') >= 0 && | 34 | TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null; |
| 34 | !ANONYMOUS_INNER.matcher(name).matches(); | 35 | |
| 35 | 36 | if (type != null) { | |
| 36 | if (isAnonymousInner) { | 37 | name = type.getName(); |
| 37 | TypeDeclaration type = node.getParent().getParent() instanceof TypeDeclaration ? (TypeDeclaration) node.getParent().getParent() : null; | 38 | token.end = token.start + name.length(); |
| 38 | if (type != null) { | 39 | } |
| 39 | name = type.getName(); | 40 | } |
| 40 | token.end = token.start + name.length(); | 41 | |
| 41 | } | 42 | return token; |
| 42 | } | 43 | } |
| 43 | |||
| 44 | return token; | ||
| 45 | } | ||
| 46 | } | 44 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java index 1e5beb1e..c48aba5b 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/AddJavadocsAstTransform.java | |||
| @@ -1,24 +1,37 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | 1 | package cuchaz.enigma.source.procyon.transformers; |
| 2 | 2 | ||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.Collections; | ||
| 5 | import java.util.List; | ||
| 6 | import java.util.Objects; | ||
| 7 | import java.util.stream.Stream; | ||
| 8 | |||
| 3 | import com.google.common.base.Function; | 9 | import com.google.common.base.Function; |
| 4 | import com.google.common.base.Strings; | 10 | import com.google.common.base.Strings; |
| 5 | import com.strobel.assembler.metadata.ParameterDefinition; | 11 | import com.strobel.assembler.metadata.ParameterDefinition; |
| 6 | import com.strobel.decompiler.languages.java.ast.*; | 12 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 13 | import com.strobel.decompiler.languages.java.ast.Comment; | ||
| 14 | import com.strobel.decompiler.languages.java.ast.CommentType; | ||
| 15 | import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; | ||
| 16 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 17 | import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; | ||
| 18 | import com.strobel.decompiler.languages.java.ast.FieldDeclaration; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 20 | import com.strobel.decompiler.languages.java.ast.MethodDeclaration; | ||
| 21 | import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; | ||
| 22 | import com.strobel.decompiler.languages.java.ast.Roles; | ||
| 23 | import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | 24 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; |
| 25 | |||
| 8 | import cuchaz.enigma.source.procyon.EntryParser; | 26 | import cuchaz.enigma.source.procyon.EntryParser; |
| 9 | import cuchaz.enigma.translation.mapping.EntryMapping; | 27 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 10 | import cuchaz.enigma.translation.mapping.EntryRemapper; | 28 | import cuchaz.enigma.translation.mapping.EntryRemapper; |
| 11 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; | 29 | import cuchaz.enigma.translation.mapping.ResolutionStrategy; |
| 12 | import cuchaz.enigma.translation.representation.entry.*; | 30 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 13 | 31 | import cuchaz.enigma.translation.representation.entry.LocalVariableDefEntry; | |
| 14 | import java.util.ArrayList; | 32 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 15 | import java.util.Collections; | ||
| 16 | import java.util.List; | ||
| 17 | import java.util.Objects; | ||
| 18 | import java.util.stream.Stream; | ||
| 19 | 33 | ||
| 20 | public final class AddJavadocsAstTransform implements IAstTransform { | 34 | public final class AddJavadocsAstTransform implements IAstTransform { |
| 21 | |||
| 22 | private final EntryRemapper remapper; | 35 | private final EntryRemapper remapper; |
| 23 | 36 | ||
| 24 | public AddJavadocsAstTransform(EntryRemapper remapper) { | 37 | public AddJavadocsAstTransform(EntryRemapper remapper) { |
| @@ -31,7 +44,6 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 31 | } | 44 | } |
| 32 | 45 | ||
| 33 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { | 46 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { |
| 34 | |||
| 35 | private final EntryRemapper remapper; | 47 | private final EntryRemapper remapper; |
| 36 | 48 | ||
| 37 | Visitor(EntryRemapper remapper) { | 49 | Visitor(EntryRemapper remapper) { |
| @@ -40,6 +52,7 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 40 | 52 | ||
| 41 | private <T extends AstNode> void addDoc(T node, Function<T, Entry<?>> retriever) { | 53 | private <T extends AstNode> void addDoc(T node, Function<T, Entry<?>> retriever) { |
| 42 | final Comment[] comments = getComments(node, retriever); | 54 | final Comment[] comments = getComments(node, retriever); |
| 55 | |||
| 43 | if (comments != null) { | 56 | if (comments != null) { |
| 44 | node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments); | 57 | node.insertChildrenBefore(node.getFirstChild(), Roles.COMMENT, comments); |
| 45 | } | 58 | } |
| @@ -48,22 +61,24 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 48 | private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { | 61 | private <T extends AstNode> Comment[] getComments(T node, Function<T, Entry<?>> retriever) { |
| 49 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); | 62 | final EntryMapping mapping = remapper.getDeobfMapping(retriever.apply(node)); |
| 50 | final String docs = Strings.emptyToNull(mapping.javadoc()); | 63 | final String docs = Strings.emptyToNull(mapping.javadoc()); |
| 51 | return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, | 64 | return docs == null ? null : Stream.of(docs.split("\\R")).map(st -> new Comment(st, CommentType.Documentation)).toArray(Comment[]::new); |
| 52 | CommentType.Documentation)).toArray(Comment[]::new); | ||
| 53 | } | 65 | } |
| 54 | 66 | ||
| 55 | private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { | 67 | private Comment[] getParameterComments(ParameterDeclaration node, Function<ParameterDeclaration, Entry<?>> retriever) { |
| 56 | Entry<?> entry = retriever.apply(node); | 68 | Entry<?> entry = retriever.apply(node); |
| 57 | final EntryMapping mapping = remapper.getDeobfMapping(entry); | 69 | final EntryMapping mapping = remapper.getDeobfMapping(entry); |
| 58 | final Comment[] ret = getComments(node, retriever); | 70 | final Comment[] ret = getComments(node, retriever); |
| 71 | |||
| 59 | if (ret != null) { | 72 | if (ret != null) { |
| 60 | final String paramPrefix = "@param " + (mapping.targetName() != null ? mapping.targetName() : entry.getName()) + " "; | 73 | final String paramPrefix = "@param " + (mapping.targetName() != null ? mapping.targetName() : entry.getName()) + " "; |
| 61 | final String indent = Strings.repeat(" ", paramPrefix.length()); | 74 | final String indent = Strings.repeat(" ", paramPrefix.length()); |
| 62 | ret[0].setContent(paramPrefix + ret[0].getContent()); | 75 | ret[0].setContent(paramPrefix + ret[0].getContent()); |
| 76 | |||
| 63 | for (int i = 1; i < ret.length; i++) { | 77 | for (int i = 1; i < ret.length; i++) { |
| 64 | ret[i].setContent(indent + ret[i].getContent()); | 78 | ret[i].setContent(indent + ret[i].getContent()); |
| 65 | } | 79 | } |
| 66 | } | 80 | } |
| 81 | |||
| 67 | return ret; | 82 | return ret; |
| 68 | } | 83 | } |
| 69 | 84 | ||
| @@ -71,23 +86,27 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 71 | final MethodDefEntry methodDefEntry = EntryParser.parse(node.getUserData(Keys.METHOD_DEFINITION)); | 86 | final MethodDefEntry methodDefEntry = EntryParser.parse(node.getUserData(Keys.METHOD_DEFINITION)); |
| 72 | final Comment[] baseComments = getComments(node, $ -> methodDefEntry); | 87 | final Comment[] baseComments = getComments(node, $ -> methodDefEntry); |
| 73 | List<Comment> comments = new ArrayList<>(); | 88 | List<Comment> comments = new ArrayList<>(); |
| 74 | if (baseComments != null) | 89 | |
| 90 | if (baseComments != null) { | ||
| 75 | Collections.addAll(comments, baseComments); | 91 | Collections.addAll(comments, baseComments); |
| 92 | } | ||
| 76 | 93 | ||
| 77 | for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) { | 94 | for (ParameterDeclaration dec : node.getChildrenByRole(Roles.PARAMETER)) { |
| 78 | ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION); | 95 | ParameterDefinition def = dec.getUserData(Keys.PARAMETER_DEFINITION); |
| 79 | final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), | 96 | final Comment[] paramComments = getParameterComments(dec, $ -> new LocalVariableDefEntry(methodDefEntry, def.getSlot(), def.getName(), true, EntryParser.parseTypeDescriptor(def.getParameterType()), null)); |
| 80 | true, | 97 | |
| 81 | EntryParser.parseTypeDescriptor(def.getParameterType()), null)); | 98 | if (paramComments != null) { |
| 82 | if (paramComments != null) | ||
| 83 | Collections.addAll(comments, paramComments); | 99 | Collections.addAll(comments, paramComments); |
| 100 | } | ||
| 84 | } | 101 | } |
| 85 | 102 | ||
| 86 | if (!comments.isEmpty()) { | 103 | if (!comments.isEmpty()) { |
| 87 | if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) { | 104 | if (remapper.getObfResolver().resolveEntry(methodDefEntry, ResolutionStrategy.RESOLVE_ROOT).stream().noneMatch(e -> Objects.equals(e, methodDefEntry))) { |
| 88 | comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation)); | 105 | comments.add(0, new Comment("{@inheritDoc}", CommentType.Documentation)); |
| 89 | } | 106 | } |
| 107 | |||
| 90 | final AstNode oldFirst = node.getFirstChild(); | 108 | final AstNode oldFirst = node.getFirstChild(); |
| 109 | |||
| 91 | for (Comment comment : comments) { | 110 | for (Comment comment : comments) { |
| 92 | node.insertChildBefore(oldFirst, comment, Roles.COMMENT); | 111 | node.insertChildBefore(oldFirst, comment, Roles.COMMENT); |
| 93 | } | 112 | } |
| @@ -99,6 +118,7 @@ public final class AddJavadocsAstTransform implements IAstTransform { | |||
| 99 | for (final AstNode child : node.getChildren()) { | 118 | for (final AstNode child : node.getChildren()) { |
| 100 | child.acceptVisitor(this, data); | 119 | child.acceptVisitor(this, data); |
| 101 | } | 120 | } |
| 121 | |||
| 102 | return null; | 122 | return null; |
| 103 | } | 123 | } |
| 104 | 124 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java index b8c087b9..defd2511 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/DropVarModifiersAstTransform.java | |||
| @@ -1,10 +1,15 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | 1 | package cuchaz.enigma.source.procyon.transformers; |
| 2 | 2 | ||
| 3 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 4 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 5 | |||
| 6 | import javax.lang.model.element.Modifier; | 3 | import javax.lang.model.element.Modifier; |
| 7 | 4 | ||
| 5 | import com.strobel.decompiler.languages.java.ast.AstNode; | ||
| 6 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 7 | import com.strobel.decompiler.languages.java.ast.EntityDeclaration; | ||
| 8 | import com.strobel.decompiler.languages.java.ast.JavaModifierToken; | ||
| 9 | import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; | ||
| 10 | import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; | ||
| 11 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | ||
| 12 | |||
| 8 | public final class DropVarModifiersAstTransform implements IAstTransform { | 13 | public final class DropVarModifiersAstTransform implements IAstTransform { |
| 9 | public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform(); | 14 | public static final DropVarModifiersAstTransform INSTANCE = new DropVarModifiersAstTransform(); |
| 10 | 15 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java index 34d95fa5..bc7d5a25 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/InvalidIdentifierFix.java | |||
| @@ -14,15 +14,17 @@ public class InvalidIdentifierFix implements IAstTransform { | |||
| 14 | compilationUnit.acceptVisitor(new Visitor(), null); | 14 | compilationUnit.acceptVisitor(new Visitor(), null); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | class Visitor extends DepthFirstAstVisitor<Void,Void>{ | 17 | class Visitor extends DepthFirstAstVisitor<Void, Void> { |
| 18 | @Override | 18 | @Override |
| 19 | public Void visitIdentifier(Identifier node, Void data) { | 19 | public Void visitIdentifier(Identifier node, Void data) { |
| 20 | super.visitIdentifier(node, data); | 20 | super.visitIdentifier(node, data); |
| 21 | if (node.getName().equals("do") || node.getName().equals("if")){ | 21 | |
| 22 | if (node.getName().equals("do") || node.getName().equals("if")) { | ||
| 22 | Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation()); | 23 | Identifier newIdentifier = Identifier.create(node.getName() + "_", node.getStartLocation()); |
| 23 | newIdentifier.copyUserDataFrom(node); | 24 | newIdentifier.copyUserDataFrom(node); |
| 24 | node.replaceWith(newIdentifier); | 25 | node.replaceWith(newIdentifier); |
| 25 | } | 26 | } |
| 27 | |||
| 26 | return null; | 28 | return null; |
| 27 | } | 29 | } |
| 28 | } | 30 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java index 8accfc7c..3edc06c8 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/Java8Generics.java | |||
| @@ -1,66 +1,62 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | 1 | package cuchaz.enigma.source.procyon.transformers; |
| 2 | 2 | ||
| 3 | import com.strobel.assembler.metadata.BuiltinTypes; | ||
| 4 | import com.strobel.assembler.metadata.CommonTypeReferences; | 3 | import com.strobel.assembler.metadata.CommonTypeReferences; |
| 5 | import com.strobel.assembler.metadata.Flags; | ||
| 6 | import com.strobel.assembler.metadata.IGenericInstance; | 4 | import com.strobel.assembler.metadata.IGenericInstance; |
| 7 | import com.strobel.assembler.metadata.IMemberDefinition; | ||
| 8 | import com.strobel.assembler.metadata.JvmType; | ||
| 9 | import com.strobel.assembler.metadata.MemberReference; | ||
| 10 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 11 | import com.strobel.assembler.metadata.TypeDefinition; | 5 | import com.strobel.assembler.metadata.TypeDefinition; |
| 12 | import com.strobel.assembler.metadata.TypeReference; | 6 | import com.strobel.assembler.metadata.TypeReference; |
| 13 | import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; | ||
| 14 | import com.strobel.decompiler.languages.java.ast.AstNode; | 7 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 15 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; | 8 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; |
| 16 | import com.strobel.decompiler.languages.java.ast.AstType; | 9 | import com.strobel.decompiler.languages.java.ast.AstType; |
| 17 | import com.strobel.decompiler.languages.java.ast.CastExpression; | 10 | import com.strobel.decompiler.languages.java.ast.CastExpression; |
| 18 | import com.strobel.decompiler.languages.java.ast.ComposedType; | ||
| 19 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | 11 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; |
| 20 | import com.strobel.decompiler.languages.java.ast.Expression; | 12 | import com.strobel.decompiler.languages.java.ast.Expression; |
| 21 | import com.strobel.decompiler.languages.java.ast.Identifier; | 13 | import com.strobel.decompiler.languages.java.ast.Identifier; |
| 22 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | 14 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; |
| 23 | import com.strobel.decompiler.languages.java.ast.Keys; | ||
| 24 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; | 15 | import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; |
| 25 | import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; | 16 | import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; |
| 26 | import com.strobel.decompiler.languages.java.ast.Roles; | 17 | import com.strobel.decompiler.languages.java.ast.Roles; |
| 27 | import com.strobel.decompiler.languages.java.ast.SimpleType; | 18 | import com.strobel.decompiler.languages.java.ast.SimpleType; |
| 28 | import com.strobel.decompiler.languages.java.ast.WildcardType; | ||
| 29 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | 19 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; |
| 30 | 20 | ||
| 31 | /** | 21 | /** |
| 32 | * Created by Thiakil on 12/07/2018. | 22 | * Created by Thiakil on 12/07/2018. |
| 33 | */ | 23 | */ |
| 34 | public class Java8Generics implements IAstTransform { | 24 | public class Java8Generics implements IAstTransform { |
| 35 | |||
| 36 | @Override | 25 | @Override |
| 37 | public void run(AstNode compilationUnit) { | 26 | public void run(AstNode compilationUnit) { |
| 38 | compilationUnit.acceptVisitor(new Visitor(), null); | 27 | compilationUnit.acceptVisitor(new Visitor(), null); |
| 39 | } | 28 | } |
| 40 | 29 | ||
| 41 | static class Visitor extends DepthFirstAstVisitor<Void,Void>{ | 30 | static class Visitor extends DepthFirstAstVisitor<Void, Void> { |
| 42 | |||
| 43 | @Override | 31 | @Override |
| 44 | public Void visitInvocationExpression(InvocationExpression node, Void data) { | 32 | public Void visitInvocationExpression(InvocationExpression node, Void data) { |
| 45 | super.visitInvocationExpression(node, data); | 33 | super.visitInvocationExpression(node, data); |
| 46 | if (node.getTarget() instanceof MemberReferenceExpression){ | 34 | |
| 35 | if (node.getTarget() instanceof MemberReferenceExpression) { | ||
| 47 | MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget(); | 36 | MemberReferenceExpression referenceExpression = (MemberReferenceExpression) node.getTarget(); |
| 48 | if (referenceExpression.getTypeArguments().stream().map(t->{ | 37 | |
| 38 | if (referenceExpression.getTypeArguments().stream().map(t -> { | ||
| 49 | TypeReference tr = t.toTypeReference(); | 39 | TypeReference tr = t.toTypeReference(); |
| 50 | if (tr.getDeclaringType() != null){//ensure that inner types are resolved so we can get the TypeDefinition below | 40 | |
| 41 | //ensure that inner types are resolved so we can get the TypeDefinition below | ||
| 42 | if (tr.getDeclaringType() != null) { | ||
| 51 | TypeReference resolved = tr.resolve(); | 43 | TypeReference resolved = tr.resolve(); |
| 52 | if (resolved != null) | 44 | |
| 45 | if (resolved != null) { | ||
| 53 | return resolved; | 46 | return resolved; |
| 47 | } | ||
| 54 | } | 48 | } |
| 49 | |||
| 55 | return tr; | 50 | return tr; |
| 56 | }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) { | 51 | }).anyMatch(t -> t.isWildcardType() || (t instanceof TypeDefinition && ((TypeDefinition) t).isAnonymous()))) { |
| 57 | //these are invalid for invocations, let the compiler work it out | 52 | //these are invalid for invocations, let the compiler work it out |
| 58 | referenceExpression.getTypeArguments().clear(); | 53 | referenceExpression.getTypeArguments().clear(); |
| 59 | } else if (referenceExpression.getTypeArguments().stream().allMatch(t->t.toTypeReference().equals(CommonTypeReferences.Object))){ | 54 | } else if (referenceExpression.getTypeArguments().stream().allMatch(t -> t.toTypeReference().equals(CommonTypeReferences.Object))) { |
| 60 | //all are <Object>, thereby redundant and/or bad | 55 | //all are <Object>, thereby redundant and/or bad |
| 61 | referenceExpression.getTypeArguments().clear(); | 56 | referenceExpression.getTypeArguments().clear(); |
| 62 | } | 57 | } |
| 63 | } | 58 | } |
| 59 | |||
| 64 | return null; | 60 | return null; |
| 65 | } | 61 | } |
| 66 | 62 | ||
| @@ -68,14 +64,17 @@ public class Java8Generics implements IAstTransform { | |||
| 68 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { | 64 | public Void visitObjectCreationExpression(ObjectCreationExpression node, Void data) { |
| 69 | super.visitObjectCreationExpression(node, data); | 65 | super.visitObjectCreationExpression(node, data); |
| 70 | AstType type = node.getType(); | 66 | AstType type = node.getType(); |
| 71 | if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()){ | 67 | |
| 68 | if (type instanceof SimpleType && !((SimpleType) type).getTypeArguments().isEmpty()) { | ||
| 72 | SimpleType simpleType = (SimpleType) type; | 69 | SimpleType simpleType = (SimpleType) type; |
| 73 | AstNodeCollection<AstType> typeArguments = simpleType.getTypeArguments(); | 70 | AstNodeCollection<AstType> typeArguments = simpleType.getTypeArguments(); |
| 74 | if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)){ | 71 | |
| 72 | if (typeArguments.size() == 1 && typeArguments.firstOrNullObject().toTypeReference().equals(CommonTypeReferences.Object)) { | ||
| 75 | //all are <Object>, thereby redundant and/or bad | 73 | //all are <Object>, thereby redundant and/or bad |
| 76 | typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create("")); | 74 | typeArguments.firstOrNullObject().getChildByRole(Roles.IDENTIFIER).replaceWith(Identifier.create("")); |
| 77 | } | 75 | } |
| 78 | } | 76 | } |
| 77 | |||
| 79 | return null; | 78 | return null; |
| 80 | } | 79 | } |
| 81 | 80 | ||
| @@ -83,24 +82,30 @@ public class Java8Generics implements IAstTransform { | |||
| 83 | public Void visitCastExpression(CastExpression node, Void data) { | 82 | public Void visitCastExpression(CastExpression node, Void data) { |
| 84 | boolean doReplace = false; | 83 | boolean doReplace = false; |
| 85 | TypeReference typeReference = node.getType().toTypeReference(); | 84 | TypeReference typeReference = node.getType().toTypeReference(); |
| 86 | if (typeReference.isArray() && typeReference.getElementType().isGenericType()){ | 85 | |
| 86 | if (typeReference.isArray() && typeReference.getElementType().isGenericType()) { | ||
| 87 | doReplace = true; | 87 | doReplace = true; |
| 88 | } else if (typeReference.isGenericType()) { | 88 | } else if (typeReference.isGenericType()) { |
| 89 | Expression target = node.getExpression(); | 89 | Expression target = node.getExpression(); |
| 90 | if (typeReference instanceof IGenericInstance && ((IGenericInstance)typeReference).getTypeArguments().stream().anyMatch(t->t.isWildcardType())){ | 90 | |
| 91 | if (typeReference instanceof IGenericInstance && ((IGenericInstance) typeReference).getTypeArguments().stream().anyMatch(t -> t.isWildcardType())) { | ||
| 91 | doReplace = true; | 92 | doReplace = true; |
| 92 | } else if (target instanceof InvocationExpression) { | 93 | } else if (target instanceof InvocationExpression) { |
| 93 | InvocationExpression invocationExpression = (InvocationExpression)target; | 94 | InvocationExpression invocationExpression = (InvocationExpression) target; |
| 95 | |||
| 94 | if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) { | 96 | if (invocationExpression.getTarget() instanceof MemberReferenceExpression && !((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().isEmpty()) { |
| 95 | ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear(); | 97 | ((MemberReferenceExpression) invocationExpression.getTarget()).getTypeArguments().clear(); |
| 96 | doReplace = true; | 98 | doReplace = true; |
| 97 | } | 99 | } |
| 98 | } | 100 | } |
| 99 | } | 101 | } |
| 102 | |||
| 100 | super.visitCastExpression(node, data); | 103 | super.visitCastExpression(node, data); |
| 101 | if (doReplace){ | 104 | |
| 105 | if (doReplace) { | ||
| 102 | node.replaceWith(node.getExpression()); | 106 | node.replaceWith(node.getExpression()); |
| 103 | } | 107 | } |
| 108 | |||
| 104 | return null; | 109 | return null; |
| 105 | } | 110 | } |
| 106 | } | 111 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java index 32bb72f4..204351ec 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/ObfuscatedEnumSwitchRewriterTransform.java | |||
| @@ -17,6 +17,12 @@ | |||
| 17 | 17 | ||
| 18 | package cuchaz.enigma.source.procyon.transformers; | 18 | package cuchaz.enigma.source.procyon.transformers; |
| 19 | 19 | ||
| 20 | import java.util.ArrayList; | ||
| 21 | import java.util.IdentityHashMap; | ||
| 22 | import java.util.LinkedHashMap; | ||
| 23 | import java.util.List; | ||
| 24 | import java.util.Map; | ||
| 25 | |||
| 20 | import com.strobel.assembler.metadata.BuiltinTypes; | 26 | import com.strobel.assembler.metadata.BuiltinTypes; |
| 21 | import com.strobel.assembler.metadata.FieldDefinition; | 27 | import com.strobel.assembler.metadata.FieldDefinition; |
| 22 | import com.strobel.assembler.metadata.MethodDefinition; | 28 | import com.strobel.assembler.metadata.MethodDefinition; |
| @@ -43,372 +49,356 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | |||
| 43 | import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; | 49 | import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; |
| 44 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | 50 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; |
| 45 | 51 | ||
| 46 | import java.util.ArrayList; | ||
| 47 | import java.util.IdentityHashMap; | ||
| 48 | import java.util.LinkedHashMap; | ||
| 49 | import java.util.List; | ||
| 50 | import java.util.Map; | ||
| 51 | |||
| 52 | /** | 52 | /** |
| 53 | * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to: | 53 | * Copy of {@link com.strobel.decompiler.languages.java.ast.transforms.EnumSwitchRewriterTransform} modified to. |
| 54 | * - Not rely on a field containing "$SwitchMap$" (Proguard strips it) | 54 | * - Not rely on a field containing "$SwitchMap$" (Proguard strips it) |
| 55 | * - Ignore classes *with* SwitchMap$ names (so the original can handle it) | 55 | * - Ignore classes *with* SwitchMap$ names (so the original can handle it) |
| 56 | * - Ignores inner synthetics that are not package private | 56 | * - Ignores inner synthetics that are not package private |
| 57 | */ | 57 | */ |
| 58 | @SuppressWarnings("Duplicates") | 58 | @SuppressWarnings("Duplicates") |
| 59 | public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform { | 59 | public class ObfuscatedEnumSwitchRewriterTransform implements IAstTransform { |
| 60 | private final DecompilerContext _context; | 60 | private final DecompilerContext _context; |
| 61 | 61 | ||
| 62 | public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) { | 62 | public ObfuscatedEnumSwitchRewriterTransform(final DecompilerContext context) { |
| 63 | _context = VerifyArgument.notNull(context, "context"); | 63 | _context = VerifyArgument.notNull(context, "context"); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | @Override | 66 | @Override |
| 67 | public void run(final AstNode compilationUnit) { | 67 | public void run(final AstNode compilationUnit) { |
| 68 | compilationUnit.acceptVisitor(new Visitor(_context), null); | 68 | compilationUnit.acceptVisitor(new Visitor(_context), null); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | private final static class Visitor extends ContextTrackingVisitor<Void> { | 71 | private static final class Visitor extends ContextTrackingVisitor<Void> { |
| 72 | private final static class SwitchMapInfo { | 72 | private static final class SwitchMapInfo { |
| 73 | final String enclosingType; | 73 | final String enclosingType; |
| 74 | final Map<String, List<SwitchStatement>> switches = new LinkedHashMap<>(); | 74 | final Map<String, List<SwitchStatement>> switches = new LinkedHashMap<>(); |
| 75 | final Map<String, Map<Integer, Expression>> mappings = new LinkedHashMap<>(); | 75 | final Map<String, Map<Integer, Expression>> mappings = new LinkedHashMap<>(); |
| 76 | 76 | ||
| 77 | TypeDeclaration enclosingTypeDeclaration; | 77 | TypeDeclaration enclosingTypeDeclaration; |
| 78 | 78 | ||
| 79 | SwitchMapInfo(final String enclosingType) { | 79 | SwitchMapInfo(final String enclosingType) { |
| 80 | this.enclosingType = enclosingType; | 80 | this.enclosingType = enclosingType; |
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | private final Map<String, SwitchMapInfo> _switchMaps = new LinkedHashMap<>(); | 84 | private final Map<String, SwitchMapInfo> _switchMaps = new LinkedHashMap<>(); |
| 85 | private boolean _isSwitchMapWrapper; | 85 | private boolean _isSwitchMapWrapper; |
| 86 | 86 | ||
| 87 | protected Visitor(final DecompilerContext context) { | 87 | protected Visitor(final DecompilerContext context) { |
| 88 | super(context); | 88 | super(context); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | @Override | 91 | @Override |
| 92 | public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) { | 92 | public Void visitTypeDeclaration(final TypeDeclaration typeDeclaration, final Void p) { |
| 93 | final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper; | 93 | final boolean oldIsSwitchMapWrapper = _isSwitchMapWrapper; |
| 94 | final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION); | 94 | final TypeDefinition typeDefinition = typeDeclaration.getUserData(Keys.TYPE_DEFINITION); |
| 95 | final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition); | 95 | final boolean isSwitchMapWrapper = isSwitchMapWrapper(typeDefinition); |
| 96 | 96 | ||
| 97 | if (isSwitchMapWrapper) { | 97 | if (isSwitchMapWrapper) { |
| 98 | final String internalName = typeDefinition.getInternalName(); | 98 | final String internalName = typeDefinition.getInternalName(); |
| 99 | 99 | ||
| 100 | SwitchMapInfo info = _switchMaps.get(internalName); | 100 | SwitchMapInfo info = _switchMaps.get(internalName); |
| 101 | 101 | ||
| 102 | if (info == null) { | 102 | if (info == null) { |
| 103 | _switchMaps.put(internalName, info = new SwitchMapInfo(internalName)); | 103 | _switchMaps.put(internalName, info = new SwitchMapInfo(internalName)); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | info.enclosingTypeDeclaration = typeDeclaration; | 106 | info.enclosingTypeDeclaration = typeDeclaration; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | _isSwitchMapWrapper = isSwitchMapWrapper; | 109 | _isSwitchMapWrapper = isSwitchMapWrapper; |
| 110 | 110 | ||
| 111 | try { | 111 | try { |
| 112 | super.visitTypeDeclaration(typeDeclaration, p); | 112 | super.visitTypeDeclaration(typeDeclaration, p); |
| 113 | } | 113 | } finally { |
| 114 | finally { | 114 | _isSwitchMapWrapper = oldIsSwitchMapWrapper; |
| 115 | _isSwitchMapWrapper = oldIsSwitchMapWrapper; | 115 | } |
| 116 | } | ||
| 117 | 116 | ||
| 118 | rewrite(); | 117 | rewrite(); |
| 119 | 118 | ||
| 120 | return null; | 119 | return null; |
| 121 | } | 120 | } |
| 122 | 121 | ||
| 123 | @Override | 122 | @Override |
| 124 | public Void visitSwitchStatement(final SwitchStatement node, final Void data) { | 123 | public Void visitSwitchStatement(final SwitchStatement node, final Void data) { |
| 125 | final Expression test = node.getExpression(); | 124 | final Expression test = node.getExpression(); |
| 126 | 125 | ||
| 127 | if (test instanceof IndexerExpression) { | 126 | if (test instanceof IndexerExpression) { |
| 128 | final IndexerExpression indexer = (IndexerExpression) test; | 127 | final IndexerExpression indexer = (IndexerExpression) test; |
| 129 | final Expression array = indexer.getTarget(); | 128 | final Expression array = indexer.getTarget(); |
| 130 | final Expression argument = indexer.getArgument(); | 129 | final Expression argument = indexer.getArgument(); |
| 131 | 130 | ||
| 132 | if (!(array instanceof MemberReferenceExpression)) { | 131 | if (!(array instanceof MemberReferenceExpression)) { |
| 133 | return super.visitSwitchStatement(node, data); | 132 | return super.visitSwitchStatement(node, data); |
| 134 | } | 133 | } |
| 135 | 134 | ||
| 136 | final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array; | 135 | final MemberReferenceExpression arrayAccess = (MemberReferenceExpression) array; |
| 137 | final Expression arrayOwner = arrayAccess.getTarget(); | 136 | final Expression arrayOwner = arrayAccess.getTarget(); |
| 138 | final String mapName = arrayAccess.getMemberName(); | 137 | final String mapName = arrayAccess.getMemberName(); |
| 139 | 138 | ||
| 140 | if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) { | 139 | if (mapName == null || mapName.startsWith("$SwitchMap$") || !(arrayOwner instanceof TypeReferenceExpression)) { |
| 141 | return super.visitSwitchStatement(node, data); | 140 | return super.visitSwitchStatement(node, data); |
| 142 | } | 141 | } |
| 143 | 142 | ||
| 144 | final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner; | 143 | final TypeReferenceExpression enclosingTypeExpression = (TypeReferenceExpression) arrayOwner; |
| 145 | final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE); | 144 | final TypeReference enclosingType = enclosingTypeExpression.getType().getUserData(Keys.TYPE_REFERENCE); |
| 146 | 145 | ||
| 147 | if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) { | 146 | if (!isSwitchMapWrapper(enclosingType) || !(argument instanceof InvocationExpression)) { |
| 148 | return super.visitSwitchStatement(node, data); | 147 | return super.visitSwitchStatement(node, data); |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | final InvocationExpression invocation = (InvocationExpression) argument; | 150 | final InvocationExpression invocation = (InvocationExpression) argument; |
| 152 | final Expression invocationTarget = invocation.getTarget(); | 151 | final Expression invocationTarget = invocation.getTarget(); |
| 153 | 152 | ||
| 154 | if (!(invocationTarget instanceof MemberReferenceExpression)) { | 153 | if (!(invocationTarget instanceof MemberReferenceExpression)) { |
| 155 | return super.visitSwitchStatement(node, data); | 154 | return super.visitSwitchStatement(node, data); |
| 156 | } | 155 | } |
| 157 | 156 | ||
| 158 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; | 157 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; |
| 159 | 158 | ||
| 160 | if (!"ordinal".equals(memberReference.getMemberName())) { | 159 | if (!"ordinal".equals(memberReference.getMemberName())) { |
| 161 | return super.visitSwitchStatement(node, data); | 160 | return super.visitSwitchStatement(node, data); |
| 162 | } | 161 | } |
| 163 | 162 | ||
| 164 | final String enclosingTypeName = enclosingType.getInternalName(); | 163 | final String enclosingTypeName = enclosingType.getInternalName(); |
| 165 | 164 | ||
| 166 | SwitchMapInfo info = _switchMaps.get(enclosingTypeName); | 165 | SwitchMapInfo info = _switchMaps.get(enclosingTypeName); |
| 167 | 166 | ||
| 168 | if (info == null) { | 167 | if (info == null) { |
| 169 | _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName)); | 168 | _switchMaps.put(enclosingTypeName, info = new SwitchMapInfo(enclosingTypeName)); |
| 170 | 169 | ||
| 171 | final TypeDefinition resolvedType = enclosingType.resolve(); | 170 | final TypeDefinition resolvedType = enclosingType.resolve(); |
| 172 | 171 | ||
| 173 | if (resolvedType != null) { | 172 | if (resolvedType != null) { |
| 174 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); | 173 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); |
| 175 | 174 | ||
| 176 | if (astBuilder == null) { | 175 | if (astBuilder == null) { |
| 177 | astBuilder = new AstBuilder(context); | 176 | astBuilder = new AstBuilder(context); |
| 178 | } | 177 | } |
| 179 | 178 | ||
| 180 | try (final SafeCloseable importSuppression = astBuilder.suppressImports()) { | 179 | try (SafeCloseable importSuppression = astBuilder.suppressImports()) { |
| 181 | final TypeDeclaration declaration = astBuilder.createType(resolvedType); | 180 | final TypeDeclaration declaration = astBuilder.createType(resolvedType); |
| 182 | 181 | ||
| 183 | declaration.acceptVisitor(this, data); | 182 | declaration.acceptVisitor(this, data); |
| 184 | } | 183 | } |
| 185 | } | 184 | } |
| 186 | } | 185 | } |
| 187 | 186 | ||
| 188 | List<SwitchStatement> switches = info.switches.get(mapName); | 187 | List<SwitchStatement> switches = info.switches.get(mapName); |
| 189 | 188 | ||
| 190 | if (switches == null) { | 189 | if (switches == null) { |
| 191 | info.switches.put(mapName, switches = new ArrayList<>()); | 190 | info.switches.put(mapName, switches = new ArrayList<>()); |
| 192 | } | 191 | } |
| 193 | 192 | ||
| 194 | switches.add(node); | 193 | switches.add(node); |
| 195 | } | 194 | } |
| 196 | 195 | ||
| 197 | return super.visitSwitchStatement(node, data); | 196 | return super.visitSwitchStatement(node, data); |
| 198 | } | 197 | } |
| 199 | 198 | ||
| 200 | @Override | 199 | @Override |
| 201 | public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) { | 200 | public Void visitAssignmentExpression(final AssignmentExpression node, final Void data) { |
| 202 | final TypeDefinition currentType = context.getCurrentType(); | 201 | final TypeDefinition currentType = context.getCurrentType(); |
| 203 | final MethodDefinition currentMethod = context.getCurrentMethod(); | 202 | final MethodDefinition currentMethod = context.getCurrentMethod(); |
| 204 | 203 | ||
| 205 | if (_isSwitchMapWrapper && | 204 | if (_isSwitchMapWrapper && currentType != null && currentMethod != null && currentMethod.isTypeInitializer()) { |
| 206 | currentType != null && | 205 | final Expression left = node.getLeft(); |
| 207 | currentMethod != null && | 206 | final Expression right = node.getRight(); |
| 208 | currentMethod.isTypeInitializer()) { | ||
| 209 | 207 | ||
| 210 | final Expression left = node.getLeft(); | 208 | if (left instanceof IndexerExpression && right instanceof PrimitiveExpression) { |
| 211 | final Expression right = node.getRight(); | 209 | String mapName = null; |
| 212 | 210 | ||
| 213 | if (left instanceof IndexerExpression && | 211 | final Expression array = ((IndexerExpression) left).getTarget(); |
| 214 | right instanceof PrimitiveExpression) { | 212 | final Expression argument = ((IndexerExpression) left).getArgument(); |
| 215 | 213 | ||
| 216 | String mapName = null; | 214 | if (array instanceof MemberReferenceExpression) { |
| 215 | mapName = ((MemberReferenceExpression) array).getMemberName(); | ||
| 216 | } else if (array instanceof IdentifierExpression) { | ||
| 217 | mapName = ((IdentifierExpression) array).getIdentifier(); | ||
| 218 | } | ||
| 217 | 219 | ||
| 218 | final Expression array = ((IndexerExpression) left).getTarget(); | 220 | if (mapName == null || mapName.startsWith("$SwitchMap$")) { |
| 219 | final Expression argument = ((IndexerExpression) left).getArgument(); | 221 | return super.visitAssignmentExpression(node, data); |
| 222 | } | ||
| 220 | 223 | ||
| 221 | if (array instanceof MemberReferenceExpression) { | 224 | if (!(argument instanceof InvocationExpression)) { |
| 222 | mapName = ((MemberReferenceExpression) array).getMemberName(); | 225 | return super.visitAssignmentExpression(node, data); |
| 223 | } | 226 | } |
| 224 | else if (array instanceof IdentifierExpression) { | ||
| 225 | mapName = ((IdentifierExpression) array).getIdentifier(); | ||
| 226 | } | ||
| 227 | 227 | ||
| 228 | if (mapName == null || mapName.startsWith("$SwitchMap$")) { | 228 | final InvocationExpression invocation = (InvocationExpression) argument; |
| 229 | return super.visitAssignmentExpression(node, data); | 229 | final Expression invocationTarget = invocation.getTarget(); |
| 230 | } | ||
| 231 | 230 | ||
| 232 | if (!(argument instanceof InvocationExpression)) { | 231 | if (!(invocationTarget instanceof MemberReferenceExpression)) { |
| 233 | return super.visitAssignmentExpression(node, data); | 232 | return super.visitAssignmentExpression(node, data); |
| 234 | } | 233 | } |
| 235 | 234 | ||
| 236 | final InvocationExpression invocation = (InvocationExpression) argument; | 235 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; |
| 237 | final Expression invocationTarget = invocation.getTarget(); | 236 | final Expression memberTarget = memberReference.getTarget(); |
| 238 | 237 | ||
| 239 | if (!(invocationTarget instanceof MemberReferenceExpression)) { | 238 | if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) { |
| 240 | return super.visitAssignmentExpression(node, data); | 239 | return super.visitAssignmentExpression(node, data); |
| 241 | } | 240 | } |
| 242 | 241 | ||
| 243 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) invocationTarget; | 242 | final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget; |
| 244 | final Expression memberTarget = memberReference.getTarget(); | 243 | final Expression outerMemberTarget = outerMemberReference.getTarget(); |
| 245 | 244 | ||
| 246 | if (!(memberTarget instanceof MemberReferenceExpression) || !"ordinal".equals(memberReference.getMemberName())) { | 245 | if (!(outerMemberTarget instanceof TypeReferenceExpression)) { |
| 247 | return super.visitAssignmentExpression(node, data); | 246 | return super.visitAssignmentExpression(node, data); |
| 248 | } | 247 | } |
| 249 | 248 | ||
| 250 | final MemberReferenceExpression outerMemberReference = (MemberReferenceExpression) memberTarget; | 249 | final String enclosingType = currentType.getInternalName(); |
| 251 | final Expression outerMemberTarget = outerMemberReference.getTarget(); | ||
| 252 | 250 | ||
| 253 | if (!(outerMemberTarget instanceof TypeReferenceExpression)) { | 251 | SwitchMapInfo info = _switchMaps.get(enclosingType); |
| 254 | return super.visitAssignmentExpression(node, data); | ||
| 255 | } | ||
| 256 | 252 | ||
| 257 | final String enclosingType = currentType.getInternalName(); | 253 | if (info == null) { |
| 254 | _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType)); | ||
| 258 | 255 | ||
| 259 | SwitchMapInfo info = _switchMaps.get(enclosingType); | 256 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); |
| 260 | 257 | ||
| 261 | if (info == null) { | 258 | if (astBuilder == null) { |
| 262 | _switchMaps.put(enclosingType, info = new SwitchMapInfo(enclosingType)); | 259 | astBuilder = new AstBuilder(context); |
| 260 | } | ||
| 263 | 261 | ||
| 264 | AstBuilder astBuilder = context.getUserData(Keys.AST_BUILDER); | 262 | info.enclosingTypeDeclaration = astBuilder.createType(currentType); |
| 263 | } | ||
| 265 | 264 | ||
| 266 | if (astBuilder == null) { | 265 | final PrimitiveExpression value = (PrimitiveExpression) right; |
| 267 | astBuilder = new AstBuilder(context); | ||
| 268 | } | ||
| 269 | 266 | ||
| 270 | info.enclosingTypeDeclaration = astBuilder.createType(currentType); | 267 | assert value.getValue() instanceof Integer; |
| 271 | } | ||
| 272 | 268 | ||
| 273 | final PrimitiveExpression value = (PrimitiveExpression) right; | 269 | Map<Integer, Expression> mapping = info.mappings.get(mapName); |
| 274 | 270 | ||
| 275 | assert value.getValue() instanceof Integer; | 271 | if (mapping == null) { |
| 272 | info.mappings.put(mapName, mapping = new LinkedHashMap<>()); | ||
| 273 | } | ||
| 276 | 274 | ||
| 277 | Map<Integer, Expression> mapping = info.mappings.get(mapName); | 275 | final IdentifierExpression enumValue = new IdentifierExpression(Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName()); |
| 278 | 276 | ||
| 279 | if (mapping == null) { | 277 | enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE)); |
| 280 | info.mappings.put(mapName, mapping = new LinkedHashMap<>()); | ||
| 281 | } | ||
| 282 | 278 | ||
| 283 | final IdentifierExpression enumValue = new IdentifierExpression( Expression.MYSTERY_OFFSET, outerMemberReference.getMemberName()); | 279 | mapping.put(((Number) value.getValue()).intValue(), enumValue); |
| 280 | } | ||
| 281 | } | ||
| 284 | 282 | ||
| 285 | enumValue.putUserData(Keys.MEMBER_REFERENCE, outerMemberReference.getUserData(Keys.MEMBER_REFERENCE)); | 283 | return super.visitAssignmentExpression(node, data); |
| 284 | } | ||
| 286 | 285 | ||
| 287 | mapping.put(((Number) value.getValue()).intValue(), enumValue); | 286 | private void rewrite() { |
| 288 | } | 287 | if (_switchMaps.isEmpty()) { |
| 289 | } | 288 | return; |
| 289 | } | ||
| 290 | 290 | ||
| 291 | return super.visitAssignmentExpression(node, data); | 291 | for (final SwitchMapInfo info : _switchMaps.values()) { |
| 292 | } | 292 | rewrite(info); |
| 293 | } | ||
| 293 | 294 | ||
| 294 | private void rewrite() { | 295 | // |
| 295 | if (_switchMaps.isEmpty()) { | 296 | // Remove switch map type wrappers that are no longer referenced. |
| 296 | return; | 297 | // |
| 297 | } | ||
| 298 | 298 | ||
| 299 | for (final SwitchMapInfo info : _switchMaps.values()) { | 299 | outer: |
| 300 | rewrite(info); | ||
| 301 | } | ||
| 302 | 300 | ||
| 303 | // | 301 | for (final SwitchMapInfo info : _switchMaps.values()) { |
| 304 | // Remove switch map type wrappers that are no longer referenced. | 302 | for (final String mapName : info.switches.keySet()) { |
| 305 | // | 303 | final List<SwitchStatement> switches = info.switches.get(mapName); |
| 306 | 304 | ||
| 307 | outer: | 305 | if (switches != null && !switches.isEmpty()) { |
| 308 | for (final SwitchMapInfo info : _switchMaps.values()) { | 306 | continue outer; |
| 309 | for (final String mapName : info.switches.keySet()) { | 307 | } |
| 310 | final List<SwitchStatement> switches = info.switches.get(mapName); | 308 | } |
| 311 | 309 | ||
| 312 | if (switches != null && !switches.isEmpty()) { | 310 | final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration; |
| 313 | continue outer; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | 311 | ||
| 317 | final TypeDeclaration enclosingTypeDeclaration = info.enclosingTypeDeclaration; | 312 | if (enclosingTypeDeclaration != null) { |
| 313 | enclosingTypeDeclaration.remove(); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 318 | 317 | ||
| 319 | if (enclosingTypeDeclaration != null) { | 318 | private void rewrite(final SwitchMapInfo info) { |
| 320 | enclosingTypeDeclaration.remove(); | 319 | if (info.switches.isEmpty()) { |
| 321 | } | 320 | return; |
| 322 | } | 321 | } |
| 323 | } | ||
| 324 | 322 | ||
| 325 | private void rewrite(final SwitchMapInfo info) { | 323 | for (final String mapName : info.switches.keySet()) { |
| 326 | if (info.switches.isEmpty()) { | 324 | final List<SwitchStatement> switches = info.switches.get(mapName); |
| 327 | return; | 325 | final Map<Integer, Expression> mappings = info.mappings.get(mapName); |
| 328 | } | ||
| 329 | 326 | ||
| 330 | for (final String mapName : info.switches.keySet()) { | 327 | if (switches != null && mappings != null) { |
| 331 | final List<SwitchStatement> switches = info.switches.get(mapName); | 328 | for (int i = 0; i < switches.size(); i++) { |
| 332 | final Map<Integer, Expression> mappings = info.mappings.get(mapName); | 329 | if (rewriteSwitch(switches.get(i), mappings)) { |
| 330 | switches.remove(i--); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 333 | 336 | ||
| 334 | if (switches != null && mappings != null) { | 337 | private boolean rewriteSwitch(final SwitchStatement s, final Map<Integer, Expression> mappings) { |
| 335 | for (int i = 0; i < switches.size(); i++) { | 338 | final Map<Expression, Expression> replacements = new IdentityHashMap<>(); |
| 336 | if (rewriteSwitch(switches.get(i), mappings)) { | ||
| 337 | switches.remove(i--); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | } | ||
| 341 | } | ||
| 342 | } | ||
| 343 | 339 | ||
| 344 | private boolean rewriteSwitch(final SwitchStatement s, final Map<Integer, Expression> mappings) { | 340 | for (final SwitchSection section : s.getSwitchSections()) { |
| 345 | final Map<Expression, Expression> replacements = new IdentityHashMap<>(); | 341 | for (final CaseLabel caseLabel : section.getCaseLabels()) { |
| 342 | final Expression expression = caseLabel.getExpression(); | ||
| 346 | 343 | ||
| 347 | for (final SwitchSection section : s.getSwitchSections()) { | 344 | if (expression.isNull()) { |
| 348 | for (final CaseLabel caseLabel : section.getCaseLabels()) { | 345 | continue; |
| 349 | final Expression expression = caseLabel.getExpression(); | 346 | } |
| 350 | 347 | ||
| 351 | if (expression.isNull()) { | 348 | if (expression instanceof PrimitiveExpression) { |
| 352 | continue; | 349 | final Object value = ((PrimitiveExpression) expression).getValue(); |
| 353 | } | ||
| 354 | 350 | ||
| 355 | if (expression instanceof PrimitiveExpression) { | 351 | if (value instanceof Integer) { |
| 356 | final Object value = ((PrimitiveExpression) expression).getValue(); | 352 | final Expression replacement = mappings.get(value); |
| 357 | 353 | ||
| 358 | if (value instanceof Integer) { | 354 | if (replacement != null) { |
| 359 | final Expression replacement = mappings.get(value); | 355 | replacements.put(expression, replacement); |
| 356 | continue; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } | ||
| 360 | 360 | ||
| 361 | if (replacement != null) { | 361 | // |
| 362 | replacements.put(expression, replacement); | 362 | // If we can't rewrite all cases, we abort. |
| 363 | continue; | 363 | // |
| 364 | } | ||
| 365 | } | ||
| 366 | } | ||
| 367 | 364 | ||
| 368 | // | 365 | return false; |
| 369 | // If we can't rewrite all cases, we abort. | 366 | } |
| 370 | // | 367 | } |
| 371 | 368 | ||
| 372 | return false; | 369 | final IndexerExpression indexer = (IndexerExpression) s.getExpression(); |
| 373 | } | 370 | final InvocationExpression argument = (InvocationExpression) indexer.getArgument(); |
| 374 | } | 371 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget(); |
| 375 | 372 | final Expression newTest = memberReference.getTarget(); | |
| 376 | final IndexerExpression indexer = (IndexerExpression) s.getExpression(); | 373 | |
| 377 | final InvocationExpression argument = (InvocationExpression) indexer.getArgument(); | 374 | newTest.remove(); |
| 378 | final MemberReferenceExpression memberReference = (MemberReferenceExpression) argument.getTarget(); | 375 | indexer.replaceWith(newTest); |
| 379 | final Expression newTest = memberReference.getTarget(); | 376 | |
| 380 | 377 | for (final Map.Entry<Expression, Expression> entry : replacements.entrySet()) { | |
| 381 | newTest.remove(); | 378 | entry.getKey().replaceWith(entry.getValue().clone()); |
| 382 | indexer.replaceWith(newTest); | 379 | } |
| 383 | 380 | ||
| 384 | for (final Map.Entry<Expression, Expression> entry : replacements.entrySet()) { | 381 | return true; |
| 385 | entry.getKey().replaceWith(entry.getValue().clone()); | 382 | } |
| 386 | } | 383 | |
| 387 | 384 | private static boolean isSwitchMapWrapper(final TypeReference type) { | |
| 388 | return true; | 385 | if (type == null) { |
| 389 | } | 386 | return false; |
| 390 | 387 | } | |
| 391 | private static boolean isSwitchMapWrapper(final TypeReference type) { | 388 | |
| 392 | if (type == null) { | 389 | final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type : type.resolve(); |
| 393 | return false; | 390 | |
| 394 | } | 391 | if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) { |
| 395 | 392 | return false; | |
| 396 | final TypeDefinition definition = type instanceof TypeDefinition ? (TypeDefinition) type | 393 | } |
| 397 | : type.resolve(); | 394 | |
| 398 | 395 | for (final FieldDefinition field : definition.getDeclaredFields()) { | |
| 399 | if (definition == null || !definition.isSynthetic() || !definition.isInnerClass() || !definition.isPackagePrivate()) { | 396 | if (!field.getName().startsWith("$SwitchMap$") && BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) { |
| 400 | return false; | 397 | return true; |
| 401 | } | 398 | } |
| 402 | 399 | } | |
| 403 | for (final FieldDefinition field : definition.getDeclaredFields()) { | 400 | |
| 404 | if (!field.getName().startsWith("$SwitchMap$") && | 401 | return false; |
| 405 | BuiltinTypes.Integer.makeArrayType().equals(field.getFieldType())) { | 402 | } |
| 406 | 403 | } | |
| 407 | return true; | 404 | } |
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | return false; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | } \ No newline at end of file | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java index cf0376f3..679b168f 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/RemoveObjectCasts.java | |||
| @@ -22,17 +22,17 @@ public class RemoveObjectCasts implements IAstTransform { | |||
| 22 | compilationUnit.acceptVisitor(new Visitor(_context), null); | 22 | compilationUnit.acceptVisitor(new Visitor(_context), null); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | private final static class Visitor extends ContextTrackingVisitor<Void>{ | 25 | private static final class Visitor extends ContextTrackingVisitor<Void> { |
| 26 | |||
| 27 | protected Visitor(DecompilerContext context) { | 26 | protected Visitor(DecompilerContext context) { |
| 28 | super(context); | 27 | super(context); |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | @Override | 30 | @Override |
| 32 | public Void visitCastExpression(CastExpression node, Void data) { | 31 | public Void visitCastExpression(CastExpression node, Void data) { |
| 33 | if (node.getType().toTypeReference().equals(BuiltinTypes.Object)){ | 32 | if (node.getType().toTypeReference().equals(BuiltinTypes.Object)) { |
| 34 | node.replaceWith(node.getExpression()); | 33 | node.replaceWith(node.getExpression()); |
| 35 | } | 34 | } |
| 35 | |||
| 36 | return super.visitCastExpression(node, data); | 36 | return super.visitCastExpression(node, data); |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java index d3ddaab6..234834b7 100644 --- a/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java +++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/transformers/VarargsFixer.java | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | package cuchaz.enigma.source.procyon.transformers; | 1 | package cuchaz.enigma.source.procyon.transformers; |
| 2 | 2 | ||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.List; | ||
| 5 | |||
| 3 | import com.strobel.assembler.metadata.MemberReference; | 6 | import com.strobel.assembler.metadata.MemberReference; |
| 4 | import com.strobel.assembler.metadata.MetadataFilters; | 7 | import com.strobel.assembler.metadata.MetadataFilters; |
| 5 | import com.strobel.assembler.metadata.MetadataHelper; | 8 | import com.strobel.assembler.metadata.MetadataHelper; |
| @@ -16,7 +19,6 @@ import com.strobel.decompiler.languages.java.ast.AstNode; | |||
| 16 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; | 19 | import com.strobel.decompiler.languages.java.ast.AstNodeCollection; |
| 17 | import com.strobel.decompiler.languages.java.ast.CastExpression; | 20 | import com.strobel.decompiler.languages.java.ast.CastExpression; |
| 18 | import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; | 21 | import com.strobel.decompiler.languages.java.ast.ContextTrackingVisitor; |
| 19 | import com.strobel.decompiler.languages.java.ast.DepthFirstAstVisitor; | ||
| 20 | import com.strobel.decompiler.languages.java.ast.Expression; | 22 | import com.strobel.decompiler.languages.java.ast.Expression; |
| 21 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; | 23 | import com.strobel.decompiler.languages.java.ast.InvocationExpression; |
| 22 | import com.strobel.decompiler.languages.java.ast.JavaResolver; | 24 | import com.strobel.decompiler.languages.java.ast.JavaResolver; |
| @@ -26,9 +28,6 @@ import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; | |||
| 26 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; | 28 | import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; |
| 27 | import com.strobel.decompiler.semantics.ResolveResult; | 29 | import com.strobel.decompiler.semantics.ResolveResult; |
| 28 | 30 | ||
| 29 | import java.util.ArrayList; | ||
| 30 | import java.util.List; | ||
| 31 | |||
| 32 | /** | 31 | /** |
| 33 | * Created by Thiakil on 12/07/2018. | 32 | * Created by Thiakil on 12/07/2018. |
| 34 | */ | 33 | */ |
| @@ -46,6 +45,7 @@ public class VarargsFixer implements IAstTransform { | |||
| 46 | 45 | ||
| 47 | class Visitor extends ContextTrackingVisitor<Void> { | 46 | class Visitor extends ContextTrackingVisitor<Void> { |
| 48 | private final JavaResolver _resolver; | 47 | private final JavaResolver _resolver; |
| 48 | |||
| 49 | protected Visitor(DecompilerContext context) { | 49 | protected Visitor(DecompilerContext context) { |
| 50 | super(context); | 50 | super(context); |
| 51 | _resolver = new JavaResolver(context); | 51 | _resolver = new JavaResolver(context); |
| @@ -56,21 +56,26 @@ public class VarargsFixer implements IAstTransform { | |||
| 56 | public Void visitInvocationExpression(InvocationExpression node, Void data) { | 56 | public Void visitInvocationExpression(InvocationExpression node, Void data) { |
| 57 | super.visitInvocationExpression(node, data); | 57 | super.visitInvocationExpression(node, data); |
| 58 | MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE); | 58 | MemberReference definition = node.getUserData(Keys.MEMBER_REFERENCE); |
| 59 | if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()){ | 59 | |
| 60 | if (definition instanceof MethodDefinition && ((MethodDefinition) definition).isVarArgs()) { | ||
| 60 | AstNodeCollection<Expression> arguments = node.getArguments(); | 61 | AstNodeCollection<Expression> arguments = node.getArguments(); |
| 61 | Expression lastParam = arguments.lastOrNullObject(); | 62 | Expression lastParam = arguments.lastOrNullObject(); |
| 62 | if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression){ | 63 | |
| 63 | ArrayCreationExpression varargArray = (ArrayCreationExpression)lastParam; | 64 | if (!lastParam.isNull() && lastParam instanceof ArrayCreationExpression) { |
| 64 | if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()){ | 65 | ArrayCreationExpression varargArray = (ArrayCreationExpression) lastParam; |
| 66 | |||
| 67 | if (varargArray.getInitializer().isNull() || varargArray.getInitializer().getElements().isEmpty()) { | ||
| 65 | lastParam.remove(); | 68 | lastParam.remove(); |
| 66 | } else { | 69 | } else { |
| 67 | for (Expression e : varargArray.getInitializer().getElements()){ | 70 | for (Expression e : varargArray.getInitializer().getElements()) { |
| 68 | arguments.insertBefore(varargArray, e.clone()); | 71 | arguments.insertBefore(varargArray, e.clone()); |
| 69 | } | 72 | } |
| 73 | |||
| 70 | varargArray.remove(); | 74 | varargArray.remove(); |
| 71 | } | 75 | } |
| 72 | } | 76 | } |
| 73 | } | 77 | } |
| 78 | |||
| 74 | return null; | 79 | return null; |
| 75 | } | 80 | } |
| 76 | 81 | ||
| @@ -83,14 +88,11 @@ public class VarargsFixer implements IAstTransform { | |||
| 83 | 88 | ||
| 84 | Expression arrayArg = lastArgument; | 89 | Expression arrayArg = lastArgument; |
| 85 | 90 | ||
| 86 | if (arrayArg instanceof CastExpression) | 91 | if (arrayArg instanceof CastExpression) { |
| 87 | arrayArg = ((CastExpression) arrayArg).getExpression(); | 92 | arrayArg = ((CastExpression) arrayArg).getExpression(); |
| 93 | } | ||
| 88 | 94 | ||
| 89 | if (arrayArg == null || | 95 | if (arrayArg == null || arrayArg.isNull() || !(arrayArg instanceof ArrayCreationExpression && node.getTarget() instanceof MemberReferenceExpression)) { |
| 90 | arrayArg.isNull() || | ||
| 91 | !(arrayArg instanceof ArrayCreationExpression && | ||
| 92 | node.getTarget() instanceof MemberReferenceExpression)) { | ||
| 93 | |||
| 94 | return null; | 96 | return null; |
| 95 | } | 97 | } |
| 96 | 98 | ||
| @@ -117,22 +119,15 @@ public class VarargsFixer implements IAstTransform { | |||
| 117 | final Expression invocationTarget = target.getTarget(); | 119 | final Expression invocationTarget = target.getTarget(); |
| 118 | 120 | ||
| 119 | if (invocationTarget == null || invocationTarget.isNull()) { | 121 | if (invocationTarget == null || invocationTarget.isNull()) { |
| 120 | candidates = MetadataHelper.findMethods( | 122 | candidates = MetadataHelper.findMethods(context.getCurrentType(), MetadataFilters.matchName(resolved.getName())); |
| 121 | context.getCurrentType(), | 123 | } else { |
| 122 | MetadataFilters.matchName(resolved.getName()) | ||
| 123 | ); | ||
| 124 | } | ||
| 125 | else { | ||
| 126 | final ResolveResult targetResult = _resolver.apply(invocationTarget); | 124 | final ResolveResult targetResult = _resolver.apply(invocationTarget); |
| 127 | 125 | ||
| 128 | if (targetResult == null || targetResult.getType() == null) { | 126 | if (targetResult == null || targetResult.getType() == null) { |
| 129 | return null; | 127 | return null; |
| 130 | } | 128 | } |
| 131 | 129 | ||
| 132 | candidates = MetadataHelper.findMethods( | 130 | candidates = MetadataHelper.findMethods(targetResult.getType(), MetadataFilters.matchName(resolved.getName())); |
| 133 | targetResult.getType(), | ||
| 134 | MetadataFilters.matchName(resolved.getName()) | ||
| 135 | ); | ||
| 136 | } | 131 | } |
| 137 | 132 | ||
| 138 | final List<TypeReference> argTypes = new ArrayList<>(); | 133 | final List<TypeReference> argTypes = new ArrayList<>(); |
| @@ -172,10 +167,7 @@ public class VarargsFixer implements IAstTransform { | |||
| 172 | 167 | ||
| 173 | final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes); | 168 | final MethodBinder.BindResult c2 = MethodBinder.selectMethod(candidates, argTypes); |
| 174 | 169 | ||
| 175 | if (c2.isFailure() || | 170 | if (c2.isFailure() || c2.isAmbiguous() || !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) { |
| 176 | c2.isAmbiguous() || | ||
| 177 | !StringUtilities.equals(c2.getMethod().getErasedSignature(), c1.getMethod().getErasedSignature())) { | ||
| 178 | |||
| 179 | return null; | 171 | return null; |
| 180 | } | 172 | } |
| 181 | 173 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java b/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java index dec75ff4..92d5cfcd 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/LocalNameGenerator.java | |||
| @@ -12,9 +12,11 @@ public class LocalNameGenerator { | |||
| 12 | String translatedName; | 12 | String translatedName; |
| 13 | int nameIndex = index + 1; | 13 | int nameIndex = index + 1; |
| 14 | StringBuilder nameBuilder = new StringBuilder(getTypeName(desc)); | 14 | StringBuilder nameBuilder = new StringBuilder(getTypeName(desc)); |
| 15 | |||
| 15 | if (!uniqueType || IdentifierValidation.isReservedMethodName(nameBuilder.toString())) { | 16 | if (!uniqueType || IdentifierValidation.isReservedMethodName(nameBuilder.toString())) { |
| 16 | nameBuilder.append(nameIndex); | 17 | nameBuilder.append(nameIndex); |
| 17 | } | 18 | } |
| 19 | |||
| 18 | translatedName = nameBuilder.toString(); | 20 | translatedName = nameBuilder.toString(); |
| 19 | return translatedName; | 21 | return translatedName; |
| 20 | } | 22 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java index 51e5d86d..833ea294 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/MappingTranslator.java | |||
| @@ -22,7 +22,7 @@ public class MappingTranslator implements Translator { | |||
| 22 | if (translatable == null) { | 22 | if (translatable == null) { |
| 23 | return null; | 23 | return null; |
| 24 | } | 24 | } |
| 25 | |||
| 25 | return (TranslateResult<T>) translatable.extendedTranslate(this, resolver, mappings); | 26 | return (TranslateResult<T>) translatable.extendedTranslate(this, resolver, mappings); |
| 26 | } | 27 | } |
| 27 | |||
| 28 | } | 28 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java index 5ab16c85..33a38fee 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/ProposingTranslator.java | |||
| @@ -29,25 +29,14 @@ public class ProposingTranslator implements Translator { | |||
| 29 | TranslateResult<T> deobfuscated = mapper.extendedDeobfuscate(translatable); | 29 | TranslateResult<T> deobfuscated = mapper.extendedDeobfuscate(translatable); |
| 30 | 30 | ||
| 31 | if (translatable instanceof Entry && ((Entry) deobfuscated.getValue()).getName().equals(((Entry<?>) translatable).getName())) { | 31 | if (translatable instanceof Entry && ((Entry) deobfuscated.getValue()).getName().equals(((Entry<?>) translatable).getName())) { |
| 32 | return mapper.getObfResolver() | 32 | return mapper.getObfResolver().resolveEntry((Entry<?>) translatable, ResolutionStrategy.RESOLVE_ROOT).stream().map(this::proposeName).filter(Optional::isPresent).map(Optional::get).findFirst().map( |
| 33 | .resolveEntry((Entry<?>) translatable, ResolutionStrategy.RESOLVE_ROOT) | 33 | newName -> TranslateResult.proposed((T) ((Entry) deobfuscated.getValue()).withName(newName))).orElse(deobfuscated); |
| 34 | .stream() | ||
| 35 | .map(this::proposeName) | ||
| 36 | .filter(Optional::isPresent) | ||
| 37 | .map(Optional::get) | ||
| 38 | .findFirst() | ||
| 39 | .map(newName -> TranslateResult.proposed((T) ((Entry) deobfuscated.getValue()).withName(newName))) | ||
| 40 | .orElse(deobfuscated); | ||
| 41 | } | 34 | } |
| 42 | 35 | ||
| 43 | return deobfuscated; | 36 | return deobfuscated; |
| 44 | } | 37 | } |
| 45 | 38 | ||
| 46 | private Optional<String> proposeName(Entry<?> entry) { | 39 | private Optional<String> proposeName(Entry<?> entry) { |
| 47 | return Arrays.stream(nameProposalServices) | 40 | return Arrays.stream(nameProposalServices).map(service -> service.proposeName(entry, mapper)).filter(Optional::isPresent).map(Optional::get).findFirst(); |
| 48 | .map(service -> service.proposeName(entry, mapper)) | ||
| 49 | .filter(Optional::isPresent) | ||
| 50 | .map(Optional::get) | ||
| 51 | .findFirst(); | ||
| 52 | } | 41 | } |
| 53 | } | 42 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java b/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java index 37830535..99660141 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/SignatureUpdater.java | |||
| @@ -1,24 +1,23 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation; | 12 | package cuchaz.enigma.translation; |
| 13 | 13 | ||
| 14 | import com.google.common.collect.Lists; | ||
| 15 | |||
| 16 | import java.io.IOException; | 14 | import java.io.IOException; |
| 17 | import java.io.StringReader; | 15 | import java.io.StringReader; |
| 18 | import java.util.List; | 16 | import java.util.List; |
| 19 | 17 | ||
| 20 | public class SignatureUpdater { | 18 | import com.google.common.collect.Lists; |
| 21 | 19 | ||
| 20 | public class SignatureUpdater { | ||
| 22 | public static String update(String signature, ClassNameUpdater updater) { | 21 | public static String update(String signature, ClassNameUpdater updater) { |
| 23 | try { | 22 | try { |
| 24 | StringBuilder buf = new StringBuilder(); | 23 | StringBuilder buf = new StringBuilder(); |
| @@ -26,6 +25,7 @@ public class SignatureUpdater { | |||
| 26 | // read the signature character-by-character | 25 | // read the signature character-by-character |
| 27 | StringReader reader = new StringReader(signature); | 26 | StringReader reader = new StringReader(signature); |
| 28 | int i; | 27 | int i; |
| 28 | |||
| 29 | while ((i = reader.read()) != -1) { | 29 | while ((i = reader.read()) != -1) { |
| 30 | char c = (char) i; | 30 | char c = (char) i; |
| 31 | 31 | ||
| @@ -34,9 +34,11 @@ public class SignatureUpdater { | |||
| 34 | // update the class name and add it to the buffer | 34 | // update the class name and add it to the buffer |
| 35 | buf.append('L'); | 35 | buf.append('L'); |
| 36 | String className = readClass(reader); | 36 | String className = readClass(reader); |
| 37 | |||
| 37 | if (className == null) { | 38 | if (className == null) { |
| 38 | throw new IllegalArgumentException("Malformed signature: " + signature); | 39 | throw new IllegalArgumentException("Malformed signature: " + signature); |
| 39 | } | 40 | } |
| 41 | |||
| 40 | buf.append(updater.update(className)); | 42 | buf.append(updater.update(className)); |
| 41 | buf.append(';'); | 43 | buf.append(';'); |
| 42 | } else { | 44 | } else { |
| @@ -58,6 +60,7 @@ public class SignatureUpdater { | |||
| 58 | StringBuilder buf = new StringBuilder(); | 60 | StringBuilder buf = new StringBuilder(); |
| 59 | int depth = 0; | 61 | int depth = 0; |
| 60 | int i; | 62 | int i; |
| 63 | |||
| 61 | while ((i = reader.read()) != -1) { | 64 | while ((i = reader.read()) != -1) { |
| 62 | char c = (char) i; | 65 | char c = (char) i; |
| 63 | 66 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java b/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java index 7061bfa3..af6fbc95 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/Translatable.java | |||
| @@ -5,12 +5,10 @@ import cuchaz.enigma.translation.mapping.EntryMapping; | |||
| 5 | import cuchaz.enigma.translation.mapping.EntryResolver; | 5 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 6 | 6 | ||
| 7 | public interface Translatable { | 7 | public interface Translatable { |
| 8 | |||
| 9 | TranslateResult<? extends Translatable> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings); | 8 | TranslateResult<? extends Translatable> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings); |
| 10 | 9 | ||
| 11 | @Deprecated | 10 | @Deprecated |
| 12 | default Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 11 | default Translatable translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 13 | return this.extendedTranslate(translator, resolver, mappings).getValue(); | 12 | return this.extendedTranslate(translator, resolver, mappings).getValue(); |
| 14 | } | 13 | } |
| 15 | |||
| 16 | } | 14 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java b/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java index bb26235b..0cf4acd2 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/TranslateResult.java | |||
| @@ -6,7 +6,6 @@ import java.util.function.Function; | |||
| 6 | import cuchaz.enigma.source.RenamableTokenType; | 6 | import cuchaz.enigma.source.RenamableTokenType; |
| 7 | 7 | ||
| 8 | public final class TranslateResult<T> { | 8 | public final class TranslateResult<T> { |
| 9 | |||
| 10 | private final RenamableTokenType type; | 9 | private final RenamableTokenType type; |
| 11 | private final T value; | 10 | private final T value; |
| 12 | 11 | ||
| @@ -65,11 +64,16 @@ public final class TranslateResult<T> { | |||
| 65 | 64 | ||
| 66 | @Override | 65 | @Override |
| 67 | public boolean equals(Object o) { | 66 | public boolean equals(Object o) { |
| 68 | if (this == o) return true; | 67 | if (this == o) { |
| 69 | if (o == null || getClass() != o.getClass()) return false; | 68 | return true; |
| 69 | } | ||
| 70 | |||
| 71 | if (o == null || getClass() != o.getClass()) { | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 70 | TranslateResult<?> that = (TranslateResult<?>) o; | 75 | TranslateResult<?> that = (TranslateResult<?>) o; |
| 71 | return type == that.type && | 76 | return type == that.type && Objects.equals(value, that.value); |
| 72 | Objects.equals(value, that.value); | ||
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | @Override | 79 | @Override |
| @@ -81,5 +85,4 @@ public final class TranslateResult<T> { | |||
| 81 | public String toString() { | 85 | public String toString() { |
| 82 | return String.format("TranslateResult { type: %s, value: %s }", type, value); | 86 | return String.format("TranslateResult { type: %s, value: %s }", type, value); |
| 83 | } | 87 | } |
| 84 | |||
| 85 | } | 88 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java b/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java index 2ecb30be..0725ebb8 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/TranslationDirection.java | |||
| @@ -1,24 +1,24 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation; | 12 | package cuchaz.enigma.translation; |
| 13 | 13 | ||
| 14 | public enum TranslationDirection { | 14 | public enum TranslationDirection { |
| 15 | |||
| 16 | DEOBFUSCATING { | 15 | DEOBFUSCATING { |
| 17 | @Override | 16 | @Override |
| 18 | public <T> T choose(T deobfChoice, T obfChoice) { | 17 | public <T> T choose(T deobfChoice, T obfChoice) { |
| 19 | if (deobfChoice == null) { | 18 | if (deobfChoice == null) { |
| 20 | return obfChoice; | 19 | return obfChoice; |
| 21 | } | 20 | } |
| 21 | |||
| 22 | return deobfChoice; | 22 | return deobfChoice; |
| 23 | } | 23 | } |
| 24 | }, | 24 | }, |
| @@ -28,6 +28,7 @@ public enum TranslationDirection { | |||
| 28 | if (obfChoice == null) { | 28 | if (obfChoice == null) { |
| 29 | return deobfChoice; | 29 | return deobfChoice; |
| 30 | } | 30 | } |
| 31 | |||
| 31 | return obfChoice; | 32 | return obfChoice; |
| 32 | } | 33 | } |
| 33 | }; | 34 | }; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/Translator.java b/enigma/src/main/java/cuchaz/enigma/translation/Translator.java index 66c2f9ec..ed581972 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/Translator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/Translator.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation; | 12 | package cuchaz.enigma.translation; |
| 13 | 13 | ||
| @@ -34,38 +34,40 @@ public interface Translator { | |||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | default <T extends Translatable> Collection<T> translate(Collection<T> translatable) { | 36 | default <T extends Translatable> Collection<T> translate(Collection<T> translatable) { |
| 37 | return translatable.stream() | 37 | return translatable.stream().map(this::translate).toList(); |
| 38 | .map(this::translate) | ||
| 39 | .toList(); | ||
| 40 | } | 38 | } |
| 41 | 39 | ||
| 42 | default <T extends Translatable> Set<T> translate(Set<T> translatable) { | 40 | default <T extends Translatable> Set<T> translate(Set<T> translatable) { |
| 43 | return translatable.stream() | 41 | return translatable.stream().map(this::translate).collect(Collectors.toSet()); |
| 44 | .map(this::translate) | ||
| 45 | .collect(Collectors.toSet()); | ||
| 46 | } | 42 | } |
| 47 | 43 | ||
| 48 | default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) { | 44 | default <T extends Translatable, V> Map<T, V> translateKeys(Map<T, V> translatable) { |
| 49 | Map<T, V> result = new HashMap<>(translatable.size()); | 45 | Map<T, V> result = new HashMap<>(translatable.size()); |
| 46 | |||
| 50 | for (Map.Entry<T, V> entry : translatable.entrySet()) { | 47 | for (Map.Entry<T, V> entry : translatable.entrySet()) { |
| 51 | result.put(translate(entry.getKey()), entry.getValue()); | 48 | result.put(translate(entry.getKey()), entry.getValue()); |
| 52 | } | 49 | } |
| 50 | |||
| 53 | return result; | 51 | return result; |
| 54 | } | 52 | } |
| 55 | 53 | ||
| 56 | default <K extends Translatable, V extends Translatable> Map<K, V> translate(Map<K, V> translatable) { | 54 | default <K extends Translatable, V extends Translatable> Map<K, V> translate(Map<K, V> translatable) { |
| 57 | Map<K, V> result = new HashMap<>(translatable.size()); | 55 | Map<K, V> result = new HashMap<>(translatable.size()); |
| 56 | |||
| 58 | for (Map.Entry<K, V> entry : translatable.entrySet()) { | 57 | for (Map.Entry<K, V> entry : translatable.entrySet()) { |
| 59 | result.put(translate(entry.getKey()), translate(entry.getValue())); | 58 | result.put(translate(entry.getKey()), translate(entry.getValue())); |
| 60 | } | 59 | } |
| 60 | |||
| 61 | return result; | 61 | return result; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | default <K extends Translatable, V extends Translatable> Multimap<K, V> translate(Multimap<K, V> translatable) { | 64 | default <K extends Translatable, V extends Translatable> Multimap<K, V> translate(Multimap<K, V> translatable) { |
| 65 | Multimap<K, V> result = HashMultimap.create(translatable.size(), 1); | 65 | Multimap<K, V> result = HashMultimap.create(translatable.size(), 1); |
| 66 | |||
| 66 | for (Map.Entry<K, Collection<V>> entry : translatable.asMap().entrySet()) { | 67 | for (Map.Entry<K, Collection<V>> entry : translatable.asMap().entrySet()) { |
| 67 | result.putAll(translate(entry.getKey()), translate(entry.getValue())); | 68 | result.putAll(translate(entry.getKey()), translate(entry.getValue())); |
| 68 | } | 69 | } |
| 70 | |||
| 69 | return result; | 71 | return result; |
| 70 | } | 72 | } |
| 71 | } | 73 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java b/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java index 28364f73..7d4755d0 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/VoidTranslator.java | |||
| @@ -7,5 +7,4 @@ public enum VoidTranslator implements Translator { | |||
| 7 | public <T extends Translatable> TranslateResult<T> extendedTranslate(T translatable) { | 7 | public <T extends Translatable> TranslateResult<T> extendedTranslate(T translatable) { |
| 8 | return TranslateResult.obfuscated(translatable); | 8 | return TranslateResult.obfuscated(translatable); |
| 9 | } | 9 | } |
| 10 | |||
| 11 | } | 10 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java index f57dd900..62337847 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/AccessModifier.java | |||
| @@ -3,7 +3,10 @@ package cuchaz.enigma.translation.mapping; | |||
| 3 | import cuchaz.enigma.translation.representation.AccessFlags; | 3 | import cuchaz.enigma.translation.representation.AccessFlags; |
| 4 | 4 | ||
| 5 | public enum AccessModifier { | 5 | public enum AccessModifier { |
| 6 | UNCHANGED, PUBLIC, PROTECTED, PRIVATE; | 6 | UNCHANGED, |
| 7 | PUBLIC, | ||
| 8 | PROTECTED, | ||
| 9 | PRIVATE; | ||
| 7 | 10 | ||
| 8 | public String getFormattedName() { | 11 | public String getFormattedName() { |
| 9 | return "ACC:" + super.toString(); | 12 | return "ACC:" + super.toString(); |
| @@ -11,10 +14,10 @@ public enum AccessModifier { | |||
| 11 | 14 | ||
| 12 | public AccessFlags transform(AccessFlags access) { | 15 | public AccessFlags transform(AccessFlags access) { |
| 13 | return switch (this) { | 16 | return switch (this) { |
| 14 | case PUBLIC -> access.setPublic(); | 17 | case PUBLIC -> access.setPublic(); |
| 15 | case PROTECTED -> access.setProtected(); | 18 | case PROTECTED -> access.setProtected(); |
| 16 | case PRIVATE -> access.setPrivate(); | 19 | case PRIVATE -> access.setPrivate(); |
| 17 | default -> access; | 20 | default -> access; |
| 18 | }; | 21 | }; |
| 19 | } | 22 | } |
| 20 | } | 23 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java index b5ec8552..4cd79b94 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryChange.java | |||
| @@ -11,7 +11,6 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 11 | import cuchaz.enigma.utils.TristateChange; | 11 | import cuchaz.enigma.utils.TristateChange; |
| 12 | 12 | ||
| 13 | public final class EntryChange<E extends Entry<?>> { | 13 | public final class EntryChange<E extends Entry<?>> { |
| 14 | |||
| 15 | private final E target; | 14 | private final E target; |
| 16 | private final TristateChange<String> deobfName; | 15 | private final TristateChange<String> deobfName; |
| 17 | private final TristateChange<String> javadoc; | 16 | private final TristateChange<String> javadoc; |
| @@ -75,13 +74,16 @@ public final class EntryChange<E extends Entry<?>> { | |||
| 75 | 74 | ||
| 76 | @Override | 75 | @Override |
| 77 | public boolean equals(Object o) { | 76 | public boolean equals(Object o) { |
| 78 | if (this == o) return true; | 77 | if (this == o) { |
| 79 | if (!(o instanceof EntryChange)) return false; | 78 | return true; |
| 79 | } | ||
| 80 | |||
| 81 | if (!(o instanceof EntryChange)) { | ||
| 82 | return false; | ||
| 83 | } | ||
| 84 | |||
| 80 | EntryChange<?> that = (EntryChange<?>) o; | 85 | EntryChange<?> that = (EntryChange<?>) o; |
| 81 | return Objects.equals(this.target, that.target) && | 86 | return Objects.equals(this.target, that.target) && Objects.equals(this.deobfName, that.deobfName) && Objects.equals(this.javadoc, that.javadoc) && Objects.equals(this.access, that.access); |
| 82 | Objects.equals(this.deobfName, that.deobfName) && | ||
| 83 | Objects.equals(this.javadoc, that.javadoc) && | ||
| 84 | Objects.equals(this.access, that.access); | ||
| 85 | } | 87 | } |
| 86 | 88 | ||
| 87 | @Override | 89 | @Override |
| @@ -93,5 +95,4 @@ public final class EntryChange<E extends Entry<?>> { | |||
| 93 | public String toString() { | 95 | public String toString() { |
| 94 | return String.format("EntryChange { target: %s, deobfName: %s, javadoc: %s, access: %s }", this.target, this.deobfName, this.javadoc, this.access); | 96 | return String.format("EntryChange { target: %s, deobfName: %s, javadoc: %s, access: %s }", this.target, this.deobfName, this.javadoc, this.access); |
| 95 | } | 97 | } |
| 96 | |||
| 97 | } | 98 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java index e1a32533..b398d412 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMap.java | |||
| @@ -1,9 +1,10 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | 3 | import java.util.stream.Stream; |
| 4 | 4 | ||
| 5 | import javax.annotation.Nullable; | 5 | import javax.annotation.Nullable; |
| 6 | import java.util.stream.Stream; | 6 | |
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 7 | 8 | ||
| 8 | public interface EntryMap<T> { | 9 | public interface EntryMap<T> { |
| 9 | void insert(Entry<?> entry, T value); | 10 | void insert(Entry<?> entry, T value); |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java index e916bf35..72a8fd48 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryMapping.java | |||
| @@ -5,11 +5,7 @@ import java.util.Arrays; | |||
| 5 | import javax.annotation.Nonnull; | 5 | import javax.annotation.Nonnull; |
| 6 | import javax.annotation.Nullable; | 6 | import javax.annotation.Nullable; |
| 7 | 7 | ||
| 8 | public record EntryMapping( | 8 | public record EntryMapping(@Nullable String targetName, @Nonnull AccessModifier accessModifier, @Nullable String javadoc) { |
| 9 | @Nullable String targetName, | ||
| 10 | @Nonnull AccessModifier accessModifier, | ||
| 11 | @Nullable String javadoc | ||
| 12 | ) { | ||
| 13 | public static final EntryMapping DEFAULT = new EntryMapping(null, AccessModifier.UNCHANGED, null); | 9 | public static final EntryMapping DEFAULT = new EntryMapping(null, AccessModifier.UNCHANGED, null); |
| 14 | 10 | ||
| 15 | public EntryMapping { | 11 | public EntryMapping { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java index 0268834d..ed5dba59 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryRemapper.java | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | 3 | import java.util.Collection; |
| 4 | import java.util.Objects; | ||
| 5 | import java.util.List; | 4 | import java.util.List; |
| 5 | import java.util.Objects; | ||
| 6 | import java.util.stream.Stream; | 6 | import java.util.stream.Stream; |
| 7 | 7 | ||
| 8 | import javax.annotation.Nonnull; | 8 | import javax.annotation.Nonnull; |
| @@ -18,7 +18,6 @@ import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.Entry; | 19 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 20 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 20 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 21 | |||
| 22 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 23 | import cuchaz.enigma.utils.validation.Message; | 22 | import cuchaz.enigma.utils.validation.Message; |
| 24 | import cuchaz.enigma.utils.validation.ValidationContext; | 23 | import cuchaz.enigma.utils.validation.ValidationContext; |
| @@ -77,7 +76,9 @@ public class EntryRemapper { | |||
| 77 | } | 76 | } |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | if (validateOnly || !vc.canProceed()) return; | 79 | if (validateOnly || !vc.canProceed()) { |
| 80 | return; | ||
| 81 | } | ||
| 81 | 82 | ||
| 82 | for (Entry<?> resolvedEntry : resolvedEntries) { | 83 | for (Entry<?> resolvedEntry : resolvedEntries) { |
| 83 | if (deobfMapping.equals(EntryMapping.DEFAULT)) { | 84 | if (deobfMapping.equals(EntryMapping.DEFAULT)) { |
| @@ -95,9 +96,7 @@ public class EntryRemapper { | |||
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | // Find all the methods in this record class | 98 | // Find all the methods in this record class |
| 98 | List<MethodEntry> classMethods = jarIndex.getEntryIndex().getMethods().stream() | 99 | List<MethodEntry> classMethods = jarIndex.getEntryIndex().getMethods().stream().filter(entry -> classEntry.equals(entry.getParent())).toList(); |
| 99 | .filter(entry -> classEntry.equals(entry.getParent())) | ||
| 100 | .toList(); | ||
| 101 | 100 | ||
| 102 | MethodEntry methodEntry = null; | 101 | MethodEntry methodEntry = null; |
| 103 | 102 | ||
| @@ -163,5 +162,4 @@ public class EntryRemapper { | |||
| 163 | public MappingValidator getValidator() { | 162 | public MappingValidator getValidator() { |
| 164 | return validator; | 163 | return validator; |
| 165 | } | 164 | } |
| 166 | |||
| 167 | } | 165 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java index 9dd0c3aa..39e68259 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryResolver.java | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.Set; | ||
| 5 | |||
| 3 | import com.google.common.collect.Streams; | 6 | import com.google.common.collect.Streams; |
| 7 | |||
| 4 | import cuchaz.enigma.analysis.EntryReference; | 8 | import cuchaz.enigma.analysis.EntryReference; |
| 5 | import cuchaz.enigma.translation.representation.entry.Entry; | 9 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 6 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 10 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 7 | 11 | ||
| 8 | import java.util.Collection; | ||
| 9 | import java.util.Set; | ||
| 10 | |||
| 11 | public interface EntryResolver { | 12 | public interface EntryResolver { |
| 12 | <E extends Entry<?>> Collection<E> resolveEntry(E entry, ResolutionStrategy strategy); | 13 | <E extends Entry<?>> Collection<E> resolveEntry(E entry, ResolutionStrategy strategy); |
| 13 | 14 | ||
| @@ -17,14 +18,12 @@ public interface EntryResolver { | |||
| 17 | 18 | ||
| 18 | default <E extends Entry<?>, C extends Entry<?>> Collection<EntryReference<E, C>> resolveReference(EntryReference<E, C> reference, ResolutionStrategy strategy) { | 19 | default <E extends Entry<?>, C extends Entry<?>> Collection<EntryReference<E, C>> resolveReference(EntryReference<E, C> reference, ResolutionStrategy strategy) { |
| 19 | Collection<E> entry = resolveEntry(reference.entry, strategy); | 20 | Collection<E> entry = resolveEntry(reference.entry, strategy); |
| 21 | |||
| 20 | if (reference.context != null) { | 22 | if (reference.context != null) { |
| 21 | Collection<C> context = resolveEntry(reference.context, strategy); | 23 | Collection<C> context = resolveEntry(reference.context, strategy); |
| 22 | return Streams.zip(entry.stream(), context.stream(), (e, c) -> new EntryReference<>(e, c, reference)) | 24 | return Streams.zip(entry.stream(), context.stream(), (e, c) -> new EntryReference<>(e, c, reference)).toList(); |
| 23 | .toList(); | ||
| 24 | } else { | 25 | } else { |
| 25 | return entry.stream() | 26 | return entry.stream().map(e -> new EntryReference<>(e, null, reference)).toList(); |
| 26 | .map(e -> new EntryReference<>(e, null, reference)) | ||
| 27 | .toList(); | ||
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | 29 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java index 582076c1..f9a10600 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/EntryUtil.java | |||
| @@ -6,7 +6,6 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 6 | import cuchaz.enigma.utils.validation.ValidationContext; | 6 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 7 | 7 | ||
| 8 | public class EntryUtil { | 8 | public class EntryUtil { |
| 9 | |||
| 10 | public static EntryMapping applyChange(ValidationContext vc, EntryRemapper remapper, EntryChange<?> change) { | 9 | public static EntryMapping applyChange(ValidationContext vc, EntryRemapper remapper, EntryChange<?> change) { |
| 11 | Entry<?> target = change.getTarget(); | 10 | Entry<?> target = change.getTarget(); |
| 12 | EntryMapping prev = remapper.getDeobfMapping(target); | 11 | EntryMapping prev = remapper.getDeobfMapping(target); |
| @@ -38,5 +37,4 @@ public class EntryUtil { | |||
| 38 | 37 | ||
| 39 | return self; | 38 | return self; |
| 40 | } | 39 | } |
| 41 | |||
| 42 | } | 40 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java index e3aeb205..06e8d762 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IdentifierValidation.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.mapping; | 12 | package cuchaz.enigma.translation.mapping; |
| 13 | 13 | ||
| @@ -18,21 +18,17 @@ import cuchaz.enigma.utils.validation.StandardValidation; | |||
| 18 | import cuchaz.enigma.utils.validation.ValidationContext; | 18 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 19 | 19 | ||
| 20 | public final class IdentifierValidation { | 20 | public final class IdentifierValidation { |
| 21 | |||
| 22 | private IdentifierValidation() { | 21 | private IdentifierValidation() { |
| 23 | } | 22 | } |
| 24 | 23 | ||
| 25 | private static final List<String> ILLEGAL_IDENTIFIERS = List.of( | 24 | private static final List<String> ILLEGAL_IDENTIFIERS = List.of("abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", |
| 26 | "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", | 25 | "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", |
| 27 | "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", | 26 | "transient", "true", "try", "void", "volatile", "while", "_"); |
| 28 | "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", | ||
| 29 | "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", | ||
| 30 | "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", | ||
| 31 | "void", "volatile", "while", "_" | ||
| 32 | ); | ||
| 33 | 27 | ||
| 34 | public static boolean validateClassName(ValidationContext vc, String name, boolean isInner) { | 28 | public static boolean validateClassName(ValidationContext vc, String name, boolean isInner) { |
| 35 | if (!StandardValidation.notBlank(vc, name)) return false; | 29 | if (!StandardValidation.notBlank(vc, name)) { |
| 30 | return false; | ||
| 31 | } | ||
| 36 | 32 | ||
| 37 | if (isInner) { | 33 | if (isInner) { |
| 38 | // When renaming, inner class names do not contain the package name, | 34 | // When renaming, inner class names do not contain the package name, |
| @@ -41,27 +37,37 @@ public final class IdentifierValidation { | |||
| 41 | } | 37 | } |
| 42 | 38 | ||
| 43 | String[] parts = name.split("/"); | 39 | String[] parts = name.split("/"); |
| 40 | |||
| 44 | for (String part : parts) { | 41 | for (String part : parts) { |
| 45 | validateIdentifier(vc, part); | 42 | validateIdentifier(vc, part); |
| 46 | } | 43 | } |
| 44 | |||
| 47 | return true; | 45 | return true; |
| 48 | } | 46 | } |
| 49 | 47 | ||
| 50 | public static boolean validateIdentifier(ValidationContext vc, String name) { | 48 | public static boolean validateIdentifier(ValidationContext vc, String name) { |
| 51 | if (!StandardValidation.notBlank(vc, name)) return false; | 49 | if (!StandardValidation.notBlank(vc, name)) { |
| 52 | if (checkForReservedName(vc, name)) return false; | 50 | return false; |
| 51 | } | ||
| 52 | |||
| 53 | if (checkForReservedName(vc, name)) { | ||
| 54 | return false; | ||
| 55 | } | ||
| 53 | 56 | ||
| 54 | // Adapted from javax.lang.model.SourceVersion.isIdentifier | 57 | // Adapted from javax.lang.model.SourceVersion.isIdentifier |
| 55 | 58 | ||
| 56 | int cp = name.codePointAt(0); | 59 | int cp = name.codePointAt(0); |
| 57 | int position = 1; | 60 | int position = 1; |
| 61 | |||
| 58 | if (!Character.isJavaIdentifierStart(cp)) { | 62 | if (!Character.isJavaIdentifierStart(cp)) { |
| 59 | vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); | 63 | vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); |
| 60 | return false; | 64 | return false; |
| 61 | } | 65 | } |
| 66 | |||
| 62 | for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) { | 67 | for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) { |
| 63 | cp = name.codePointAt(i); | 68 | cp = name.codePointAt(i); |
| 64 | position += 1; | 69 | position += 1; |
| 70 | |||
| 65 | if (!Character.isJavaIdentifierPart(cp)) { | 71 | if (!Character.isJavaIdentifierPart(cp)) { |
| 66 | vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); | 72 | vc.raise(Message.ILLEGAL_IDENTIFIER, name, new String(Character.toChars(cp)), position); |
| 67 | return false; | 73 | return false; |
| @@ -76,11 +82,11 @@ public final class IdentifierValidation { | |||
| 76 | vc.raise(Message.RESERVED_IDENTIFIER, name); | 82 | vc.raise(Message.RESERVED_IDENTIFIER, name); |
| 77 | return true; | 83 | return true; |
| 78 | } | 84 | } |
| 85 | |||
| 79 | return false; | 86 | return false; |
| 80 | } | 87 | } |
| 81 | 88 | ||
| 82 | public static boolean isReservedMethodName(String name) { | 89 | public static boolean isReservedMethodName(String name) { |
| 83 | return ILLEGAL_IDENTIFIERS.contains(name); | 90 | return ILLEGAL_IDENTIFIERS.contains(name); |
| 84 | } | 91 | } |
| 85 | |||
| 86 | } | 92 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java index 00168ba7..8dc56599 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/IndexEntryResolver.java | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.Collection; |
| 4 | import java.util.Collections; | ||
| 5 | import java.util.HashSet; | ||
| 6 | import java.util.List; | ||
| 7 | import java.util.Set; | ||
| 4 | 8 | ||
| 5 | import javax.annotation.Nullable; | 9 | import javax.annotation.Nullable; |
| 6 | 10 | ||
| @@ -40,6 +44,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 40 | } | 44 | } |
| 41 | 45 | ||
| 42 | Entry<ClassEntry> classChild = getClassChild(entry); | 46 | Entry<ClassEntry> classChild = getClassChild(entry); |
| 47 | |||
| 43 | if (classChild != null && !(classChild instanceof ClassEntry)) { | 48 | if (classChild != null && !(classChild instanceof ClassEntry)) { |
| 44 | AccessFlags access = entryIndex.getEntryAccess(classChild); | 49 | AccessFlags access = entryIndex.getEntryAccess(classChild); |
| 45 | 50 | ||
| @@ -50,10 +55,9 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 50 | 55 | ||
| 51 | if (access == null || !access.isPrivate()) { | 56 | if (access == null || !access.isPrivate()) { |
| 52 | Collection<Entry<ClassEntry>> resolvedChildren = resolveChildEntry(classChild, strategy); | 57 | Collection<Entry<ClassEntry>> resolvedChildren = resolveChildEntry(classChild, strategy); |
| 58 | |||
| 53 | if (!resolvedChildren.isEmpty()) { | 59 | if (!resolvedChildren.isEmpty()) { |
| 54 | return resolvedChildren.stream() | 60 | return resolvedChildren.stream().map(resolvedChild -> (E) entry.replaceAncestor(classChild, resolvedChild)).toList(); |
| 55 | .map(resolvedChild -> (E) entry.replaceAncestor(classChild, resolvedChild)) | ||
| 56 | .toList(); | ||
| 57 | } | 61 | } |
| 58 | } | 62 | } |
| 59 | } | 63 | } |
| @@ -69,9 +73,11 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 69 | 73 | ||
| 70 | // get the entry in the hierarchy that is the child of a class | 74 | // get the entry in the hierarchy that is the child of a class |
| 71 | List<Entry<?>> ancestry = entry.getAncestry(); | 75 | List<Entry<?>> ancestry = entry.getAncestry(); |
| 76 | |||
| 72 | for (int i = ancestry.size() - 1; i > 0; i--) { | 77 | for (int i = ancestry.size() - 1; i > 0; i--) { |
| 73 | Entry<?> child = ancestry.get(i); | 78 | Entry<?> child = ancestry.get(i); |
| 74 | Entry<ClassEntry> cast = child.castParent(ClassEntry.class); | 79 | Entry<ClassEntry> cast = child.castParent(ClassEntry.class); |
| 80 | |||
| 75 | if (cast != null && !(cast instanceof ClassEntry)) { | 81 | if (cast != null && !(cast instanceof ClassEntry)) { |
| 76 | // we found the entry which is a child of a class, we are now able to resolve the owner of this entry | 82 | // we found the entry which is a child of a class, we are now able to resolve the owner of this entry |
| 77 | return cast; | 83 | return cast; |
| @@ -86,8 +92,10 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 86 | 92 | ||
| 87 | if (entry instanceof MethodEntry) { | 93 | if (entry instanceof MethodEntry) { |
| 88 | MethodEntry bridgeMethod = bridgeMethodIndex.getBridgeFromSpecialized((MethodEntry) entry); | 94 | MethodEntry bridgeMethod = bridgeMethodIndex.getBridgeFromSpecialized((MethodEntry) entry); |
| 95 | |||
| 89 | if (bridgeMethod != null && ownerClass.equals(bridgeMethod.getParent())) { | 96 | if (bridgeMethod != null && ownerClass.equals(bridgeMethod.getParent())) { |
| 90 | Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy); | 97 | Set<Entry<ClassEntry>> resolvedBridge = resolveChildEntry(bridgeMethod, strategy); |
| 98 | |||
| 91 | if (!resolvedBridge.isEmpty()) { | 99 | if (!resolvedBridge.isEmpty()) { |
| 92 | return resolvedBridge; | 100 | return resolvedBridge; |
| 93 | } else { | 101 | } else { |
| @@ -117,6 +125,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 117 | 125 | ||
| 118 | if (parentResolution.isEmpty()) { | 126 | if (parentResolution.isEmpty()) { |
| 119 | AccessFlags parentAccess = entryIndex.getEntryAccess(entry); | 127 | AccessFlags parentAccess = entryIndex.getEntryAccess(entry); |
| 128 | |||
| 120 | if (parentAccess != null && !parentAccess.isPrivate()) { | 129 | if (parentAccess != null && !parentAccess.isPrivate()) { |
| 121 | return Collections.singleton(entry); | 130 | return Collections.singleton(entry); |
| 122 | } | 131 | } |
| @@ -128,6 +137,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 128 | private Collection<Entry<ClassEntry>> resolveClosest(Entry<ClassEntry> entry, ResolutionStrategy strategy) { | 137 | private Collection<Entry<ClassEntry>> resolveClosest(Entry<ClassEntry> entry, ResolutionStrategy strategy) { |
| 129 | // When resolving closest, we want to first check if we exist before looking further down | 138 | // When resolving closest, we want to first check if we exist before looking further down |
| 130 | AccessFlags parentAccess = entryIndex.getEntryAccess(entry); | 139 | AccessFlags parentAccess = entryIndex.getEntryAccess(entry); |
| 140 | |||
| 131 | if (parentAccess != null && !parentAccess.isPrivate()) { | 141 | if (parentAccess != null && !parentAccess.isPrivate()) { |
| 132 | return Collections.singleton(entry); | 142 | return Collections.singleton(entry); |
| 133 | } else { | 143 | } else { |
| @@ -138,6 +148,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 138 | @Override | 148 | @Override |
| 139 | public Set<Entry<?>> resolveEquivalentEntries(Entry<?> entry) { | 149 | public Set<Entry<?>> resolveEquivalentEntries(Entry<?> entry) { |
| 140 | MethodEntry relevantMethod = entry.findAncestor(MethodEntry.class); | 150 | MethodEntry relevantMethod = entry.findAncestor(MethodEntry.class); |
| 151 | |||
| 141 | if (relevantMethod == null || !entryIndex.hasMethod(relevantMethod)) { | 152 | if (relevantMethod == null || !entryIndex.hasMethod(relevantMethod)) { |
| 142 | return Collections.singleton(entry); | 153 | return Collections.singleton(entry); |
| 143 | } | 154 | } |
| @@ -162,6 +173,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 162 | 173 | ||
| 163 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodEntry methodEntry) { | 174 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodEntry methodEntry) { |
| 164 | AccessFlags access = entryIndex.getMethodAccess(methodEntry); | 175 | AccessFlags access = entryIndex.getMethodAccess(methodEntry); |
| 176 | |||
| 165 | if (access == null) { | 177 | if (access == null) { |
| 166 | throw new IllegalArgumentException("Could not find method " + methodEntry); | 178 | throw new IllegalArgumentException("Could not find method " + methodEntry); |
| 167 | } | 179 | } |
| @@ -176,11 +188,13 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 176 | 188 | ||
| 177 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) { | 189 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node) { |
| 178 | MethodEntry methodEntry = node.getMethodEntry(); | 190 | MethodEntry methodEntry = node.getMethodEntry(); |
| 191 | |||
| 179 | if (methodEntries.contains(methodEntry)) { | 192 | if (methodEntries.contains(methodEntry)) { |
| 180 | return; | 193 | return; |
| 181 | } | 194 | } |
| 182 | 195 | ||
| 183 | AccessFlags flags = entryIndex.getMethodAccess(methodEntry); | 196 | AccessFlags flags = entryIndex.getMethodAccess(methodEntry); |
| 197 | |||
| 184 | if (flags != null && canInherit(methodEntry, flags)) { | 198 | if (flags != null && canInherit(methodEntry, flags)) { |
| 185 | // collect the entry | 199 | // collect the entry |
| 186 | methodEntries.add(methodEntry); | 200 | methodEntries.add(methodEntry); |
| @@ -188,6 +202,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 188 | 202 | ||
| 189 | // look at bridge methods! | 203 | // look at bridge methods! |
| 190 | MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); | 204 | MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); |
| 205 | |||
| 191 | while (bridgedMethod != null) { | 206 | while (bridgedMethod != null) { |
| 192 | resolveEquivalentMethods(methodEntries, bridgedMethod); | 207 | resolveEquivalentMethods(methodEntries, bridgedMethod); |
| 193 | bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); | 208 | bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); |
| @@ -207,6 +222,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 207 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) { | 222 | private void resolveEquivalentMethods(Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node) { |
| 208 | MethodEntry methodEntry = node.getMethodEntry(); | 223 | MethodEntry methodEntry = node.getMethodEntry(); |
| 209 | AccessFlags flags = entryIndex.getMethodAccess(methodEntry); | 224 | AccessFlags flags = entryIndex.getMethodAccess(methodEntry); |
| 225 | |||
| 210 | if (flags != null && !flags.isPrivate() && !flags.isStatic()) { | 226 | if (flags != null && !flags.isPrivate() && !flags.isStatic()) { |
| 211 | // collect the entry | 227 | // collect the entry |
| 212 | methodEntries.add(methodEntry); | 228 | methodEntries.add(methodEntry); |
| @@ -214,6 +230,7 @@ public class IndexEntryResolver implements EntryResolver { | |||
| 214 | 230 | ||
| 215 | // look at bridge methods! | 231 | // look at bridge methods! |
| 216 | MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); | 232 | MethodEntry bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(methodEntry); |
| 233 | |||
| 217 | while (bridgedMethod != null) { | 234 | while (bridgedMethod != null) { |
| 218 | resolveEquivalentMethods(methodEntries, bridgedMethod); | 235 | resolveEquivalentMethods(methodEntries, bridgedMethod); |
| 219 | bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); | 236 | bridgedMethod = bridgeMethodIndex.getBridgeFromSpecialized(bridgedMethod); |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java index 250851ce..765c1f2a 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingDelta.java | |||
| @@ -49,9 +49,6 @@ public class MappingDelta<T> implements Translatable { | |||
| 49 | public TranslateResult<MappingDelta<T>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 49 | public TranslateResult<MappingDelta<T>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 50 | // there's no concept of deobfuscated for this as far as I can see, so | 50 | // there's no concept of deobfuscated for this as far as I can see, so |
| 51 | // it will always be marked as obfuscated | 51 | // it will always be marked as obfuscated |
| 52 | return TranslateResult.ungrouped(new MappingDelta<>( | 52 | return TranslateResult.ungrouped(new MappingDelta<>(translator.translate(baseMappings), translator.translate(changes))); |
| 53 | translator.translate(baseMappings), | ||
| 54 | translator.translate(changes) | ||
| 55 | )); | ||
| 56 | } | 53 | } |
| 57 | } | 54 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java index 2c037484..3b756c66 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingOperations.java | |||
| @@ -1,71 +1,74 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.util.HashSet; | ||
| 4 | import java.util.Set; | ||
| 5 | |||
| 6 | import cuchaz.enigma.translation.MappingTranslator; | ||
| 7 | import cuchaz.enigma.translation.Translator; | ||
| 3 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 4 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 9 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| 5 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | 10 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; |
| 6 | import cuchaz.enigma.translation.MappingTranslator; | ||
| 7 | import cuchaz.enigma.translation.Translator; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 11 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | 12 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 10 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 11 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 12 | 15 | ||
| 13 | import java.util.HashSet; | ||
| 14 | import java.util.Set; | ||
| 15 | |||
| 16 | public class MappingOperations { | 16 | public class MappingOperations { |
| 17 | public static EntryTree<EntryMapping> invert(EntryTree<EntryMapping> mappings) { | 17 | public static EntryTree<EntryMapping> invert(EntryTree<EntryMapping> mappings) { |
| 18 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | 18 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); |
| 19 | EntryTree<EntryMapping> result = new HashEntryTree<>(); | 19 | EntryTree<EntryMapping> result = new HashEntryTree<>(); |
| 20 | 20 | ||
| 21 | for (EntryTreeNode<EntryMapping> node : mappings) { | 21 | for (EntryTreeNode<EntryMapping> node : mappings) { |
| 22 | Entry<?> leftEntry = node.getEntry(); | 22 | Entry<?> leftEntry = node.getEntry(); |
| 23 | EntryMapping leftMapping = node.getValue(); | 23 | EntryMapping leftMapping = node.getValue(); |
| 24 | 24 | ||
| 25 | if (!(leftEntry instanceof ClassEntry || leftEntry instanceof MethodEntry || leftEntry instanceof FieldEntry)) { | 25 | if (!(leftEntry instanceof ClassEntry || leftEntry instanceof MethodEntry || leftEntry instanceof FieldEntry)) { |
| 26 | result.insert(translator.translate(leftEntry), leftMapping); | 26 | result.insert(translator.translate(leftEntry), leftMapping); |
| 27 | continue; | 27 | continue; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | Entry<?> rightEntry = translator.translate(leftEntry); | 30 | Entry<?> rightEntry = translator.translate(leftEntry); |
| 31 | 31 | ||
| 32 | result.insert(rightEntry, leftMapping == null ? null : leftMapping.withName(leftEntry.getName())); | 32 | result.insert(rightEntry, leftMapping == null ? null : leftMapping.withName(leftEntry.getName())); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | return result; | 35 | return result; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | public static EntryTree<EntryMapping> compose(EntryTree<EntryMapping> left, EntryTree<EntryMapping> right, boolean keepLeftOnly, boolean keepRightOnly) { | 38 | public static EntryTree<EntryMapping> compose(EntryTree<EntryMapping> left, EntryTree<EntryMapping> right, boolean keepLeftOnly, boolean keepRightOnly) { |
| 39 | Translator leftTranslator = new MappingTranslator(left, VoidEntryResolver.INSTANCE); | 39 | Translator leftTranslator = new MappingTranslator(left, VoidEntryResolver.INSTANCE); |
| 40 | EntryTree<EntryMapping> result = new HashEntryTree<>(); | 40 | EntryTree<EntryMapping> result = new HashEntryTree<>(); |
| 41 | Set<Entry<?>> addedMappings = new HashSet<>(); | 41 | Set<Entry<?>> addedMappings = new HashSet<>(); |
| 42 | 42 | ||
| 43 | for (EntryTreeNode<EntryMapping> node : left) { | 43 | for (EntryTreeNode<EntryMapping> node : left) { |
| 44 | Entry<?> leftEntry = node.getEntry(); | 44 | Entry<?> leftEntry = node.getEntry(); |
| 45 | EntryMapping leftMapping = node.getValue(); | 45 | EntryMapping leftMapping = node.getValue(); |
| 46 | 46 | ||
| 47 | Entry<?> rightEntry = leftTranslator.translate(leftEntry); | 47 | Entry<?> rightEntry = leftTranslator.translate(leftEntry); |
| 48 | 48 | ||
| 49 | EntryMapping rightMapping = right.get(rightEntry); | 49 | EntryMapping rightMapping = right.get(rightEntry); |
| 50 | if (rightMapping != null) { | 50 | |
| 51 | result.insert(leftEntry, rightMapping); | 51 | if (rightMapping != null) { |
| 52 | addedMappings.add(rightEntry); | 52 | result.insert(leftEntry, rightMapping); |
| 53 | } else if (keepLeftOnly) { | 53 | addedMappings.add(rightEntry); |
| 54 | result.insert(leftEntry, leftMapping); | 54 | } else if (keepLeftOnly) { |
| 55 | } | 55 | result.insert(leftEntry, leftMapping); |
| 56 | } | 56 | } |
| 57 | 57 | } | |
| 58 | if (keepRightOnly) { | 58 | |
| 59 | Translator leftInverseTranslator = new MappingTranslator(invert(left), VoidEntryResolver.INSTANCE); | 59 | if (keepRightOnly) { |
| 60 | for (EntryTreeNode<EntryMapping> node : right) { | 60 | Translator leftInverseTranslator = new MappingTranslator(invert(left), VoidEntryResolver.INSTANCE); |
| 61 | Entry<?> rightEntry = node.getEntry(); | 61 | |
| 62 | EntryMapping rightMapping = node.getValue(); | 62 | for (EntryTreeNode<EntryMapping> node : right) { |
| 63 | 63 | Entry<?> rightEntry = node.getEntry(); | |
| 64 | if (!addedMappings.contains(rightEntry)) { | 64 | EntryMapping rightMapping = node.getValue(); |
| 65 | result.insert(leftInverseTranslator.translate(rightEntry), rightMapping); | 65 | |
| 66 | } | 66 | if (!addedMappings.contains(rightEntry)) { |
| 67 | } | 67 | result.insert(leftInverseTranslator.translate(rightEntry), rightMapping); |
| 68 | } | 68 | } |
| 69 | return result; | 69 | } |
| 70 | } | 70 | } |
| 71 | |||
| 72 | return result; | ||
| 73 | } | ||
| 71 | } | 74 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java index 5d39e3d2..21c78cfd 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingPair.java | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 4 | |||
| 5 | import javax.annotation.Nullable; | 3 | import javax.annotation.Nullable; |
| 6 | 4 | ||
| 5 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 6 | |||
| 7 | public class MappingPair<E extends Entry<?>, M> { | 7 | public class MappingPair<E extends Entry<?>, M> { |
| 8 | private final E entry; | 8 | private final E entry; |
| 9 | private M mapping; | 9 | private M mapping; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java index 065e5c3e..5f42373c 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingValidator.java | |||
| @@ -14,7 +14,6 @@ import cuchaz.enigma.utils.validation.Message; | |||
| 14 | import cuchaz.enigma.utils.validation.ValidationContext; | 14 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 15 | 15 | ||
| 16 | public class MappingValidator { | 16 | public class MappingValidator { |
| 17 | |||
| 18 | private final EntryTree<EntryMapping> obfToDeobf; | 17 | private final EntryTree<EntryMapping> obfToDeobf; |
| 19 | private final Translator deobfuscator; | 18 | private final Translator deobfuscator; |
| 20 | private final JarIndex index; | 19 | private final JarIndex index; |
| @@ -28,10 +27,12 @@ public class MappingValidator { | |||
| 28 | public boolean validateRename(ValidationContext vc, Entry<?> entry, String name) { | 27 | public boolean validateRename(ValidationContext vc, Entry<?> entry, String name) { |
| 29 | Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry); | 28 | Collection<Entry<?>> equivalentEntries = index.getEntryResolver().resolveEquivalentEntries(entry); |
| 30 | boolean error = false; | 29 | boolean error = false; |
| 30 | |||
| 31 | for (Entry<?> equivalentEntry : equivalentEntries) { | 31 | for (Entry<?> equivalentEntry : equivalentEntries) { |
| 32 | equivalentEntry.validateName(vc, name); | 32 | equivalentEntry.validateName(vc, name); |
| 33 | error |= validateUnique(vc, equivalentEntry, name); | 33 | error |= validateUnique(vc, equivalentEntry, name); |
| 34 | } | 34 | } |
| 35 | |||
| 35 | return error; | 36 | return error; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| @@ -45,17 +46,17 @@ public class MappingValidator { | |||
| 45 | Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass); | 46 | Entry<?> relatedEntry = entry.replaceAncestor(containingClass, relatedClass); |
| 46 | Entry<?> translatedEntry = deobfuscator.translate(relatedEntry); | 47 | Entry<?> translatedEntry = deobfuscator.translate(relatedEntry); |
| 47 | 48 | ||
| 48 | List<? extends Entry<?>> translatedSiblings = obfToDeobf.getSiblings(relatedEntry).stream() | 49 | List<? extends Entry<?>> translatedSiblings = obfToDeobf.getSiblings(relatedEntry).stream().map(deobfuscator::translate).toList(); |
| 49 | .map(deobfuscator::translate) | ||
| 50 | .toList(); | ||
| 51 | 50 | ||
| 52 | if (!isUnique(translatedEntry, translatedSiblings, name)) { | 51 | if (!isUnique(translatedEntry, translatedSiblings, name)) { |
| 53 | Entry<?> parent = translatedEntry.getParent(); | 52 | Entry<?> parent = translatedEntry.getParent(); |
| 53 | |||
| 54 | if (parent != null) { | 54 | if (parent != null) { |
| 55 | vc.raise(Message.NONUNIQUE_NAME_CLASS, name, parent); | 55 | vc.raise(Message.NONUNIQUE_NAME_CLASS, name, parent); |
| 56 | } else { | 56 | } else { |
| 57 | vc.raise(Message.NONUNIQUE_NAME, name); | 57 | vc.raise(Message.NONUNIQUE_NAME, name); |
| 58 | } | 58 | } |
| 59 | |||
| 59 | error = true; | 60 | error = true; |
| 60 | } | 61 | } |
| 61 | } | 62 | } |
| @@ -80,7 +81,7 @@ public class MappingValidator { | |||
| 80 | return false; | 81 | return false; |
| 81 | } | 82 | } |
| 82 | } | 83 | } |
| 84 | |||
| 83 | return true; | 85 | return true; |
| 84 | } | 86 | } |
| 85 | |||
| 86 | } | 87 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java index 33247fa6..dc8055b7 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/MappingsChecker.java | |||
| @@ -1,16 +1,20 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.mapping; | 12 | package cuchaz.enigma.translation.mapping; |
| 13 | 13 | ||
| 14 | import java.util.Collection; | ||
| 15 | import java.util.HashMap; | ||
| 16 | import java.util.Map; | ||
| 17 | |||
| 14 | import cuchaz.enigma.ProgressListener; | 18 | import cuchaz.enigma.ProgressListener; |
| 15 | import cuchaz.enigma.analysis.index.JarIndex; | 19 | import cuchaz.enigma.analysis.index.JarIndex; |
| 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 20 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| @@ -21,10 +25,6 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 21 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | 25 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; |
| 22 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 26 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 23 | 27 | ||
| 24 | import java.util.Collection; | ||
| 25 | import java.util.HashMap; | ||
| 26 | import java.util.Map; | ||
| 27 | |||
| 28 | public class MappingsChecker { | 28 | public class MappingsChecker { |
| 29 | private final JarIndex index; | 29 | private final JarIndex index; |
| 30 | private final EntryTree<EntryMapping> mappings; | 30 | private final EntryTree<EntryMapping> mappings; |
| @@ -37,13 +37,12 @@ public class MappingsChecker { | |||
| 37 | public Dropped dropBrokenMappings(ProgressListener progress) { | 37 | public Dropped dropBrokenMappings(ProgressListener progress) { |
| 38 | Dropped dropped = new Dropped(); | 38 | Dropped dropped = new Dropped(); |
| 39 | 39 | ||
| 40 | Collection<Entry<?>> obfEntries = mappings.getAllEntries() | 40 | Collection<Entry<?>> obfEntries = mappings.getAllEntries().filter(e -> e instanceof ClassEntry || e instanceof MethodEntry || e instanceof FieldEntry || e instanceof LocalVariableEntry).toList(); |
| 41 | .filter(e -> e instanceof ClassEntry || e instanceof MethodEntry || e instanceof FieldEntry || e instanceof LocalVariableEntry) | ||
| 42 | .toList(); | ||
| 43 | 41 | ||
| 44 | progress.init(obfEntries.size(), "Checking for dropped mappings"); | 42 | progress.init(obfEntries.size(), "Checking for dropped mappings"); |
| 45 | 43 | ||
| 46 | int steps = 0; | 44 | int steps = 0; |
| 45 | |||
| 47 | for (Entry<?> entry : obfEntries) { | 46 | for (Entry<?> entry : obfEntries) { |
| 48 | progress.step(steps++, entry.toString()); | 47 | progress.step(steps++, entry.toString()); |
| 49 | tryDropEntry(dropped, entry); | 48 | tryDropEntry(dropped, entry); |
| @@ -57,6 +56,7 @@ public class MappingsChecker { | |||
| 57 | private void tryDropEntry(Dropped dropped, Entry<?> entry) { | 56 | private void tryDropEntry(Dropped dropped, Entry<?> entry) { |
| 58 | if (shouldDropEntry(entry)) { | 57 | if (shouldDropEntry(entry)) { |
| 59 | EntryMapping mapping = mappings.get(entry); | 58 | EntryMapping mapping = mappings.get(entry); |
| 59 | |||
| 60 | if (mapping != null) { | 60 | if (mapping != null) { |
| 61 | dropped.drop(entry, mapping); | 61 | dropped.drop(entry, mapping); |
| 62 | } | 62 | } |
| @@ -102,6 +102,7 @@ public class MappingsChecker { | |||
| 102 | void apply(EntryTree<EntryMapping> mappings) { | 102 | void apply(EntryTree<EntryMapping> mappings) { |
| 103 | for (Entry<?> entry : droppedMappings.keySet()) { | 103 | for (Entry<?> entry : droppedMappings.keySet()) { |
| 104 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | 104 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); |
| 105 | |||
| 105 | if (node == null) { | 106 | if (node == null) { |
| 106 | continue; | 107 | continue; |
| 107 | } | 108 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java index 2eab55fd..19975721 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/VoidEntryResolver.java | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 4 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 5 | |||
| 6 | import java.util.Collection; | 3 | import java.util.Collection; |
| 7 | import java.util.Collections; | 4 | import java.util.Collections; |
| 8 | import java.util.Set; | 5 | import java.util.Set; |
| 9 | 6 | ||
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 8 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 9 | |||
| 10 | public enum VoidEntryResolver implements EntryResolver { | 10 | public enum VoidEntryResolver implements EntryResolver { |
| 11 | INSTANCE; | 11 | INSTANCE; |
| 12 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java index 441949c6..f118e64a 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/LfPrintWriter.java | |||
| @@ -4,13 +4,13 @@ import java.io.PrintWriter; | |||
| 4 | import java.io.Writer; | 4 | import java.io.Writer; |
| 5 | 5 | ||
| 6 | public class LfPrintWriter extends PrintWriter { | 6 | public class LfPrintWriter extends PrintWriter { |
| 7 | public LfPrintWriter(Writer out) { | 7 | public LfPrintWriter(Writer out) { |
| 8 | super(out); | 8 | super(out); |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | @Override | 11 | @Override |
| 12 | public void println() { | 12 | public void println() { |
| 13 | // https://stackoverflow.com/a/14749004 | 13 | // https://stackoverflow.com/a/14749004 |
| 14 | write('\n'); | 14 | write('\n'); |
| 15 | } | 15 | } |
| 16 | } | 16 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java index 062c8775..3be80481 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingFormat.java | |||
| @@ -1,5 +1,10 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | 1 | package cuchaz.enigma.translation.mapping.serde; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Path; | ||
| 5 | |||
| 6 | import javax.annotation.Nullable; | ||
| 7 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 8 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 9 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.MappingDelta; | 10 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| @@ -14,10 +19,6 @@ import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Reader; | |||
| 14 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; | 19 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; |
| 15 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 20 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 16 | 21 | ||
| 17 | import javax.annotation.Nullable; | ||
| 18 | import java.io.IOException; | ||
| 19 | import java.nio.file.Path; | ||
| 20 | |||
| 21 | public enum MappingFormat { | 22 | public enum MappingFormat { |
| 22 | ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE), | 23 | ENIGMA_FILE(EnigmaMappingsWriter.FILE, EnigmaMappingsReader.FILE), |
| 23 | ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY), | 24 | ENIGMA_DIRECTORY(EnigmaMappingsWriter.DIRECTORY, EnigmaMappingsReader.DIRECTORY), |
| @@ -28,7 +29,6 @@ public enum MappingFormat { | |||
| 28 | PROGUARD(null, ProguardMappingsReader.INSTANCE), | 29 | PROGUARD(null, ProguardMappingsReader.INSTANCE), |
| 29 | RECAF(null, RecafMappingsReader.INSTANCE); | 30 | RECAF(null, RecafMappingsReader.INSTANCE); |
| 30 | 31 | ||
| 31 | |||
| 32 | private final MappingsWriter writer; | 32 | private final MappingsWriter writer; |
| 33 | private final MappingsReader reader; | 33 | private final MappingsReader reader; |
| 34 | 34 | ||
| @@ -37,14 +37,15 @@ public enum MappingFormat { | |||
| 37 | this.reader = reader; | 37 | this.reader = reader; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | public void write(EntryTree<EntryMapping> mappings, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { | 40 | public void write(EntryTree<EntryMapping> mappings, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { |
| 41 | write(mappings, MappingDelta.added(mappings), path, progressListener, saveParameters); | 41 | write(mappings, MappingDelta.added(mappings), path, progressListener, saveParameters); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { | 44 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progressListener, MappingSaveParameters saveParameters) { |
| 45 | if (writer == null) { | 45 | if (writer == null) { |
| 46 | throw new IllegalStateException(name() + " does not support writing"); | 46 | throw new IllegalStateException(name() + " does not support writing"); |
| 47 | } | 47 | } |
| 48 | |||
| 48 | writer.write(mappings, delta, path, progressListener, saveParameters); | 49 | writer.write(mappings, delta, path, progressListener, saveParameters); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| @@ -52,6 +53,7 @@ public enum MappingFormat { | |||
| 52 | if (reader == null) { | 53 | if (reader == null) { |
| 53 | throw new IllegalStateException(name() + " does not support reading"); | 54 | throw new IllegalStateException(name() + " does not support reading"); |
| 54 | } | 55 | } |
| 56 | |||
| 55 | return reader.read(path, progressListener, saveParameters); | 57 | return reader.read(path, progressListener, saveParameters); |
| 56 | } | 58 | } |
| 57 | 59 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java index 7c8f6cc6..5f466bba 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingHelper.java | |||
| @@ -6,21 +6,27 @@ public final class MappingHelper { | |||
| 6 | 6 | ||
| 7 | public static String escape(String raw) { | 7 | public static String escape(String raw) { |
| 8 | StringBuilder builder = new StringBuilder(raw.length() + 1); | 8 | StringBuilder builder = new StringBuilder(raw.length() + 1); |
| 9 | |||
| 9 | for (int i = 0; i < raw.length(); i++) { | 10 | for (int i = 0; i < raw.length(); i++) { |
| 10 | final char c = raw.charAt(i); | 11 | final char c = raw.charAt(i); |
| 11 | final int r = TO_ESCAPE.indexOf(c); | 12 | final int r = TO_ESCAPE.indexOf(c); |
| 13 | |||
| 12 | if (r < 0) { | 14 | if (r < 0) { |
| 13 | builder.append(c); | 15 | builder.append(c); |
| 14 | } else { | 16 | } else { |
| 15 | builder.append('\\').append(ESCAPED.charAt(r)); | 17 | builder.append('\\').append(ESCAPED.charAt(r)); |
| 16 | } | 18 | } |
| 17 | } | 19 | } |
| 20 | |||
| 18 | return builder.toString(); | 21 | return builder.toString(); |
| 19 | } | 22 | } |
| 20 | 23 | ||
| 21 | public static String unescape(String str) { | 24 | public static String unescape(String str) { |
| 22 | int pos = str.indexOf('\\'); | 25 | int pos = str.indexOf('\\'); |
| 23 | if (pos < 0) return str; | 26 | |
| 27 | if (pos < 0) { | ||
| 28 | return str; | ||
| 29 | } | ||
| 24 | 30 | ||
| 25 | StringBuilder ret = new StringBuilder(str.length() - 1); | 31 | StringBuilder ret = new StringBuilder(str.length() - 1); |
| 26 | int start = 0; | 32 | int start = 0; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java index 9d04b976..6f5d7d6e 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingParseException.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.mapping.serde; | 12 | package cuchaz.enigma.translation.mapping.serde; |
| 13 | 13 | ||
| @@ -15,7 +15,6 @@ import java.io.File; | |||
| 15 | import java.util.function.Supplier; | 15 | import java.util.function.Supplier; |
| 16 | 16 | ||
| 17 | public class MappingParseException extends Exception { | 17 | public class MappingParseException extends Exception { |
| 18 | |||
| 19 | private int line; | 18 | private int line; |
| 20 | private String message; | 19 | private String message; |
| 21 | private String filePath; | 20 | private String filePath; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java index 2f01375a..4fdfdcba 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsReader.java | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | 1 | package cuchaz.enigma.translation.mapping.serde; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Path; | ||
| 5 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 6 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 7 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 6 | 9 | ||
| 7 | import java.io.IOException; | ||
| 8 | import java.nio.file.Path; | ||
| 9 | |||
| 10 | public interface MappingsReader { | 10 | public interface MappingsReader { |
| 11 | EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException; | 11 | EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException; |
| 12 | } | 12 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java index 68a8dbb2..5c273ad3 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/MappingsWriter.java | |||
| @@ -1,12 +1,12 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde; | 1 | package cuchaz.enigma.translation.mapping.serde; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | ||
| 4 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 5 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 6 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.MappingDelta; | 7 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 6 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 7 | 9 | ||
| 8 | import java.nio.file.Path; | ||
| 9 | |||
| 10 | public interface MappingsWriter { | 10 | public interface MappingsWriter { |
| 11 | void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters); | 11 | void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters); |
| 12 | 12 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java index 61dbe93a..1f8b7558 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsReader.java | |||
| @@ -5,7 +5,11 @@ import java.nio.file.FileSystem; | |||
| 5 | import java.nio.file.FileSystems; | 5 | import java.nio.file.FileSystems; |
| 6 | import java.nio.file.Files; | 6 | import java.nio.file.Files; |
| 7 | import java.nio.file.Path; | 7 | import java.nio.file.Path; |
| 8 | import java.util.*; | 8 | import java.util.ArrayDeque; |
| 9 | import java.util.Arrays; | ||
| 10 | import java.util.Deque; | ||
| 11 | import java.util.List; | ||
| 12 | import java.util.Locale; | ||
| 9 | 13 | ||
| 10 | import javax.annotation.Nullable; | 14 | import javax.annotation.Nullable; |
| 11 | 15 | ||
| @@ -15,12 +19,20 @@ import cuchaz.enigma.ProgressListener; | |||
| 15 | import cuchaz.enigma.translation.mapping.AccessModifier; | 19 | import cuchaz.enigma.translation.mapping.AccessModifier; |
| 16 | import cuchaz.enigma.translation.mapping.EntryMapping; | 20 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 17 | import cuchaz.enigma.translation.mapping.MappingPair; | 21 | import cuchaz.enigma.translation.mapping.MappingPair; |
| 18 | import cuchaz.enigma.translation.mapping.serde.*; | 22 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; |
| 23 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 24 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 25 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | ||
| 26 | import cuchaz.enigma.translation.mapping.serde.RawEntryMapping; | ||
| 19 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 27 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 20 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; | 28 | import cuchaz.enigma.translation.mapping.tree.HashEntryTree; |
| 21 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 29 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 22 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 30 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 23 | import cuchaz.enigma.translation.representation.entry.*; | 31 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 32 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 33 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 34 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 35 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 24 | import cuchaz.enigma.utils.I18n; | 36 | import cuchaz.enigma.utils.I18n; |
| 25 | 37 | ||
| 26 | public enum EnigmaMappingsReader implements MappingsReader { | 38 | public enum EnigmaMappingsReader implements MappingsReader { |
| @@ -42,19 +54,18 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 42 | public EntryTree<EntryMapping> read(Path root, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException { | 54 | public EntryTree<EntryMapping> read(Path root, ProgressListener progress, MappingSaveParameters saveParameters) throws IOException, MappingParseException { |
| 43 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); | 55 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); |
| 44 | 56 | ||
| 45 | List<Path> files = Files.walk(root) | 57 | List<Path> files = Files.walk(root).filter(f -> !Files.isDirectory(f)).filter(f -> f.toString().endsWith(".mapping")).toList(); |
| 46 | .filter(f -> !Files.isDirectory(f)) | ||
| 47 | .filter(f -> f.toString().endsWith(".mapping")) | ||
| 48 | .toList(); | ||
| 49 | 58 | ||
| 50 | progress.init(files.size(), I18n.translate("progress.mappings.enigma_directory.loading")); | 59 | progress.init(files.size(), I18n.translate("progress.mappings.enigma_directory.loading")); |
| 51 | int step = 0; | 60 | int step = 0; |
| 52 | 61 | ||
| 53 | for (Path file : files) { | 62 | for (Path file : files) { |
| 54 | progress.step(step++, root.relativize(file).toString()); | 63 | progress.step(step++, root.relativize(file).toString()); |
| 64 | |||
| 55 | if (Files.isHidden(file)) { | 65 | if (Files.isHidden(file)) { |
| 56 | continue; | 66 | continue; |
| 57 | } | 67 | } |
| 68 | |||
| 58 | readFile(file, mappings); | 69 | readFile(file, mappings); |
| 59 | } | 70 | } |
| 60 | 71 | ||
| @@ -74,10 +85,10 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 74 | * Reads multiple Enigma mapping files. | 85 | * Reads multiple Enigma mapping files. |
| 75 | * | 86 | * |
| 76 | * @param progress the progress listener | 87 | * @param progress the progress listener |
| 77 | * @param paths the Enigma files to read; cannot be empty | 88 | * @param paths the Enigma files to read; cannot be empty |
| 78 | * @return the parsed mappings | 89 | * @return the parsed mappings |
| 79 | * @throws MappingParseException if a mapping file cannot be parsed | 90 | * @throws MappingParseException if a mapping file cannot be parsed |
| 80 | * @throws IOException if an IO error occurs | 91 | * @throws IOException if an IO error occurs |
| 81 | * @throws IllegalArgumentException if there are no paths to read | 92 | * @throws IllegalArgumentException if there are no paths to read |
| 82 | */ | 93 | */ |
| 83 | public static EntryTree<EntryMapping> readFiles(ProgressListener progress, Path... paths) throws MappingParseException, IOException { | 94 | public static EntryTree<EntryMapping> readFiles(ProgressListener progress, Path... paths) throws MappingParseException, IOException { |
| @@ -107,6 +118,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 107 | int indentation = countIndentation(line, path, lineNumber); | 118 | int indentation = countIndentation(line, path, lineNumber); |
| 108 | 119 | ||
| 109 | line = formatLine(line); | 120 | line = formatLine(line); |
| 121 | |||
| 110 | if (line == null) { | 122 | if (line == null) { |
| 111 | continue; | 123 | continue; |
| 112 | } | 124 | } |
| @@ -115,6 +127,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 115 | 127 | ||
| 116 | try { | 128 | try { |
| 117 | MappingPair<?, RawEntryMapping> pair = parseLine(mappingStack.peek(), line); | 129 | MappingPair<?, RawEntryMapping> pair = parseLine(mappingStack.peek(), line); |
| 130 | |||
| 118 | if (pair != null) { | 131 | if (pair != null) { |
| 119 | mappingStack.push(pair); | 132 | mappingStack.push(pair); |
| 120 | } | 133 | } |
| @@ -131,6 +144,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 131 | private static void cleanMappingStack(int indentation, Deque<MappingPair<?, RawEntryMapping>> mappingStack, EntryTree<EntryMapping> mappings) { | 144 | private static void cleanMappingStack(int indentation, Deque<MappingPair<?, RawEntryMapping>> mappingStack, EntryTree<EntryMapping> mappings) { |
| 132 | while (indentation < mappingStack.size()) { | 145 | while (indentation < mappingStack.size()) { |
| 133 | MappingPair<?, RawEntryMapping> pair = mappingStack.pop(); | 146 | MappingPair<?, RawEntryMapping> pair = mappingStack.pop(); |
| 147 | |||
| 134 | if (pair.getMapping() != null) { | 148 | if (pair.getMapping() != null) { |
| 135 | mappings.insert(pair.getEntry(), pair.getMapping().bake()); | 149 | mappings.insert(pair.getEntry(), pair.getMapping().bake()); |
| 136 | } | 150 | } |
| @@ -156,14 +170,17 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 156 | } | 170 | } |
| 157 | 171 | ||
| 158 | int commentPos = line.indexOf('#'); | 172 | int commentPos = line.indexOf('#'); |
| 173 | |||
| 159 | if (commentPos >= 0) { | 174 | if (commentPos >= 0) { |
| 160 | return line.substring(0, commentPos); | 175 | return line.substring(0, commentPos); |
| 161 | } | 176 | } |
| 177 | |||
| 162 | return line; | 178 | return line; |
| 163 | } | 179 | } |
| 164 | 180 | ||
| 165 | private static int countIndentation(String line, Path path, int lineNumber) throws MappingParseException { | 181 | private static int countIndentation(String line, Path path, int lineNumber) throws MappingParseException { |
| 166 | int indent = 0; | 182 | int indent = 0; |
| 183 | |||
| 167 | for (int i = 0; i < line.length(); i++) { | 184 | for (int i = 0; i < line.length(); i++) { |
| 168 | if (line.charAt(i) == ' ') { | 185 | if (line.charAt(i) == ' ') { |
| 169 | throw new MappingParseException(path::toString, lineNumber + 1, "Spaces must not be used to indent lines!"); | 186 | throw new MappingParseException(path::toString, lineNumber + 1, "Spaces must not be used to indent lines!"); |
| @@ -172,8 +189,10 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 172 | if (line.charAt(i) != '\t') { | 189 | if (line.charAt(i) != '\t') { |
| 173 | break; | 190 | break; |
| 174 | } | 191 | } |
| 192 | |||
| 175 | indent++; | 193 | indent++; |
| 176 | } | 194 | } |
| 195 | |||
| 177 | return indent; | 196 | return indent; |
| 178 | } | 197 | } |
| 179 | 198 | ||
| @@ -183,36 +202,41 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 183 | Entry<?> parentEntry = parent == null ? null : parent.getEntry(); | 202 | Entry<?> parentEntry = parent == null ? null : parent.getEntry(); |
| 184 | 203 | ||
| 185 | switch (keyToken) { | 204 | switch (keyToken) { |
| 186 | case EnigmaFormat.CLASS: | 205 | case EnigmaFormat.CLASS: |
| 187 | return parseClass(parentEntry, tokens); | 206 | return parseClass(parentEntry, tokens); |
| 188 | case EnigmaFormat.FIELD: | 207 | case EnigmaFormat.FIELD: |
| 189 | return parseField(parentEntry, tokens); | 208 | return parseField(parentEntry, tokens); |
| 190 | case EnigmaFormat.METHOD: | 209 | case EnigmaFormat.METHOD: |
| 191 | return parseMethod(parentEntry, tokens); | 210 | return parseMethod(parentEntry, tokens); |
| 192 | case EnigmaFormat.PARAMETER: | 211 | case EnigmaFormat.PARAMETER: |
| 193 | return parseArgument(parentEntry, tokens); | 212 | return parseArgument(parentEntry, tokens); |
| 194 | case EnigmaFormat.COMMENT: | 213 | case EnigmaFormat.COMMENT: |
| 195 | readJavadoc(parent, tokens); | 214 | readJavadoc(parent, tokens); |
| 196 | return null; | 215 | return null; |
| 197 | default: | 216 | default: |
| 198 | throw new RuntimeException("Unknown token '" + keyToken + "'"); | 217 | throw new RuntimeException("Unknown token '" + keyToken + "'"); |
| 199 | } | 218 | } |
| 200 | } | 219 | } |
| 201 | 220 | ||
| 202 | private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) { | 221 | private static void readJavadoc(MappingPair<?, RawEntryMapping> parent, String[] tokens) { |
| 203 | if (parent == null) | 222 | if (parent == null) { |
| 204 | throw new IllegalStateException("Javadoc has no parent!"); | 223 | throw new IllegalStateException("Javadoc has no parent!"); |
| 224 | } | ||
| 225 | |||
| 205 | // Empty string to concat | 226 | // Empty string to concat |
| 206 | String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)) : ""; | 227 | String jdLine = tokens.length > 1 ? String.join(" ", Arrays.copyOfRange(tokens, 1, tokens.length)) : ""; |
| 228 | |||
| 207 | if (parent.getMapping() == null) { | 229 | if (parent.getMapping() == null) { |
| 208 | parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED)); | 230 | parent.setMapping(new RawEntryMapping(parent.getEntry().getName(), AccessModifier.UNCHANGED)); |
| 209 | } | 231 | } |
| 232 | |||
| 210 | parent.getMapping().addJavadocLine(MappingHelper.unescape(jdLine)); | 233 | parent.getMapping().addJavadocLine(MappingHelper.unescape(jdLine)); |
| 211 | } | 234 | } |
| 212 | 235 | ||
| 213 | private static MappingPair<ClassEntry, RawEntryMapping> parseClass(@Nullable Entry<?> parent, String[] tokens) { | 236 | private static MappingPair<ClassEntry, RawEntryMapping> parseClass(@Nullable Entry<?> parent, String[] tokens) { |
| 214 | String obfuscatedName = ClassEntry.getInnerName(tokens[1]); | 237 | String obfuscatedName = ClassEntry.getInnerName(tokens[1]); |
| 215 | ClassEntry obfuscatedEntry; | 238 | ClassEntry obfuscatedEntry; |
| 239 | |||
| 216 | if (parent instanceof ClassEntry) { | 240 | if (parent instanceof ClassEntry) { |
| 217 | obfuscatedEntry = new ClassEntry((ClassEntry) parent, obfuscatedName); | 241 | obfuscatedEntry = new ClassEntry((ClassEntry) parent, obfuscatedName); |
| 218 | } else { | 242 | } else { |
| @@ -224,6 +248,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 224 | 248 | ||
| 225 | if (tokens.length == 3) { | 249 | if (tokens.length == 3) { |
| 226 | AccessModifier parsedModifier = parseModifier(tokens[2]); | 250 | AccessModifier parsedModifier = parseModifier(tokens[2]); |
| 251 | |||
| 227 | if (parsedModifier != null) { | 252 | if (parsedModifier != null) { |
| 228 | modifier = parsedModifier; | 253 | modifier = parsedModifier; |
| 229 | mapping = obfuscatedName; | 254 | mapping = obfuscatedName; |
| @@ -254,6 +279,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 254 | descriptor = new TypeDescriptor(tokens[2]); | 279 | descriptor = new TypeDescriptor(tokens[2]); |
| 255 | } else if (tokens.length == 4) { | 280 | } else if (tokens.length == 4) { |
| 256 | AccessModifier parsedModifier = parseModifier(tokens[3]); | 281 | AccessModifier parsedModifier = parseModifier(tokens[3]); |
| 282 | |||
| 257 | if (parsedModifier != null) { | 283 | if (parsedModifier != null) { |
| 258 | descriptor = new TypeDescriptor(tokens[2]); | 284 | descriptor = new TypeDescriptor(tokens[2]); |
| 259 | modifier = parsedModifier; | 285 | modifier = parsedModifier; |
| @@ -289,6 +315,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 289 | descriptor = new MethodDescriptor(tokens[2]); | 315 | descriptor = new MethodDescriptor(tokens[2]); |
| 290 | } else if (tokens.length == 4) { | 316 | } else if (tokens.length == 4) { |
| 291 | AccessModifier parsedModifier = parseModifier(tokens[3]); | 317 | AccessModifier parsedModifier = parseModifier(tokens[3]); |
| 318 | |||
| 292 | if (parsedModifier != null) { | 319 | if (parsedModifier != null) { |
| 293 | modifier = parsedModifier; | 320 | modifier = parsedModifier; |
| 294 | mapping = obfuscatedName; | 321 | mapping = obfuscatedName; |
| @@ -326,6 +353,7 @@ public enum EnigmaMappingsReader implements MappingsReader { | |||
| 326 | if (token.startsWith("ACC:")) { | 353 | if (token.startsWith("ACC:")) { |
| 327 | return AccessModifier.valueOf(token.substring(4)); | 354 | return AccessModifier.valueOf(token.substring(4)); |
| 328 | } | 355 | } |
| 356 | |||
| 329 | return null; | 357 | return null; |
| 330 | } | 358 | } |
| 331 | } | 359 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java index 5d7a7893..cd00ef77 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/enigma/EnigmaMappingsWriter.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.mapping.serde.enigma; | 12 | package cuchaz.enigma.translation.mapping.serde.enigma; |
| 13 | 13 | ||
| @@ -15,7 +15,12 @@ import java.io.IOException; | |||
| 15 | import java.io.PrintWriter; | 15 | import java.io.PrintWriter; |
| 16 | import java.net.URI; | 16 | import java.net.URI; |
| 17 | import java.net.URISyntaxException; | 17 | import java.net.URISyntaxException; |
| 18 | import java.nio.file.*; | 18 | import java.nio.file.DirectoryStream; |
| 19 | import java.nio.file.FileSystem; | ||
| 20 | import java.nio.file.FileSystems; | ||
| 21 | import java.nio.file.Files; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.nio.file.Paths; | ||
| 19 | import java.util.ArrayList; | 24 | import java.util.ArrayList; |
| 20 | import java.util.Collection; | 25 | import java.util.Collection; |
| 21 | import java.util.Collections; | 26 | import java.util.Collections; |
| @@ -32,24 +37,30 @@ import cuchaz.enigma.translation.mapping.AccessModifier; | |||
| 32 | import cuchaz.enigma.translation.mapping.EntryMapping; | 37 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 33 | import cuchaz.enigma.translation.mapping.MappingDelta; | 38 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 34 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | 39 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; |
| 35 | import cuchaz.enigma.translation.mapping.serde.*; | 40 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; |
| 41 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | ||
| 42 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; | ||
| 43 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 44 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | ||
| 36 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 45 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 37 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 46 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| 38 | import cuchaz.enigma.translation.representation.entry.*; | 47 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 48 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 49 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | ||
| 50 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | ||
| 51 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 39 | import cuchaz.enigma.utils.I18n; | 52 | import cuchaz.enigma.utils.I18n; |
| 40 | 53 | ||
| 41 | public enum EnigmaMappingsWriter implements MappingsWriter { | 54 | public enum EnigmaMappingsWriter implements MappingsWriter { |
| 42 | FILE { | 55 | FILE { |
| 43 | @Override | 56 | @Override |
| 44 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { | 57 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { |
| 45 | Collection<ClassEntry> classes = mappings.getRootNodes() | 58 | Collection<ClassEntry> classes = mappings.getRootNodes().filter(entry -> entry.getEntry() instanceof ClassEntry).map(entry -> (ClassEntry) entry.getEntry()).toList(); |
| 46 | .filter(entry -> entry.getEntry() instanceof ClassEntry) | ||
| 47 | .map(entry -> (ClassEntry) entry.getEntry()) | ||
| 48 | .toList(); | ||
| 49 | 59 | ||
| 50 | progress.init(classes.size(), I18n.translate("progress.mappings.enigma_file.writing")); | 60 | progress.init(classes.size(), I18n.translate("progress.mappings.enigma_file.writing")); |
| 51 | 61 | ||
| 52 | int steps = 0; | 62 | int steps = 0; |
| 63 | |||
| 53 | try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { | 64 | try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { |
| 54 | for (ClassEntry classEntry : classes) { | 65 | for (ClassEntry classEntry : classes) { |
| 55 | progress.step(steps++, classEntry.getFullName()); | 66 | progress.step(steps++, classEntry.getFullName()); |
| @@ -63,10 +74,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 63 | DIRECTORY { | 74 | DIRECTORY { |
| 64 | @Override | 75 | @Override |
| 65 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { | 76 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { |
| 66 | Collection<ClassEntry> changedClasses = delta.getChangedRoots() | 77 | Collection<ClassEntry> changedClasses = delta.getChangedRoots().filter(entry -> entry instanceof ClassEntry).map(entry -> (ClassEntry) entry).toList(); |
| 67 | .filter(entry -> entry instanceof ClassEntry) | ||
| 68 | .map(entry -> (ClassEntry) entry) | ||
| 69 | .toList(); | ||
| 70 | 78 | ||
| 71 | applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat()); | 79 | applyDeletions(path, changedClasses, mappings, delta.getBaseMappings(), saveParameters.getFileNameFormat()); |
| 72 | 80 | ||
| @@ -80,6 +88,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 80 | 88 | ||
| 81 | try { | 89 | try { |
| 82 | ClassEntry fileEntry = classEntry; | 90 | ClassEntry fileEntry = classEntry; |
| 91 | |||
| 83 | if (saveParameters.getFileNameFormat() == MappingFileNameFormat.BY_DEOBF) { | 92 | if (saveParameters.getFileNameFormat() == MappingFileNameFormat.BY_DEOBF) { |
| 84 | fileEntry = translator.translate(fileEntry); | 93 | fileEntry = translator.translate(fileEntry); |
| 85 | } | 94 | } |
| @@ -101,8 +110,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 101 | private void applyDeletions(Path root, Collection<ClassEntry> changedClasses, EntryTree<EntryMapping> mappings, EntryTree<EntryMapping> oldMappings, MappingFileNameFormat fileNameFormat) { | 110 | private void applyDeletions(Path root, Collection<ClassEntry> changedClasses, EntryTree<EntryMapping> mappings, EntryTree<EntryMapping> oldMappings, MappingFileNameFormat fileNameFormat) { |
| 102 | Translator oldMappingTranslator = new MappingTranslator(oldMappings, VoidEntryResolver.INSTANCE); | 111 | Translator oldMappingTranslator = new MappingTranslator(oldMappings, VoidEntryResolver.INSTANCE); |
| 103 | 112 | ||
| 104 | Stream<ClassEntry> deletedClassStream = changedClasses.stream() | 113 | Stream<ClassEntry> deletedClassStream = changedClasses.stream().filter(e -> !Objects.equals(oldMappings.get(e), mappings.get(e))); |
| 105 | .filter(e -> !Objects.equals(oldMappings.get(e), mappings.get(e))); | ||
| 106 | 114 | ||
| 107 | if (fileNameFormat == MappingFileNameFormat.BY_DEOBF) { | 115 | if (fileNameFormat == MappingFileNameFormat.BY_DEOBF) { |
| 108 | deletedClassStream = deletedClassStream.map(oldMappingTranslator::translate); | 116 | deletedClassStream = deletedClassStream.map(oldMappingTranslator::translate); |
| @@ -121,8 +129,10 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 121 | 129 | ||
| 122 | for (ClassEntry classEntry : deletedClasses) { | 130 | for (ClassEntry classEntry : deletedClasses) { |
| 123 | String packageName = classEntry.getPackageName(); | 131 | String packageName = classEntry.getPackageName(); |
| 132 | |||
| 124 | if (packageName != null) { | 133 | if (packageName != null) { |
| 125 | Path packagePath = Paths.get(packageName); | 134 | Path packagePath = Paths.get(packageName); |
| 135 | |||
| 126 | try { | 136 | try { |
| 127 | deleteDeadPackages(root, packagePath); | 137 | deleteDeadPackages(root, packagePath); |
| 128 | } catch (IOException e) { | 138 | } catch (IOException e) { |
| @@ -137,6 +147,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 137 | for (int i = packagePath.getNameCount() - 1; i >= 0; i--) { | 147 | for (int i = packagePath.getNameCount() - 1; i >= 0; i--) { |
| 138 | Path subPath = packagePath.subpath(0, i + 1); | 148 | Path subPath = packagePath.subpath(0, i + 1); |
| 139 | Path packagePart = root.resolve(subPath.toString()); | 149 | Path packagePart = root.resolve(subPath.toString()); |
| 150 | |||
| 140 | if (isEmpty(packagePart)) { | 151 | if (isEmpty(packagePart)) { |
| 141 | Files.deleteIfExists(packagePart); | 152 | Files.deleteIfExists(packagePart); |
| 142 | } | 153 | } |
| @@ -178,6 +189,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 178 | } | 189 | } |
| 179 | 190 | ||
| 180 | writer.println(writeClass(classEntry, classEntryMapping).trim()); | 191 | writer.println(writeClass(classEntry, classEntryMapping).trim()); |
| 192 | |||
| 181 | if (classEntryMapping.javadoc() != null) { | 193 | if (classEntryMapping.javadoc() != null) { |
| 182 | writeDocs(writer, classEntryMapping, 0); | 194 | writeDocs(writer, classEntryMapping, 0); |
| 183 | } | 195 | } |
| @@ -189,6 +201,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 189 | 201 | ||
| 190 | private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { | 202 | private void writeDocs(PrintWriter writer, EntryMapping mapping, int depth) { |
| 191 | String jd = mapping.javadoc(); | 203 | String jd = mapping.javadoc(); |
| 204 | |||
| 192 | if (jd != null) { | 205 | if (jd != null) { |
| 193 | for (String line : jd.split("\\R")) { | 206 | for (String line : jd.split("\\R")) { |
| 194 | writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); | 207 | writer.println(indent(EnigmaFormat.COMMENT + " " + MappingHelper.escape(line), depth + 1)); |
| @@ -198,6 +211,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 198 | 211 | ||
| 199 | protected void writeEntry(PrintWriter writer, EntryTree<EntryMapping> mappings, Entry<?> entry, int depth) { | 212 | protected void writeEntry(PrintWriter writer, EntryTree<EntryMapping> mappings, Entry<?> entry, int depth) { |
| 200 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | 213 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); |
| 214 | |||
| 201 | if (node == null) { | 215 | if (node == null) { |
| 202 | return; | 216 | return; |
| 203 | } | 217 | } |
| @@ -209,6 +223,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 209 | } | 223 | } |
| 210 | 224 | ||
| 211 | String line = null; | 225 | String line = null; |
| 226 | |||
| 212 | if (entry instanceof ClassEntry classEntry) { | 227 | if (entry instanceof ClassEntry classEntry) { |
| 213 | line = writeClass(classEntry, mapping); | 228 | line = writeClass(classEntry, mapping); |
| 214 | } else if (entry instanceof MethodEntry methodEntry) { | 229 | } else if (entry instanceof MethodEntry methodEntry) { |
| @@ -228,6 +243,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 228 | } | 243 | } |
| 229 | 244 | ||
| 230 | Collection<Entry<?>> children = groupChildren(node.getChildren()); | 245 | Collection<Entry<?>> children = groupChildren(node.getChildren()); |
| 246 | |||
| 231 | for (Entry<?> child : children) { | 247 | for (Entry<?> child : children) { |
| 232 | writeEntry(writer, mappings, child, depth + 1); | 248 | writeEntry(writer, mappings, child, depth + 1); |
| 233 | } | 249 | } |
| @@ -236,25 +252,13 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 236 | private Collection<Entry<?>> groupChildren(Collection<Entry<?>> children) { | 252 | private Collection<Entry<?>> groupChildren(Collection<Entry<?>> children) { |
| 237 | Collection<Entry<?>> result = new ArrayList<>(children.size()); | 253 | Collection<Entry<?>> result = new ArrayList<>(children.size()); |
| 238 | 254 | ||
| 239 | children.stream().filter(e -> e instanceof FieldEntry) | 255 | children.stream().filter(e -> e instanceof FieldEntry).map(e -> (FieldEntry) e).sorted().forEach(result::add); |
| 240 | .map(e -> (FieldEntry) e) | ||
| 241 | .sorted() | ||
| 242 | .forEach(result::add); | ||
| 243 | 256 | ||
| 244 | children.stream().filter(e -> e instanceof MethodEntry) | 257 | children.stream().filter(e -> e instanceof MethodEntry).map(e -> (MethodEntry) e).sorted().forEach(result::add); |
| 245 | .map(e -> (MethodEntry) e) | ||
| 246 | .sorted() | ||
| 247 | .forEach(result::add); | ||
| 248 | 258 | ||
| 249 | children.stream().filter(e -> e instanceof LocalVariableEntry) | 259 | children.stream().filter(e -> e instanceof LocalVariableEntry).map(e -> (LocalVariableEntry) e).sorted().forEach(result::add); |
| 250 | .map(e -> (LocalVariableEntry) e) | ||
| 251 | .sorted() | ||
| 252 | .forEach(result::add); | ||
| 253 | 260 | ||
| 254 | children.stream().filter(e -> e instanceof ClassEntry) | 261 | children.stream().filter(e -> e instanceof ClassEntry).map(e -> (ClassEntry) e).sorted().forEach(result::add); |
| 255 | .map(e -> (ClassEntry) e) | ||
| 256 | .sorted() | ||
| 257 | .forEach(result::add); | ||
| 258 | 262 | ||
| 259 | return result; | 263 | return result; |
| 260 | } | 264 | } |
| @@ -294,6 +298,7 @@ public enum EnigmaMappingsWriter implements MappingsWriter { | |||
| 294 | private void writeMapping(StringBuilder builder, EntryMapping mapping) { | 298 | private void writeMapping(StringBuilder builder, EntryMapping mapping) { |
| 295 | if (mapping.targetName() != null) { | 299 | if (mapping.targetName() != null) { |
| 296 | builder.append(mapping.targetName()).append(' '); | 300 | builder.append(mapping.targetName()).append(' '); |
| 301 | |||
| 297 | if (mapping.accessModifier() != AccessModifier.UNCHANGED) { | 302 | if (mapping.accessModifier() != AccessModifier.UNCHANGED) { |
| 298 | builder.append(mapping.accessModifier().getFormattedName()).append(' '); | 303 | builder.append(mapping.accessModifier().getFormattedName()).append(' '); |
| 299 | } | 304 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java index 034fb416..fc550d4d 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/proguard/ProguardMappingsReader.java | |||
| @@ -1,9 +1,16 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.proguard; | 1 | package cuchaz.enigma.translation.mapping.serde.proguard; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.charset.StandardCharsets; | ||
| 5 | import java.nio.file.Files; | ||
| 6 | import java.nio.file.Path; | ||
| 7 | import java.util.regex.Matcher; | ||
| 8 | import java.util.regex.Pattern; | ||
| 9 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 10 | import cuchaz.enigma.ProgressListener; |
| 11 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 4 | import cuchaz.enigma.translation.mapping.MappingOperations; | 12 | import cuchaz.enigma.translation.mapping.MappingOperations; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 13 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; |
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 14 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | 15 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; |
| 9 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| @@ -14,122 +21,117 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 14 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 21 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 15 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 22 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 16 | 23 | ||
| 17 | import java.io.IOException; | ||
| 18 | import java.nio.charset.StandardCharsets; | ||
| 19 | import java.nio.file.Files; | ||
| 20 | import java.nio.file.Path; | ||
| 21 | import java.util.regex.Matcher; | ||
| 22 | import java.util.regex.Pattern; | ||
| 23 | |||
| 24 | public class ProguardMappingsReader implements MappingsReader { | 24 | public class ProguardMappingsReader implements MappingsReader { |
| 25 | public static final ProguardMappingsReader INSTANCE = new ProguardMappingsReader(); | 25 | public static final ProguardMappingsReader INSTANCE = new ProguardMappingsReader(); |
| 26 | private static final String NAME = "[a-zA-Z0-9_\\-.$<>]+"; | 26 | private static final String NAME = "[a-zA-Z0-9_\\-.$<>]+"; |
| 27 | private static final String TYPE = NAME + "(?:\\[])*"; | 27 | private static final String TYPE = NAME + "(?:\\[])*"; |
| 28 | private static final String TYPE_LIST = "|(?:(?:" + TYPE + ",)*" + TYPE + ")"; | 28 | private static final String TYPE_LIST = "|(?:(?:" + TYPE + ",)*" + TYPE + ")"; |
| 29 | private static final Pattern CLASS = Pattern.compile("(" + NAME + ") -> (" + NAME + "):"); | 29 | private static final Pattern CLASS = Pattern.compile("(" + NAME + ") -> (" + NAME + "):"); |
| 30 | private static final Pattern FIELD = Pattern.compile(" {4}(" + TYPE + ") (" + NAME + ") -> (" + NAME + ")"); | 30 | private static final Pattern FIELD = Pattern.compile(" {4}(" + TYPE + ") (" + NAME + ") -> (" + NAME + ")"); |
| 31 | private static final Pattern METHOD = Pattern.compile(" {4}(?:[0-9]+:[0-9]+:)?(" + TYPE + ") (" + NAME + ")\\((" + TYPE_LIST + ")\\) -> (" + NAME + ")"); | 31 | private static final Pattern METHOD = Pattern.compile(" {4}(?:[0-9]+:[0-9]+:)?(" + TYPE + ") (" + NAME + ")\\((" + TYPE_LIST + ")\\) -> (" + NAME + ")"); |
| 32 | 32 | ||
| 33 | public ProguardMappingsReader() {} | 33 | public ProguardMappingsReader() { |
| 34 | 34 | } | |
| 35 | @Override | 35 | |
| 36 | public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException { | 36 | @Override |
| 37 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); | 37 | public EntryTree<EntryMapping> read(Path path, ProgressListener progress, MappingSaveParameters saveParameters) throws MappingParseException, IOException { |
| 38 | 38 | EntryTree<EntryMapping> mappings = new HashEntryTree<>(); | |
| 39 | int lineNumber = 0; | 39 | |
| 40 | ClassEntry currentClass = null; | 40 | int lineNumber = 0; |
| 41 | for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) { | 41 | ClassEntry currentClass = null; |
| 42 | lineNumber++; | 42 | |
| 43 | 43 | for (String line : Files.readAllLines(path, StandardCharsets.UTF_8)) { | |
| 44 | if (line.startsWith("#") || line.isEmpty()) { | 44 | lineNumber++; |
| 45 | continue; | 45 | |
| 46 | } | 46 | if (line.startsWith("#") || line.isEmpty()) { |
| 47 | 47 | continue; | |
| 48 | Matcher classMatcher = CLASS.matcher(line); | 48 | } |
| 49 | Matcher fieldMatcher = FIELD.matcher(line); | 49 | |
| 50 | Matcher methodMatcher = METHOD.matcher(line); | 50 | Matcher classMatcher = CLASS.matcher(line); |
| 51 | 51 | Matcher fieldMatcher = FIELD.matcher(line); | |
| 52 | if (classMatcher.matches()) { | 52 | Matcher methodMatcher = METHOD.matcher(line); |
| 53 | String name = classMatcher.group(1); | 53 | |
| 54 | String targetName = classMatcher.group(2); | 54 | if (classMatcher.matches()) { |
| 55 | 55 | String name = classMatcher.group(1); | |
| 56 | mappings.insert(currentClass = new ClassEntry(name.replace('.', '/')), new EntryMapping(ClassEntry.getInnerName(targetName.replace('.', '/')))); | 56 | String targetName = classMatcher.group(2); |
| 57 | } else if (fieldMatcher.matches()) { | 57 | |
| 58 | String type = fieldMatcher.group(1); | 58 | mappings.insert(currentClass = new ClassEntry(name.replace('.', '/')), new EntryMapping(ClassEntry.getInnerName(targetName.replace('.', '/')))); |
| 59 | String name = fieldMatcher.group(2); | 59 | } else if (fieldMatcher.matches()) { |
| 60 | String targetName = fieldMatcher.group(3); | 60 | String type = fieldMatcher.group(1); |
| 61 | 61 | String name = fieldMatcher.group(2); | |
| 62 | if (currentClass == null) { | 62 | String targetName = fieldMatcher.group(3); |
| 63 | throw new MappingParseException(path::toString, lineNumber, "field mapping not inside class: " + line); | 63 | |
| 64 | } | 64 | if (currentClass == null) { |
| 65 | 65 | throw new MappingParseException(path::toString, lineNumber, "field mapping not inside class: " + line); | |
| 66 | mappings.insert(new FieldEntry(currentClass, name, new TypeDescriptor(getDescriptor(type))), new EntryMapping(targetName)); | 66 | } |
| 67 | } else if (methodMatcher.matches()) { | 67 | |
| 68 | String returnType = methodMatcher.group(1); | 68 | mappings.insert(new FieldEntry(currentClass, name, new TypeDescriptor(getDescriptor(type))), new EntryMapping(targetName)); |
| 69 | String name = methodMatcher.group(2); | 69 | } else if (methodMatcher.matches()) { |
| 70 | String[] parameterTypes = methodMatcher.group(3).isEmpty() ? new String[0] : methodMatcher.group(3).split(","); | 70 | String returnType = methodMatcher.group(1); |
| 71 | String targetName = methodMatcher.group(4); | 71 | String name = methodMatcher.group(2); |
| 72 | 72 | String[] parameterTypes = methodMatcher.group(3).isEmpty() ? new String[0] : methodMatcher.group(3).split(","); | |
| 73 | if (currentClass == null) { | 73 | String targetName = methodMatcher.group(4); |
| 74 | throw new MappingParseException(path::toString, lineNumber, "method mapping not inside class: " + line); | 74 | |
| 75 | } | 75 | if (currentClass == null) { |
| 76 | 76 | throw new MappingParseException(path::toString, lineNumber, "method mapping not inside class: " + line); | |
| 77 | mappings.insert(new MethodEntry(currentClass, name, new MethodDescriptor(getDescriptor(returnType, parameterTypes))), new EntryMapping(targetName)); | 77 | } |
| 78 | } else { | 78 | |
| 79 | throw new MappingParseException(path::toString, lineNumber, "invalid mapping line: " + line); | 79 | mappings.insert(new MethodEntry(currentClass, name, new MethodDescriptor(getDescriptor(returnType, parameterTypes))), new EntryMapping(targetName)); |
| 80 | } | 80 | } else { |
| 81 | } | 81 | throw new MappingParseException(path::toString, lineNumber, "invalid mapping line: " + line); |
| 82 | 82 | } | |
| 83 | return MappingOperations.invert(mappings); | 83 | } |
| 84 | } | 84 | |
| 85 | 85 | return MappingOperations.invert(mappings); | |
| 86 | private String getDescriptor(String type) { | 86 | } |
| 87 | StringBuilder descriptor = new StringBuilder(); | 87 | |
| 88 | 88 | private String getDescriptor(String type) { | |
| 89 | while (type.endsWith("[]")) { | 89 | StringBuilder descriptor = new StringBuilder(); |
| 90 | descriptor.append("["); | 90 | |
| 91 | type = type.substring(0, type.length() - 2); | 91 | while (type.endsWith("[]")) { |
| 92 | } | 92 | descriptor.append("["); |
| 93 | 93 | type = type.substring(0, type.length() - 2); | |
| 94 | switch (type) { | 94 | } |
| 95 | case "byte": | 95 | |
| 96 | return descriptor + "B"; | 96 | switch (type) { |
| 97 | case "char": | 97 | case "byte": |
| 98 | return descriptor + "C"; | 98 | return descriptor + "B"; |
| 99 | case "short": | 99 | case "char": |
| 100 | return descriptor + "S"; | 100 | return descriptor + "C"; |
| 101 | case "int": | 101 | case "short": |
| 102 | return descriptor + "I"; | 102 | return descriptor + "S"; |
| 103 | case "long": | 103 | case "int": |
| 104 | return descriptor + "J"; | 104 | return descriptor + "I"; |
| 105 | case "float": | 105 | case "long": |
| 106 | return descriptor + "F"; | 106 | return descriptor + "J"; |
| 107 | case "double": | 107 | case "float": |
| 108 | return descriptor + "D"; | 108 | return descriptor + "F"; |
| 109 | case "boolean": | 109 | case "double": |
| 110 | return descriptor + "Z"; | 110 | return descriptor + "D"; |
| 111 | case "void": | 111 | case "boolean": |
| 112 | return descriptor + "V"; | 112 | return descriptor + "Z"; |
| 113 | } | 113 | case "void": |
| 114 | 114 | return descriptor + "V"; | |
| 115 | descriptor.append("L"); | 115 | } |
| 116 | descriptor.append(type.replace('.', '/')); | 116 | |
| 117 | descriptor.append(";"); | 117 | descriptor.append("L"); |
| 118 | 118 | descriptor.append(type.replace('.', '/')); | |
| 119 | return descriptor.toString(); | 119 | descriptor.append(";"); |
| 120 | } | 120 | |
| 121 | 121 | return descriptor.toString(); | |
| 122 | private String getDescriptor(String returnType, String[] parameterTypes) { | 122 | } |
| 123 | StringBuilder descriptor = new StringBuilder(); | 123 | |
| 124 | descriptor.append('('); | 124 | private String getDescriptor(String returnType, String[] parameterTypes) { |
| 125 | 125 | StringBuilder descriptor = new StringBuilder(); | |
| 126 | for (String parameterType : parameterTypes) { | 126 | descriptor.append('('); |
| 127 | descriptor.append(getDescriptor(parameterType)); | 127 | |
| 128 | } | 128 | for (String parameterType : parameterTypes) { |
| 129 | 129 | descriptor.append(getDescriptor(parameterType)); | |
| 130 | descriptor.append(')'); | 130 | } |
| 131 | descriptor.append(getDescriptor(returnType)); | 131 | |
| 132 | 132 | descriptor.append(')'); | |
| 133 | return descriptor.toString(); | 133 | descriptor.append(getDescriptor(returnType)); |
| 134 | } | 134 | |
| 135 | return descriptor.toString(); | ||
| 136 | } | ||
| 135 | } | 137 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java index 483e4e40..ce54feae 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsReader.java | |||
| @@ -1,5 +1,12 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | 1 | package cuchaz.enigma.translation.mapping.serde.recaf; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Files; | ||
| 5 | import java.nio.file.Path; | ||
| 6 | import java.util.List; | ||
| 7 | import java.util.regex.Matcher; | ||
| 8 | import java.util.regex.Pattern; | ||
| 9 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 10 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMapping; | 11 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 12 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; |
| @@ -13,15 +20,7 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 20 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 15 | 22 | ||
| 16 | import java.io.IOException; | ||
| 17 | import java.nio.file.Files; | ||
| 18 | import java.nio.file.Path; | ||
| 19 | import java.util.List; | ||
| 20 | import java.util.regex.Matcher; | ||
| 21 | import java.util.regex.Pattern; | ||
| 22 | |||
| 23 | public class RecafMappingsReader implements MappingsReader { | 23 | public class RecafMappingsReader implements MappingsReader { |
| 24 | |||
| 25 | public static final RecafMappingsReader INSTANCE = new RecafMappingsReader(); | 24 | public static final RecafMappingsReader INSTANCE = new RecafMappingsReader(); |
| 26 | private static final Pattern METHOD_PATTERN = Pattern.compile("(.*?)\\.(.*?)(\\(.*?) (.*)"); | 25 | private static final Pattern METHOD_PATTERN = Pattern.compile("(.*?)\\.(.*?)(\\(.*?) (.*)"); |
| 27 | private static final Pattern FIELD_PATTERN = Pattern.compile("(.*?)\\.(.*?) (.*?) (.*)"); | 26 | private static final Pattern FIELD_PATTERN = Pattern.compile("(.*?)\\.(.*?) (.*?) (.*)"); |
| @@ -34,6 +33,7 @@ public class RecafMappingsReader implements MappingsReader { | |||
| 34 | 33 | ||
| 35 | for (String line : lines) { | 34 | for (String line : lines) { |
| 36 | Matcher methodMatcher = METHOD_PATTERN.matcher(line); | 35 | Matcher methodMatcher = METHOD_PATTERN.matcher(line); |
| 36 | |||
| 37 | if (methodMatcher.find()) { | 37 | if (methodMatcher.find()) { |
| 38 | ClassEntry owner = new ClassEntry(methodMatcher.group(1)); | 38 | ClassEntry owner = new ClassEntry(methodMatcher.group(1)); |
| 39 | String name = methodMatcher.group(2); | 39 | String name = methodMatcher.group(2); |
| @@ -43,6 +43,7 @@ public class RecafMappingsReader implements MappingsReader { | |||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | Matcher fieldMatcher = FIELD_PATTERN.matcher(line); | 45 | Matcher fieldMatcher = FIELD_PATTERN.matcher(line); |
| 46 | |||
| 46 | if (fieldMatcher.find()) { | 47 | if (fieldMatcher.find()) { |
| 47 | ClassEntry owner = new ClassEntry(fieldMatcher.group(1)); | 48 | ClassEntry owner = new ClassEntry(fieldMatcher.group(1)); |
| 48 | String name = fieldMatcher.group(2); | 49 | String name = fieldMatcher.group(2); |
| @@ -52,10 +53,12 @@ public class RecafMappingsReader implements MappingsReader { | |||
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | Matcher classMatcher = CLASS_PATTERN.matcher(line); | 55 | Matcher classMatcher = CLASS_PATTERN.matcher(line); |
| 56 | |||
| 55 | if (classMatcher.find()) { | 57 | if (classMatcher.find()) { |
| 56 | mappings.insert(new ClassEntry(classMatcher.group(1)), new EntryMapping(classMatcher.group(2))); | 58 | mappings.insert(new ClassEntry(classMatcher.group(1)), new EntryMapping(classMatcher.group(2))); |
| 57 | } | 59 | } |
| 58 | } | 60 | } |
| 61 | |||
| 59 | return mappings; | 62 | return mappings; |
| 60 | } | 63 | } |
| 61 | } | 64 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java index aa29ff60..df65b3c8 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/recaf/RecafMappingsWriter.java | |||
| @@ -1,6 +1,13 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | 1 | package cuchaz.enigma.translation.mapping.serde.recaf; |
| 2 | 2 | ||
| 3 | import java.io.BufferedWriter; | ||
| 4 | import java.io.IOException; | ||
| 5 | import java.io.Writer; | ||
| 6 | import java.nio.file.Files; | ||
| 7 | import java.nio.file.Path; | ||
| 8 | |||
| 3 | import com.google.common.collect.Lists; | 9 | import com.google.common.collect.Lists; |
| 10 | |||
| 4 | import cuchaz.enigma.ProgressListener; | 11 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 12 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 6 | import cuchaz.enigma.translation.mapping.MappingDelta; | 13 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| @@ -13,14 +20,7 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 13 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 20 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 21 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 15 | 22 | ||
| 16 | import java.io.BufferedWriter; | ||
| 17 | import java.io.IOException; | ||
| 18 | import java.io.Writer; | ||
| 19 | import java.nio.file.Files; | ||
| 20 | import java.nio.file.Path; | ||
| 21 | |||
| 22 | public class RecafMappingsWriter implements MappingsWriter { | 23 | public class RecafMappingsWriter implements MappingsWriter { |
| 23 | |||
| 24 | public static final RecafMappingsWriter INSTANCE = new RecafMappingsWriter(); | 24 | public static final RecafMappingsWriter INSTANCE = new RecafMappingsWriter(); |
| 25 | 25 | ||
| 26 | @Override | 26 | @Override |
| @@ -33,10 +33,7 @@ public class RecafMappingsWriter implements MappingsWriter { | |||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | try (BufferedWriter writer = Files.newBufferedWriter(path)) { | 35 | try (BufferedWriter writer = Files.newBufferedWriter(path)) { |
| 36 | Lists.newArrayList(mappings) | 36 | Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).forEach(entry -> writeEntry(writer, mappings, entry)); |
| 37 | .stream() | ||
| 38 | .map(EntryTreeNode::getEntry) | ||
| 39 | .forEach(entry -> writeEntry(writer, mappings, entry)); | ||
| 40 | } catch (IOException e) { | 37 | } catch (IOException e) { |
| 41 | e.printStackTrace(); | 38 | e.printStackTrace(); |
| 42 | } | 39 | } |
| @@ -44,6 +41,7 @@ public class RecafMappingsWriter implements MappingsWriter { | |||
| 44 | 41 | ||
| 45 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { | 42 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { |
| 46 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | 43 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); |
| 44 | |||
| 47 | if (node == null) { | 45 | if (node == null) { |
| 48 | return; | 46 | return; |
| 49 | } | 47 | } |
| @@ -53,27 +51,22 @@ public class RecafMappingsWriter implements MappingsWriter { | |||
| 53 | try { | 51 | try { |
| 54 | if (mapping != null && mapping.targetName() != null) { | 52 | if (mapping != null && mapping.targetName() != null) { |
| 55 | if (entry instanceof ClassEntry classEntry) { | 53 | if (entry instanceof ClassEntry classEntry) { |
| 56 | |||
| 57 | writer.write(classEntry.getFullName()); | 54 | writer.write(classEntry.getFullName()); |
| 58 | writer.write(" "); | 55 | writer.write(" "); |
| 59 | writer.write(mapping.targetName()); | 56 | writer.write(mapping.targetName()); |
| 60 | |||
| 61 | } else if (entry instanceof FieldEntry fieldEntry) { | 57 | } else if (entry instanceof FieldEntry fieldEntry) { |
| 62 | |||
| 63 | writer.write(fieldEntry.getFullName()); | 58 | writer.write(fieldEntry.getFullName()); |
| 64 | writer.write(" "); | 59 | writer.write(" "); |
| 65 | writer.write(fieldEntry.getDesc().toString()); | 60 | writer.write(fieldEntry.getDesc().toString()); |
| 66 | writer.write(" "); | 61 | writer.write(" "); |
| 67 | writer.write(mapping.targetName()); | 62 | writer.write(mapping.targetName()); |
| 68 | |||
| 69 | } else if (entry instanceof MethodEntry methodEntry) { | 63 | } else if (entry instanceof MethodEntry methodEntry) { |
| 70 | |||
| 71 | writer.write(methodEntry.getFullName()); | 64 | writer.write(methodEntry.getFullName()); |
| 72 | writer.write(methodEntry.getDesc().toString()); | 65 | writer.write(methodEntry.getDesc().toString()); |
| 73 | writer.write(" "); | 66 | writer.write(" "); |
| 74 | writer.write(mapping.targetName()); | 67 | writer.write(mapping.targetName()); |
| 75 | |||
| 76 | } | 68 | } |
| 69 | |||
| 77 | writer.write("\n"); | 70 | writer.write("\n"); |
| 78 | } | 71 | } |
| 79 | } catch (IOException e) { | 72 | } catch (IOException e) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java index 92758475..4621efef 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/srg/SrgMappingsWriter.java | |||
| @@ -1,14 +1,24 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.srg; | 1 | package cuchaz.enigma.translation.mapping.serde.srg; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.PrintWriter; | ||
| 5 | import java.nio.file.Files; | ||
| 6 | import java.nio.file.Path; | ||
| 7 | import java.util.ArrayList; | ||
| 8 | import java.util.Collection; | ||
| 9 | import java.util.Comparator; | ||
| 10 | import java.util.List; | ||
| 11 | |||
| 3 | import com.google.common.collect.Lists; | 12 | import com.google.common.collect.Lists; |
| 13 | |||
| 4 | import cuchaz.enigma.ProgressListener; | 14 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.translation.MappingTranslator; | 15 | import cuchaz.enigma.translation.MappingTranslator; |
| 6 | import cuchaz.enigma.translation.Translator; | 16 | import cuchaz.enigma.translation.Translator; |
| 7 | import cuchaz.enigma.translation.mapping.EntryMapping; | 17 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 8 | import cuchaz.enigma.translation.mapping.MappingDelta; | 18 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 10 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | 19 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; |
| 11 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; | 20 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; |
| 21 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 12 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | 22 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; |
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 23 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 14 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 24 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| @@ -18,15 +28,6 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 28 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | import cuchaz.enigma.utils.I18n; | 29 | import cuchaz.enigma.utils.I18n; |
| 20 | 30 | ||
| 21 | import java.io.IOException; | ||
| 22 | import java.io.PrintWriter; | ||
| 23 | import java.nio.file.Files; | ||
| 24 | import java.nio.file.Path; | ||
| 25 | import java.util.ArrayList; | ||
| 26 | import java.util.Collection; | ||
| 27 | import java.util.Comparator; | ||
| 28 | import java.util.List; | ||
| 29 | |||
| 30 | public enum SrgMappingsWriter implements MappingsWriter { | 31 | public enum SrgMappingsWriter implements MappingsWriter { |
| 31 | INSTANCE; | 32 | INSTANCE; |
| 32 | 33 | ||
| @@ -43,18 +44,18 @@ public enum SrgMappingsWriter implements MappingsWriter { | |||
| 43 | List<String> fieldLines = new ArrayList<>(); | 44 | List<String> fieldLines = new ArrayList<>(); |
| 44 | List<String> methodLines = new ArrayList<>(); | 45 | List<String> methodLines = new ArrayList<>(); |
| 45 | 46 | ||
| 46 | List<? extends Entry<?>> rootEntries = Lists.newArrayList(mappings).stream() | 47 | List<? extends Entry<?>> rootEntries = Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).toList(); |
| 47 | .map(EntryTreeNode::getEntry) | ||
| 48 | .toList(); | ||
| 49 | progress.init(rootEntries.size(), I18n.translate("progress.mappings.srg_file.generating")); | 48 | progress.init(rootEntries.size(), I18n.translate("progress.mappings.srg_file.generating")); |
| 50 | 49 | ||
| 51 | int steps = 0; | 50 | int steps = 0; |
| 51 | |||
| 52 | for (Entry<?> entry : sorted(rootEntries)) { | 52 | for (Entry<?> entry : sorted(rootEntries)) { |
| 53 | progress.step(steps++, entry.getName()); | 53 | progress.step(steps++, entry.getName()); |
| 54 | writeEntry(classLines, fieldLines, methodLines, mappings, entry); | 54 | writeEntry(classLines, fieldLines, methodLines, mappings, entry); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | progress.init(3, I18n.translate("progress.mappings.srg_file.writing")); | 57 | progress.init(3, I18n.translate("progress.mappings.srg_file.writing")); |
| 58 | |||
| 58 | try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { | 59 | try (PrintWriter writer = new LfPrintWriter(Files.newBufferedWriter(path))) { |
| 59 | progress.step(0, I18n.translate("type.classes")); | 60 | progress.step(0, I18n.translate("type.classes")); |
| 60 | classLines.forEach(writer::println); | 61 | classLines.forEach(writer::println); |
| @@ -69,11 +70,13 @@ public enum SrgMappingsWriter implements MappingsWriter { | |||
| 69 | 70 | ||
| 70 | private void writeEntry(List<String> classes, List<String> fields, List<String> methods, EntryTree<EntryMapping> mappings, Entry<?> entry) { | 71 | private void writeEntry(List<String> classes, List<String> fields, List<String> methods, EntryTree<EntryMapping> mappings, Entry<?> entry) { |
| 71 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | 72 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); |
| 73 | |||
| 72 | if (node == null) { | 74 | if (node == null) { |
| 73 | return; | 75 | return; |
| 74 | } | 76 | } |
| 75 | 77 | ||
| 76 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | 78 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); |
| 79 | |||
| 77 | if (entry instanceof ClassEntry) { | 80 | if (entry instanceof ClassEntry) { |
| 78 | classes.add(generateClassLine((ClassEntry) entry, translator)); | 81 | classes.add(generateClassLine((ClassEntry) entry, translator)); |
| 79 | } else if (entry instanceof FieldEntry) { | 82 | } else if (entry instanceof FieldEntry) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java index f3c66dfb..e08c8673 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsReader.java | |||
| @@ -1,10 +1,16 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.tiny; | 1 | package cuchaz.enigma.translation.mapping.serde.tiny; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.file.Files; | ||
| 5 | import java.nio.file.Path; | ||
| 6 | import java.util.List; | ||
| 7 | |||
| 3 | import com.google.common.base.Charsets; | 8 | import com.google.common.base.Charsets; |
| 9 | |||
| 4 | import cuchaz.enigma.ProgressListener; | 10 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | 11 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 7 | import cuchaz.enigma.translation.mapping.MappingPair; | 12 | import cuchaz.enigma.translation.mapping.MappingPair; |
| 13 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 14 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | 15 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; |
| 10 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| @@ -17,11 +23,6 @@ import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 23 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 18 | import cuchaz.enigma.utils.I18n; | 24 | import cuchaz.enigma.utils.I18n; |
| 19 | 25 | ||
| 20 | import java.io.IOException; | ||
| 21 | import java.nio.file.Files; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.util.List; | ||
| 24 | |||
| 25 | public enum TinyMappingsReader implements MappingsReader { | 26 | public enum TinyMappingsReader implements MappingsReader { |
| 26 | INSTANCE; | 27 | INSTANCE; |
| 27 | 28 | ||
| @@ -62,26 +63,28 @@ public enum TinyMappingsReader implements MappingsReader { | |||
| 62 | 63 | ||
| 63 | String key = tokens[0]; | 64 | String key = tokens[0]; |
| 64 | switch (key) { | 65 | switch (key) { |
| 65 | case "CLASS": | 66 | case "CLASS": |
| 66 | return parseClass(tokens); | 67 | return parseClass(tokens); |
| 67 | case "FIELD": | 68 | case "FIELD": |
| 68 | return parseField(tokens); | 69 | return parseField(tokens); |
| 69 | case "METHOD": | 70 | case "METHOD": |
| 70 | return parseMethod(tokens); | 71 | return parseMethod(tokens); |
| 71 | case "MTH-ARG": | 72 | case "MTH-ARG": |
| 72 | return parseArgument(tokens); | 73 | return parseArgument(tokens); |
| 73 | default: | 74 | default: |
| 74 | throw new RuntimeException("Unknown token '" + key + "'!"); | 75 | throw new RuntimeException("Unknown token '" + key + "'!"); |
| 75 | } | 76 | } |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | private MappingPair<ClassEntry, EntryMapping> parseClass(String[] tokens) { | 79 | private MappingPair<ClassEntry, EntryMapping> parseClass(String[] tokens) { |
| 79 | ClassEntry obfuscatedEntry = new ClassEntry(tokens[1]); | 80 | ClassEntry obfuscatedEntry = new ClassEntry(tokens[1]); |
| 80 | String mapping = tokens[2]; | 81 | String mapping = tokens[2]; |
| 82 | |||
| 81 | if (mapping.indexOf('$') > 0) { | 83 | if (mapping.indexOf('$') > 0) { |
| 82 | // inner classes should map to only the final part | 84 | // inner classes should map to only the final part |
| 83 | mapping = mapping.substring(mapping.lastIndexOf('$') + 1); | 85 | mapping = mapping.substring(mapping.lastIndexOf('$') + 1); |
| 84 | } | 86 | } |
| 87 | |||
| 85 | return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping)); | 88 | return new MappingPair<>(obfuscatedEntry, new EntryMapping(mapping)); |
| 86 | } | 89 | } |
| 87 | 90 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java index 1f785e10..972d1807 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tiny/TinyMappingsWriter.java | |||
| @@ -1,14 +1,25 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.tiny; | 1 | package cuchaz.enigma.translation.mapping.serde.tiny; |
| 2 | 2 | ||
| 3 | import java.io.BufferedWriter; | ||
| 4 | import java.io.IOException; | ||
| 5 | import java.io.Writer; | ||
| 6 | import java.nio.charset.StandardCharsets; | ||
| 7 | import java.nio.file.Files; | ||
| 8 | import java.nio.file.Path; | ||
| 9 | import java.util.Comparator; | ||
| 10 | import java.util.HashSet; | ||
| 11 | import java.util.Set; | ||
| 12 | |||
| 3 | import com.google.common.base.Joiner; | 13 | import com.google.common.base.Joiner; |
| 4 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 15 | |||
| 5 | import cuchaz.enigma.ProgressListener; | 16 | import cuchaz.enigma.ProgressListener; |
| 6 | import cuchaz.enigma.translation.MappingTranslator; | 17 | import cuchaz.enigma.translation.MappingTranslator; |
| 7 | import cuchaz.enigma.translation.Translator; | 18 | import cuchaz.enigma.translation.Translator; |
| 8 | import cuchaz.enigma.translation.mapping.EntryMapping; | 19 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 9 | import cuchaz.enigma.translation.mapping.MappingDelta; | 20 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 11 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; | 21 | import cuchaz.enigma.translation.mapping.VoidEntryResolver; |
| 22 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 12 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | 23 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; |
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 24 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 14 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 25 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| @@ -17,136 +28,120 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 28 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 29 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | 30 | ||
| 20 | import java.io.BufferedWriter; | ||
| 21 | import java.io.IOException; | ||
| 22 | import java.io.Writer; | ||
| 23 | import java.nio.charset.StandardCharsets; | ||
| 24 | import java.nio.file.Files; | ||
| 25 | import java.nio.file.Path; | ||
| 26 | import java.util.Comparator; | ||
| 27 | import java.util.HashSet; | ||
| 28 | import java.util.Set; | ||
| 29 | |||
| 30 | public class TinyMappingsWriter implements MappingsWriter { | 31 | public class TinyMappingsWriter implements MappingsWriter { |
| 31 | private static final String VERSION_CONSTANT = "v1"; | 32 | private static final String VERSION_CONSTANT = "v1"; |
| 32 | private static final Joiner TAB_JOINER = Joiner.on('\t'); | 33 | private static final Joiner TAB_JOINER = Joiner.on('\t'); |
| 33 | 34 | ||
| 34 | //Possibly add a gui or a way to select the namespaces when exporting from the gui | 35 | //Possibly add a gui or a way to select the namespaces when exporting from the gui |
| 35 | public static final TinyMappingsWriter INSTANCE = new TinyMappingsWriter("intermediary", "named"); | 36 | public static final TinyMappingsWriter INSTANCE = new TinyMappingsWriter("intermediary", "named"); |
| 36 | 37 | ||
| 37 | // HACK: as of enigma 0.13.1, some fields seem to appear duplicated? | 38 | // HACK: as of enigma 0.13.1, some fields seem to appear duplicated? |
| 38 | private final Set<String> writtenLines = new HashSet<>(); | 39 | private final Set<String> writtenLines = new HashSet<>(); |
| 39 | private final String nameObf; | 40 | private final String nameObf; |
| 40 | private final String nameDeobf; | 41 | private final String nameDeobf; |
| 41 | 42 | ||
| 42 | public TinyMappingsWriter(String nameObf, String nameDeobf) { | 43 | public TinyMappingsWriter(String nameObf, String nameDeobf) { |
| 43 | this.nameObf = nameObf; | 44 | this.nameObf = nameObf; |
| 44 | this.nameDeobf = nameDeobf; | 45 | this.nameDeobf = nameDeobf; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | @Override | 48 | @Override |
| 48 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { | 49 | public void write(EntryTree<EntryMapping> mappings, MappingDelta<EntryMapping> delta, Path path, ProgressListener progress, MappingSaveParameters saveParameters) { |
| 49 | try { | 50 | try { |
| 50 | Files.deleteIfExists(path); | 51 | Files.deleteIfExists(path); |
| 51 | Files.createFile(path); | 52 | Files.createFile(path); |
| 52 | } catch (IOException e) { | 53 | } catch (IOException e) { |
| 53 | e.printStackTrace(); | 54 | e.printStackTrace(); |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { | 57 | try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { |
| 57 | writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf}); | 58 | writeLine(writer, new String[]{VERSION_CONSTANT, nameObf, nameDeobf}); |
| 58 | 59 | ||
| 59 | Lists.newArrayList(mappings).stream() | 60 | Lists.newArrayList(mappings).stream().map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString)).forEach(entry -> writeEntry(writer, mappings, entry)); |
| 60 | .map(EntryTreeNode::getEntry).sorted(Comparator.comparing(Object::toString)) | 61 | } catch (IOException e) { |
| 61 | .forEach(entry -> writeEntry(writer, mappings, entry)); | 62 | e.printStackTrace(); |
| 62 | } catch (IOException e) { | 63 | } |
| 63 | e.printStackTrace(); | 64 | } |
| 64 | } | 65 | |
| 65 | } | 66 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { |
| 66 | 67 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | |
| 67 | private void writeEntry(Writer writer, EntryTree<EntryMapping> mappings, Entry<?> entry) { | 68 | |
| 68 | EntryTreeNode<EntryMapping> node = mappings.findNode(entry); | 69 | if (node == null) { |
| 69 | if (node == null) { | 70 | return; |
| 70 | return; | 71 | } |
| 71 | } | 72 | |
| 72 | 73 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | |
| 73 | Translator translator = new MappingTranslator(mappings, VoidEntryResolver.INSTANCE); | 74 | |
| 74 | 75 | EntryMapping mapping = mappings.get(entry); | |
| 75 | EntryMapping mapping = mappings.get(entry); | 76 | |
| 76 | 77 | // Do not write mappings without deobfuscated name since tiny v1 doesn't | |
| 77 | // Do not write mappings without deobfuscated name since tiny v1 doesn't | 78 | // support comments anyway |
| 78 | // support comments anyway | ||
| 79 | if (mapping != null && mapping.targetName() != null) { | 79 | if (mapping != null && mapping.targetName() != null) { |
| 80 | if (entry instanceof ClassEntry) { | 80 | if (entry instanceof ClassEntry) { |
| 81 | writeClass(writer, (ClassEntry) entry, translator); | 81 | writeClass(writer, (ClassEntry) entry, translator); |
| 82 | } else if (entry instanceof FieldEntry) { | 82 | } else if (entry instanceof FieldEntry) { |
| 83 | writeLine(writer, serializeEntry(entry, mapping.targetName())); | 83 | writeLine(writer, serializeEntry(entry, mapping.targetName())); |
| 84 | } else if (entry instanceof MethodEntry) { | 84 | } else if (entry instanceof MethodEntry) { |
| 85 | writeLine(writer, serializeEntry(entry, mapping.targetName())); | 85 | writeLine(writer, serializeEntry(entry, mapping.targetName())); |
| 86 | } | 86 | } |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | writeChildren(writer, mappings, node); | 89 | writeChildren(writer, mappings, node); |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) { | 92 | private void writeChildren(Writer writer, EntryTree<EntryMapping> mappings, EntryTreeNode<EntryMapping> node) { |
| 93 | node.getChildren().stream() | 93 | node.getChildren().stream().filter(e -> e instanceof FieldEntry).sorted().forEach(child -> writeEntry(writer, mappings, child)); |
| 94 | .filter(e -> e instanceof FieldEntry).sorted() | 94 | |
| 95 | .forEach(child -> writeEntry(writer, mappings, child)); | 95 | node.getChildren().stream().filter(e -> e instanceof MethodEntry).sorted().forEach(child -> writeEntry(writer, mappings, child)); |
| 96 | 96 | ||
| 97 | node.getChildren().stream() | 97 | node.getChildren().stream().filter(e -> e instanceof ClassEntry).sorted().forEach(child -> writeEntry(writer, mappings, child)); |
| 98 | .filter(e -> e instanceof MethodEntry).sorted() | 98 | } |
| 99 | .forEach(child -> writeEntry(writer, mappings, child)); | 99 | |
| 100 | 100 | private void writeClass(Writer writer, ClassEntry entry, Translator translator) { | |
| 101 | node.getChildren().stream() | 101 | ClassEntry translatedEntry = translator.translate(entry); |
| 102 | .filter(e -> e instanceof ClassEntry).sorted() | 102 | |
| 103 | .forEach(child -> writeEntry(writer, mappings, child)); | 103 | String obfClassName = entry.getFullName(); |
| 104 | } | 104 | String deobfClassName = translatedEntry.getFullName(); |
| 105 | 105 | writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName}); | |
| 106 | private void writeClass(Writer writer, ClassEntry entry, Translator translator) { | 106 | } |
| 107 | ClassEntry translatedEntry = translator.translate(entry); | 107 | |
| 108 | 108 | private void writeLine(Writer writer, String[] data) { | |
| 109 | String obfClassName = entry.getFullName(); | 109 | try { |
| 110 | String deobfClassName = translatedEntry.getFullName(); | 110 | String line = TAB_JOINER.join(data) + "\n"; |
| 111 | writeLine(writer, new String[]{"CLASS", obfClassName, deobfClassName}); | 111 | |
| 112 | } | 112 | if (writtenLines.add(line)) { |
| 113 | 113 | writer.write(line); | |
| 114 | private void writeLine(Writer writer, String[] data) { | 114 | } |
| 115 | try { | 115 | } catch (IOException e) { |
| 116 | String line = TAB_JOINER.join(data) + "\n"; | 116 | throw new RuntimeException(e); |
| 117 | if (writtenLines.add(line)) { | 117 | } |
| 118 | writer.write(line); | 118 | } |
| 119 | } | 119 | |
| 120 | } catch (IOException e) { | 120 | private String[] serializeEntry(Entry<?> entry, String... extraFields) { |
| 121 | throw new RuntimeException(e); | 121 | String[] data = null; |
| 122 | } | 122 | |
| 123 | } | 123 | if (entry instanceof FieldEntry) { |
| 124 | 124 | data = new String[4 + extraFields.length]; | |
| 125 | private String[] serializeEntry(Entry<?> entry, String... extraFields) { | 125 | data[0] = "FIELD"; |
| 126 | String[] data = null; | 126 | data[1] = entry.getContainingClass().getFullName(); |
| 127 | 127 | data[2] = ((FieldEntry) entry).getDesc().toString(); | |
| 128 | if (entry instanceof FieldEntry) { | 128 | data[3] = entry.getName(); |
| 129 | data = new String[4 + extraFields.length]; | 129 | } else if (entry instanceof MethodEntry) { |
| 130 | data[0] = "FIELD"; | 130 | data = new String[4 + extraFields.length]; |
| 131 | data[1] = entry.getContainingClass().getFullName(); | 131 | data[0] = "METHOD"; |
| 132 | data[2] = ((FieldEntry) entry).getDesc().toString(); | 132 | data[1] = entry.getContainingClass().getFullName(); |
| 133 | data[3] = entry.getName(); | 133 | data[2] = ((MethodEntry) entry).getDesc().toString(); |
| 134 | } else if (entry instanceof MethodEntry) { | 134 | data[3] = entry.getName(); |
| 135 | data = new String[4 + extraFields.length]; | 135 | } else if (entry instanceof ClassEntry) { |
| 136 | data[0] = "METHOD"; | 136 | data = new String[2 + extraFields.length]; |
| 137 | data[1] = entry.getContainingClass().getFullName(); | 137 | data[0] = "CLASS"; |
| 138 | data[2] = ((MethodEntry) entry).getDesc().toString(); | 138 | data[1] = ((ClassEntry) entry).getFullName(); |
| 139 | data[3] = entry.getName(); | 139 | } |
| 140 | } else if (entry instanceof ClassEntry) { | 140 | |
| 141 | data = new String[2 + extraFields.length]; | 141 | if (data != null) { |
| 142 | data[0] = "CLASS"; | 142 | System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length); |
| 143 | data[1] = ((ClassEntry) entry).getFullName(); | 143 | } |
| 144 | } | 144 | |
| 145 | 145 | return data; | |
| 146 | if (data != null) { | 146 | } |
| 147 | System.arraycopy(extraFields, 0, data, data.length - extraFields.length, extraFields.length); | ||
| 148 | } | ||
| 149 | |||
| 150 | return data; | ||
| 151 | } | ||
| 152 | } | 147 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java index dc3246de..61bc41da 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Reader.java | |||
| @@ -1,9 +1,16 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.tinyv2; | 1 | package cuchaz.enigma.translation.mapping.serde.tinyv2; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.nio.charset.StandardCharsets; | ||
| 5 | import java.nio.file.Files; | ||
| 6 | import java.nio.file.Path; | ||
| 7 | import java.util.BitSet; | ||
| 8 | import java.util.List; | ||
| 9 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 10 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 11 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 6 | import cuchaz.enigma.translation.mapping.MappingPair; | 12 | import cuchaz.enigma.translation.mapping.MappingPair; |
| 13 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | ||
| 7 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 14 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; | 15 | import cuchaz.enigma.translation.mapping.serde.MappingsReader; |
| 9 | import cuchaz.enigma.translation.mapping.serde.RawEntryMapping; | 16 | import cuchaz.enigma.translation.mapping.serde.RawEntryMapping; |
| @@ -17,15 +24,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | 24 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 25 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | 26 | ||
| 20 | import java.io.IOException; | ||
| 21 | import java.nio.charset.StandardCharsets; | ||
| 22 | import java.nio.file.Files; | ||
| 23 | import java.nio.file.Path; | ||
| 24 | import java.util.BitSet; | ||
| 25 | import java.util.List; | ||
| 26 | |||
| 27 | public final class TinyV2Reader implements MappingsReader { | 27 | public final class TinyV2Reader implements MappingsReader { |
| 28 | |||
| 29 | private static final String MINOR_VERSION = "0"; | 28 | private static final String MINOR_VERSION = "0"; |
| 30 | // 0 indent | 29 | // 0 indent |
| 31 | private static final int IN_HEADER = 0; | 30 | private static final int IN_HEADER = 0; |
| @@ -50,8 +49,7 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 50 | progress.init(lines.size(), "progress.mappings.tiny_v2.loading"); | 49 | progress.init(lines.size(), "progress.mappings.tiny_v2.loading"); |
| 51 | 50 | ||
| 52 | BitSet state = new BitSet(STATE_SIZE); | 51 | BitSet state = new BitSet(STATE_SIZE); |
| 53 | @SuppressWarnings({"unchecked", "rawtypes"}) | 52 | @SuppressWarnings({"unchecked", "rawtypes"}) MappingPair<? extends Entry<?>, RawEntryMapping>[] holds = new MappingPair[STATE_SIZE]; |
| 54 | MappingPair<? extends Entry<?>, RawEntryMapping>[] holds = new MappingPair[STATE_SIZE]; | ||
| 55 | boolean escapeNames = false; | 53 | boolean escapeNames = false; |
| 56 | 54 | ||
| 57 | for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { | 55 | for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) { |
| @@ -60,16 +58,21 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 60 | String line = lines.get(lineNumber); | 58 | String line = lines.get(lineNumber); |
| 61 | 59 | ||
| 62 | int indent = 0; | 60 | int indent = 0; |
| 63 | while (line.charAt(indent) == '\t') | 61 | |
| 62 | while (line.charAt(indent) == '\t') { | ||
| 64 | indent++; | 63 | indent++; |
| 64 | } | ||
| 65 | 65 | ||
| 66 | String[] parts = line.substring(indent).split("\t", -1); | 66 | String[] parts = line.substring(indent).split("\t", -1); |
| 67 | if (parts.length == 0 || indent >= INDENT_CLEAR_START.length) | 67 | |
| 68 | if (parts.length == 0 || indent >= INDENT_CLEAR_START.length) { | ||
| 68 | throw new IllegalArgumentException("Invalid format"); | 69 | throw new IllegalArgumentException("Invalid format"); |
| 70 | } | ||
| 69 | 71 | ||
| 70 | // clean and register stuff in stack | 72 | // clean and register stuff in stack |
| 71 | for (int i = INDENT_CLEAR_START[indent]; i < STATE_SIZE; i++) { | 73 | for (int i = INDENT_CLEAR_START[indent]; i < STATE_SIZE; i++) { |
| 72 | state.clear(i); | 74 | state.clear(i); |
| 75 | |||
| 73 | if (holds[i] != null) { | 76 | if (holds[i] != null) { |
| 74 | bakeHeld(mappings, holds[i]); | 77 | bakeHeld(mappings, holds[i]); |
| 75 | holds[i] = null; | 78 | holds[i] = null; |
| @@ -77,104 +80,112 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | switch (indent) { | 82 | switch (indent) { |
| 80 | case 0: | 83 | case 0: |
| 81 | switch (parts[0]) { | 84 | switch (parts[0]) { |
| 82 | case "tiny": // header | 85 | case "tiny": // header |
| 83 | if (lineNumber != 0) { | 86 | if (lineNumber != 0) { |
| 84 | throw new IllegalArgumentException("Header can only be on the first line"); | 87 | throw new IllegalArgumentException("Header can only be on the first line"); |
| 85 | } | 88 | } |
| 86 | if (parts.length < 5) { | 89 | |
| 87 | throw new IllegalArgumentException("Not enough header columns, needs at least 5"); | 90 | if (parts.length < 5) { |
| 88 | } | 91 | throw new IllegalArgumentException("Not enough header columns, needs at least 5"); |
| 89 | if (!"2".equals(parts[1]) || !MINOR_VERSION.equals(parts[2])) { | ||
| 90 | throw new IllegalArgumentException("Unsupported TinyV2 version, requires major " + "2" + " and minor " + MINOR_VERSION + ""); | ||
| 91 | } | ||
| 92 | state.set(IN_HEADER); | ||
| 93 | break; | ||
| 94 | case "c": // class | ||
| 95 | state.set(IN_CLASS); | ||
| 96 | holds[IN_CLASS] = parseClass(parts, escapeNames); | ||
| 97 | break; | ||
| 98 | default: | ||
| 99 | unsupportKey(parts); | ||
| 100 | } | 92 | } |
| 101 | 93 | ||
| 94 | if (!"2".equals(parts[1]) || !MINOR_VERSION.equals(parts[2])) { | ||
| 95 | throw new IllegalArgumentException("Unsupported TinyV2 version, requires major " + "2" + " and minor " + MINOR_VERSION + ""); | ||
| 96 | } | ||
| 97 | |||
| 98 | state.set(IN_HEADER); | ||
| 99 | break; | ||
| 100 | case "c": // class | ||
| 101 | state.set(IN_CLASS); | ||
| 102 | holds[IN_CLASS] = parseClass(parts, escapeNames); | ||
| 102 | break; | 103 | break; |
| 103 | case 1: | 104 | default: |
| 104 | if (state.get(IN_HEADER)) { | 105 | unsupportKey(parts); |
| 105 | if (parts[0].equals("esacpe-names")) { | 106 | } |
| 106 | escapeNames = true; | ||
| 107 | } | ||
| 108 | 107 | ||
| 109 | break; | 108 | break; |
| 109 | case 1: | ||
| 110 | if (state.get(IN_HEADER)) { | ||
| 111 | if (parts[0].equals("esacpe-names")) { | ||
| 112 | escapeNames = true; | ||
| 110 | } | 113 | } |
| 111 | 114 | ||
| 112 | if (state.get(IN_CLASS)) { | 115 | break; |
| 113 | switch (parts[0]) { | 116 | } |
| 114 | case "m": // method | 117 | |
| 115 | state.set(IN_METHOD); | 118 | if (state.get(IN_CLASS)) { |
| 116 | holds[IN_METHOD] = parseMethod(holds[IN_CLASS], parts, escapeNames); | 119 | switch (parts[0]) { |
| 117 | break; | 120 | case "m": // method |
| 118 | case "f": // field | 121 | state.set(IN_METHOD); |
| 119 | state.set(IN_FIELD); | 122 | holds[IN_METHOD] = parseMethod(holds[IN_CLASS], parts, escapeNames); |
| 120 | holds[IN_FIELD] = parseField(holds[IN_CLASS], parts, escapeNames); | 123 | break; |
| 121 | break; | 124 | case "f": // field |
| 122 | case "c": // class javadoc | 125 | state.set(IN_FIELD); |
| 123 | addJavadoc(holds[IN_CLASS], parts); | 126 | holds[IN_FIELD] = parseField(holds[IN_CLASS], parts, escapeNames); |
| 124 | break; | 127 | break; |
| 125 | default: | 128 | case "c": // class javadoc |
| 126 | unsupportKey(parts); | 129 | addJavadoc(holds[IN_CLASS], parts); |
| 127 | } | ||
| 128 | break; | 130 | break; |
| 131 | default: | ||
| 132 | unsupportKey(parts); | ||
| 129 | } | 133 | } |
| 130 | 134 | ||
| 131 | unsupportKey(parts); | 135 | break; |
| 132 | case 2: | 136 | } |
| 133 | if (state.get(IN_METHOD)) { | 137 | |
| 134 | switch (parts[0]) { | 138 | unsupportKey(parts); |
| 135 | case "p": // parameter | 139 | case 2: |
| 136 | state.set(IN_PARAMETER); | 140 | if (state.get(IN_METHOD)) { |
| 137 | holds[IN_PARAMETER] = parseArgument(holds[IN_METHOD], parts, escapeNames); | 141 | switch (parts[0]) { |
| 138 | break; | 142 | case "p": // parameter |
| 139 | case "v": // local variable | 143 | state.set(IN_PARAMETER); |
| 140 | // TODO add local var mapping | 144 | holds[IN_PARAMETER] = parseArgument(holds[IN_METHOD], parts, escapeNames); |
| 141 | break; | ||
| 142 | case "c": // method javadoc | ||
| 143 | addJavadoc(holds[IN_METHOD], parts); | ||
| 144 | break; | ||
| 145 | default: | ||
| 146 | unsupportKey(parts); | ||
| 147 | } | ||
| 148 | break; | 145 | break; |
| 146 | case "v": // local variable | ||
| 147 | // TODO add local var mapping | ||
| 148 | break; | ||
| 149 | case "c": // method javadoc | ||
| 150 | addJavadoc(holds[IN_METHOD], parts); | ||
| 151 | break; | ||
| 152 | default: | ||
| 153 | unsupportKey(parts); | ||
| 149 | } | 154 | } |
| 150 | 155 | ||
| 151 | if (state.get(IN_FIELD)) { | 156 | break; |
| 152 | switch (parts[0]) { | 157 | } |
| 153 | case "c": // field javadoc | 158 | |
| 154 | addJavadoc(holds[IN_FIELD], parts); | 159 | if (state.get(IN_FIELD)) { |
| 155 | break; | 160 | switch (parts[0]) { |
| 156 | default: | 161 | case "c": // field javadoc |
| 157 | unsupportKey(parts); | 162 | addJavadoc(holds[IN_FIELD], parts); |
| 158 | } | ||
| 159 | break; | 163 | break; |
| 164 | default: | ||
| 165 | unsupportKey(parts); | ||
| 160 | } | 166 | } |
| 161 | unsupportKey(parts); | 167 | |
| 162 | case 3: | 168 | break; |
| 163 | if (state.get(IN_PARAMETER)) { | 169 | } |
| 164 | switch (parts[0]) { | 170 | |
| 165 | case "c": | 171 | unsupportKey(parts); |
| 166 | addJavadoc(holds[IN_PARAMETER], parts); | 172 | case 3: |
| 167 | break; | 173 | if (state.get(IN_PARAMETER)) { |
| 168 | default: | 174 | switch (parts[0]) { |
| 169 | unsupportKey(parts); | 175 | case "c": |
| 170 | } | 176 | addJavadoc(holds[IN_PARAMETER], parts); |
| 171 | break; | 177 | break; |
| 178 | default: | ||
| 179 | unsupportKey(parts); | ||
| 172 | } | 180 | } |
| 173 | unsupportKey(parts); | ||
| 174 | default: | ||
| 175 | unsupportKey(parts); | ||
| 176 | } | ||
| 177 | 181 | ||
| 182 | break; | ||
| 183 | } | ||
| 184 | |||
| 185 | unsupportKey(parts); | ||
| 186 | default: | ||
| 187 | unsupportKey(parts); | ||
| 188 | } | ||
| 178 | } catch (Throwable t) { | 189 | } catch (Throwable t) { |
| 179 | t.printStackTrace(); | 190 | t.printStackTrace(); |
| 180 | throw new MappingParseException(path::toString, lineNumber + 1, t.toString()); | 191 | throw new MappingParseException(path::toString, lineNumber + 1, t.toString()); |
| @@ -193,8 +204,10 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 193 | 204 | ||
| 194 | private static void bakeHeld(EntryTree<EntryMapping> mappings, MappingPair<? extends Entry<?>, RawEntryMapping> hold2) { | 205 | private static void bakeHeld(EntryTree<EntryMapping> mappings, MappingPair<? extends Entry<?>, RawEntryMapping> hold2) { |
| 195 | RawEntryMapping mapping = hold2.getMapping(); | 206 | RawEntryMapping mapping = hold2.getMapping(); |
| 207 | |||
| 196 | if (mapping != null) { | 208 | if (mapping != null) { |
| 197 | EntryMapping baked = mapping.bake(); | 209 | EntryMapping baked = mapping.bake(); |
| 210 | |||
| 198 | if (baked != null) { | 211 | if (baked != null) { |
| 199 | mappings.insert(hold2.getEntry(), baked); | 212 | mappings.insert(hold2.getEntry(), baked); |
| 200 | } | 213 | } |
| @@ -215,8 +228,11 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 215 | 228 | ||
| 216 | private MappingPair<ClassEntry, RawEntryMapping> parseClass(String[] tokens, boolean escapeNames) { | 229 | private MappingPair<ClassEntry, RawEntryMapping> parseClass(String[] tokens, boolean escapeNames) { |
| 217 | ClassEntry obfuscatedEntry = new ClassEntry(unescapeOpt(tokens[1], escapeNames)); | 230 | ClassEntry obfuscatedEntry = new ClassEntry(unescapeOpt(tokens[1], escapeNames)); |
| 218 | if (tokens.length <= 2) | 231 | |
| 232 | if (tokens.length <= 2) { | ||
| 219 | return new MappingPair<>(obfuscatedEntry); | 233 | return new MappingPair<>(obfuscatedEntry); |
| 234 | } | ||
| 235 | |||
| 220 | String token2 = unescapeOpt(tokens[2], escapeNames); | 236 | String token2 = unescapeOpt(tokens[2], escapeNames); |
| 221 | String mapping = token2.substring(token2.lastIndexOf('$') + 1); | 237 | String mapping = token2.substring(token2.lastIndexOf('$') + 1); |
| 222 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); | 238 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); |
| @@ -227,8 +243,11 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 227 | TypeDescriptor descriptor = new TypeDescriptor(unescapeOpt(tokens[1], escapeNames)); | 243 | TypeDescriptor descriptor = new TypeDescriptor(unescapeOpt(tokens[1], escapeNames)); |
| 228 | 244 | ||
| 229 | FieldEntry obfuscatedEntry = new FieldEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); | 245 | FieldEntry obfuscatedEntry = new FieldEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); |
| 230 | if (tokens.length <= 3) | 246 | |
| 247 | if (tokens.length <= 3) { | ||
| 231 | return new MappingPair<>(obfuscatedEntry); | 248 | return new MappingPair<>(obfuscatedEntry); |
| 249 | } | ||
| 250 | |||
| 232 | String mapping = unescapeOpt(tokens[3], escapeNames); | 251 | String mapping = unescapeOpt(tokens[3], escapeNames); |
| 233 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); | 252 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); |
| 234 | } | 253 | } |
| @@ -238,24 +257,25 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 238 | MethodDescriptor descriptor = new MethodDescriptor(unescapeOpt(tokens[1], escapeNames)); | 257 | MethodDescriptor descriptor = new MethodDescriptor(unescapeOpt(tokens[1], escapeNames)); |
| 239 | 258 | ||
| 240 | MethodEntry obfuscatedEntry = new MethodEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); | 259 | MethodEntry obfuscatedEntry = new MethodEntry(ownerClass, unescapeOpt(tokens[2], escapeNames), descriptor); |
| 241 | if (tokens.length <= 3) | 260 | |
| 261 | if (tokens.length <= 3) { | ||
| 242 | return new MappingPair<>(obfuscatedEntry); | 262 | return new MappingPair<>(obfuscatedEntry); |
| 263 | } | ||
| 264 | |||
| 243 | String mapping = unescapeOpt(tokens[3], escapeNames); | 265 | String mapping = unescapeOpt(tokens[3], escapeNames); |
| 244 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); | 266 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); |
| 245 | } | 267 | } |
| 246 | 268 | ||
| 247 | |||
| 248 | |||
| 249 | private void addJavadoc(MappingPair<? extends Entry, RawEntryMapping> pair, String javadoc) { | 269 | private void addJavadoc(MappingPair<? extends Entry, RawEntryMapping> pair, String javadoc) { |
| 250 | RawEntryMapping mapping = pair.getMapping(); | 270 | RawEntryMapping mapping = pair.getMapping(); |
| 271 | |||
| 251 | if (mapping == null) { | 272 | if (mapping == null) { |
| 252 | throw new IllegalArgumentException("Javadoc requires a mapping in enigma!"); | 273 | throw new IllegalArgumentException("Javadoc requires a mapping in enigma!"); |
| 253 | } | 274 | } |
| 275 | |||
| 254 | mapping.addJavadocLine(unescape(javadoc)); | 276 | mapping.addJavadocLine(unescape(javadoc)); |
| 255 | } | 277 | } |
| 256 | 278 | ||
| 257 | |||
| 258 | |||
| 259 | private MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(MappingPair<? extends Entry, RawEntryMapping> parent, String[] tokens, boolean escapeNames) { | 279 | private MappingPair<LocalVariableEntry, RawEntryMapping> parseArgument(MappingPair<? extends Entry, RawEntryMapping> parent, String[] tokens, boolean escapeNames) { |
| 260 | MethodEntry ownerMethod = (MethodEntry) parent.getEntry(); | 280 | MethodEntry ownerMethod = (MethodEntry) parent.getEntry(); |
| 261 | int variableIndex = Integer.parseInt(tokens[1]); | 281 | int variableIndex = Integer.parseInt(tokens[1]); |
| @@ -263,8 +283,11 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 263 | // tokens[2] is the useless obf name | 283 | // tokens[2] is the useless obf name |
| 264 | 284 | ||
| 265 | LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null); | 285 | LocalVariableEntry obfuscatedEntry = new LocalVariableEntry(ownerMethod, variableIndex, "", true, null); |
| 266 | if (tokens.length <= 3) | 286 | |
| 287 | if (tokens.length <= 3) { | ||
| 267 | return new MappingPair<>(obfuscatedEntry); | 288 | return new MappingPair<>(obfuscatedEntry); |
| 289 | } | ||
| 290 | |||
| 268 | String mapping = unescapeOpt(tokens[3], escapeNames); | 291 | String mapping = unescapeOpt(tokens[3], escapeNames); |
| 269 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); | 292 | return new MappingPair<>(obfuscatedEntry, new RawEntryMapping(mapping)); |
| 270 | } | 293 | } |
| @@ -279,7 +302,10 @@ public final class TinyV2Reader implements MappingsReader { | |||
| 279 | private static String unescape(String str) { | 302 | private static String unescape(String str) { |
| 280 | // copied from matcher, lazy! | 303 | // copied from matcher, lazy! |
| 281 | int pos = str.indexOf('\\'); | 304 | int pos = str.indexOf('\\'); |
| 282 | if (pos < 0) return str; | 305 | |
| 306 | if (pos < 0) { | ||
| 307 | return str; | ||
| 308 | } | ||
| 283 | 309 | ||
| 284 | StringBuilder ret = new StringBuilder(str.length() - 1); | 310 | StringBuilder ret = new StringBuilder(str.length() - 1); |
| 285 | int start = 0; | 311 | int start = 0; |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java index c4005688..959d2d8f 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/serde/tinyv2/TinyV2Writer.java | |||
| @@ -1,13 +1,23 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.tinyv2; | 1 | package cuchaz.enigma.translation.mapping.serde.tinyv2; |
| 2 | 2 | ||
| 3 | import java.io.IOException; | ||
| 4 | import java.io.PrintWriter; | ||
| 5 | import java.nio.file.Files; | ||
| 6 | import java.nio.file.Path; | ||
| 7 | import java.util.Deque; | ||
| 8 | import java.util.LinkedList; | ||
| 9 | import java.util.List; | ||
| 10 | import java.util.stream.StreamSupport; | ||
| 11 | |||
| 3 | import com.google.common.base.Strings; | 12 | import com.google.common.base.Strings; |
| 13 | |||
| 4 | import cuchaz.enigma.ProgressListener; | 14 | import cuchaz.enigma.ProgressListener; |
| 5 | import cuchaz.enigma.translation.mapping.EntryMap; | 15 | import cuchaz.enigma.translation.mapping.EntryMap; |
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | 16 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 7 | import cuchaz.enigma.translation.mapping.MappingDelta; | 17 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 8 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 9 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; | 18 | import cuchaz.enigma.translation.mapping.serde.LfPrintWriter; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; | 19 | import cuchaz.enigma.translation.mapping.serde.MappingHelper; |
| 20 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | ||
| 11 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; | 21 | import cuchaz.enigma.translation.mapping.serde.MappingsWriter; |
| 12 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 22 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 13 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; | 23 | import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; |
| @@ -17,17 +27,7 @@ import cuchaz.enigma.translation.representation.entry.FieldEntry; | |||
| 17 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; | 27 | import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 28 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | 29 | ||
| 20 | import java.io.IOException; | ||
| 21 | import java.io.PrintWriter; | ||
| 22 | import java.nio.file.Files; | ||
| 23 | import java.nio.file.Path; | ||
| 24 | import java.util.Deque; | ||
| 25 | import java.util.LinkedList; | ||
| 26 | import java.util.List; | ||
| 27 | import java.util.stream.StreamSupport; | ||
| 28 | |||
| 29 | public final class TinyV2Writer implements MappingsWriter { | 30 | public final class TinyV2Writer implements MappingsWriter { |
| 30 | |||
| 31 | private static final String MINOR_VERSION = "0"; | 31 | private static final String MINOR_VERSION = "0"; |
| 32 | private final String obfHeader; | 32 | private final String obfHeader; |
| 33 | private final String deobfHeader; | 33 | private final String deobfHeader; |
| @@ -60,13 +60,16 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 60 | String fullName = classEntry.getFullName(); | 60 | String fullName = classEntry.getFullName(); |
| 61 | writer.print(fullName); | 61 | writer.print(fullName); |
| 62 | Deque<String> parts = new LinkedList<>(); | 62 | Deque<String> parts = new LinkedList<>(); |
| 63 | |||
| 63 | do { | 64 | do { |
| 64 | EntryMapping mapping = tree.get(classEntry); | 65 | EntryMapping mapping = tree.get(classEntry); |
| 66 | |||
| 65 | if (mapping != null && mapping.targetName() != null) { | 67 | if (mapping != null && mapping.targetName() != null) { |
| 66 | parts.addFirst(mapping.targetName()); | 68 | parts.addFirst(mapping.targetName()); |
| 67 | } else { | 69 | } else { |
| 68 | parts.addFirst(classEntry.getName()); | 70 | parts.addFirst(classEntry.getName()); |
| 69 | } | 71 | } |
| 72 | |||
| 70 | classEntry = classEntry.getOuterClass(); | 73 | classEntry = classEntry.getOuterClass(); |
| 71 | } while (classEntry != null); | 74 | } while (classEntry != null); |
| 72 | 75 | ||
| @@ -82,6 +85,7 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 82 | 85 | ||
| 83 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { | 86 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { |
| 84 | Entry<?> entry = child.getEntry(); | 87 | Entry<?> entry = child.getEntry(); |
| 88 | |||
| 85 | if (entry instanceof FieldEntry) { | 89 | if (entry instanceof FieldEntry) { |
| 86 | writeField(writer, child); | 90 | writeField(writer, child); |
| 87 | } else if (entry instanceof MethodEntry) { | 91 | } else if (entry instanceof MethodEntry) { |
| @@ -113,16 +117,19 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 113 | 117 | ||
| 114 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { | 118 | for (EntryTreeNode<EntryMapping> child : node.getChildNodes()) { |
| 115 | Entry<?> entry = child.getEntry(); | 119 | Entry<?> entry = child.getEntry(); |
| 120 | |||
| 116 | if (entry instanceof LocalVariableEntry) { | 121 | if (entry instanceof LocalVariableEntry) { |
| 117 | writeParameter(writer, child); | 122 | writeParameter(writer, child); |
| 118 | } | 123 | } |
| 124 | |||
| 119 | // TODO write actual local variables | 125 | // TODO write actual local variables |
| 120 | } | 126 | } |
| 121 | } | 127 | } |
| 122 | 128 | ||
| 123 | private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) { | 129 | private void writeField(PrintWriter writer, EntryTreeNode<EntryMapping> node) { |
| 124 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) | 130 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) { |
| 125 | return; // Shortcut | 131 | return; // Shortcut |
| 132 | } | ||
| 126 | 133 | ||
| 127 | writer.print(indent(1)); | 134 | writer.print(indent(1)); |
| 128 | writer.print("f\t"); | 135 | writer.print("f\t"); |
| @@ -146,8 +153,9 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 146 | } | 153 | } |
| 147 | 154 | ||
| 148 | private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) { | 155 | private void writeParameter(PrintWriter writer, EntryTreeNode<EntryMapping> node) { |
| 149 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) | 156 | if (node.getValue() == null || node.getValue().equals(EntryMapping.DEFAULT)) { |
| 150 | return; // Shortcut | 157 | return; // Shortcut |
| 158 | } | ||
| 151 | 159 | ||
| 152 | writer.print(indent(2)); | 160 | writer.print(indent(2)); |
| 153 | writer.print("p\t"); | 161 | writer.print("p\t"); |
| @@ -156,6 +164,7 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 156 | writer.print(node.getEntry().getName()); | 164 | writer.print(node.getEntry().getName()); |
| 157 | writer.print("\t"); | 165 | writer.print("\t"); |
| 158 | EntryMapping mapping = node.getValue(); | 166 | EntryMapping mapping = node.getValue(); |
| 167 | |||
| 159 | if (mapping == null || mapping.targetName() == null) { | 168 | if (mapping == null || mapping.targetName() == null) { |
| 160 | writer.println(); // todo ??? | 169 | writer.println(); // todo ??? |
| 161 | } else { | 170 | } else { |
| @@ -177,5 +186,4 @@ public final class TinyV2Writer implements MappingsWriter { | |||
| 177 | private String indent(int level) { | 186 | private String indent(int level) { |
| 178 | return Strings.repeat("\t", level); | 187 | return Strings.repeat("\t", level); |
| 179 | } | 188 | } |
| 180 | |||
| 181 | } | 189 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java index 255fa5fb..b943cc84 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/DeltaTrackingTree.java | |||
| @@ -1,5 +1,11 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import java.util.Collection; | ||
| 4 | import java.util.Iterator; | ||
| 5 | import java.util.stream.Stream; | ||
| 6 | |||
| 7 | import javax.annotation.Nullable; | ||
| 8 | |||
| 3 | import cuchaz.enigma.translation.Translator; | 9 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMap; | 10 | import cuchaz.enigma.translation.mapping.EntryMap; |
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 11 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| @@ -7,11 +13,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver; | |||
| 7 | import cuchaz.enigma.translation.mapping.MappingDelta; | 13 | import cuchaz.enigma.translation.mapping.MappingDelta; |
| 8 | import cuchaz.enigma.translation.representation.entry.Entry; | 14 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 9 | 15 | ||
| 10 | import javax.annotation.Nullable; | ||
| 11 | import java.util.Collection; | ||
| 12 | import java.util.Iterator; | ||
| 13 | import java.util.stream.Stream; | ||
| 14 | |||
| 15 | public class DeltaTrackingTree<T> implements EntryTree<T> { | 16 | public class DeltaTrackingTree<T> implements EntryTree<T> { |
| 16 | private final EntryTree<T> delegate; | 17 | private final EntryTree<T> delegate; |
| 17 | 18 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java index eb26ea99..254b3318 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/EntryTreeNode.java | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 4 | |||
| 5 | import javax.annotation.Nullable; | ||
| 6 | import java.util.ArrayList; | 3 | import java.util.ArrayList; |
| 7 | import java.util.Collection; | 4 | import java.util.Collection; |
| 8 | import java.util.List; | 5 | import java.util.List; |
| 9 | 6 | ||
| 7 | import javax.annotation.Nullable; | ||
| 8 | |||
| 9 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 10 | |||
| 10 | public interface EntryTreeNode<T> { | 11 | public interface EntryTreeNode<T> { |
| 11 | @Nullable | 12 | @Nullable |
| 12 | T getValue(); | 13 | T getValue(); |
| @@ -22,16 +23,16 @@ public interface EntryTreeNode<T> { | |||
| 22 | default Collection<? extends EntryTreeNode<T>> getNodesRecursively() { | 23 | default Collection<? extends EntryTreeNode<T>> getNodesRecursively() { |
| 23 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); | 24 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); |
| 24 | nodes.add(this); | 25 | nodes.add(this); |
| 26 | |||
| 25 | for (EntryTreeNode<T> node : getChildNodes()) { | 27 | for (EntryTreeNode<T> node : getChildNodes()) { |
| 26 | nodes.addAll(node.getNodesRecursively()); | 28 | nodes.addAll(node.getNodesRecursively()); |
| 27 | } | 29 | } |
| 30 | |||
| 28 | return nodes; | 31 | return nodes; |
| 29 | } | 32 | } |
| 30 | 33 | ||
| 31 | default List<? extends Entry<?>> getChildrenRecursively() { | 34 | default List<? extends Entry<?>> getChildrenRecursively() { |
| 32 | return getNodesRecursively().stream() | 35 | return getNodesRecursively().stream().map(EntryTreeNode::getEntry).toList(); |
| 33 | .map(EntryTreeNode::getEntry) | ||
| 34 | .toList(); | ||
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | default boolean hasValue() { | 38 | default boolean hasValue() { |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java index 0992d342..2902373d 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashEntryTree.java | |||
| @@ -1,18 +1,27 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import java.util.ArrayList; | ||
| 4 | import java.util.Collection; | ||
| 5 | import java.util.Collections; | ||
| 6 | import java.util.HashMap; | ||
| 7 | import java.util.HashSet; | ||
| 8 | import java.util.Iterator; | ||
| 9 | import java.util.List; | ||
| 10 | import java.util.Map; | ||
| 11 | import java.util.Set; | ||
| 12 | import java.util.function.Function; | ||
| 13 | import java.util.stream.Stream; | ||
| 14 | import java.util.stream.StreamSupport; | ||
| 15 | |||
| 16 | import javax.annotation.Nonnull; | ||
| 17 | import javax.annotation.Nullable; | ||
| 18 | |||
| 3 | import cuchaz.enigma.translation.Translator; | 19 | import cuchaz.enigma.translation.Translator; |
| 4 | import cuchaz.enigma.translation.mapping.EntryMap; | 20 | import cuchaz.enigma.translation.mapping.EntryMap; |
| 5 | import cuchaz.enigma.translation.mapping.EntryMapping; | 21 | import cuchaz.enigma.translation.mapping.EntryMapping; |
| 6 | import cuchaz.enigma.translation.mapping.EntryResolver; | 22 | import cuchaz.enigma.translation.mapping.EntryResolver; |
| 7 | import cuchaz.enigma.translation.representation.entry.Entry; | 23 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 8 | 24 | ||
| 9 | import javax.annotation.Nonnull; | ||
| 10 | import javax.annotation.Nullable; | ||
| 11 | import java.util.*; | ||
| 12 | import java.util.function.Function; | ||
| 13 | import java.util.stream.Stream; | ||
| 14 | import java.util.stream.StreamSupport; | ||
| 15 | |||
| 16 | public class HashEntryTree<T> implements EntryTree<T> { | 25 | public class HashEntryTree<T> implements EntryTree<T> { |
| 17 | private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); | 26 | private final Map<Entry<?>, HashTreeNode<T>> root = new HashMap<>(); |
| 18 | 27 | ||
| @@ -29,6 +38,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 29 | public void insert(Entry<?> entry, T value) { | 38 | public void insert(Entry<?> entry, T value) { |
| 30 | List<HashTreeNode<T>> path = computePath(entry, true); | 39 | List<HashTreeNode<T>> path = computePath(entry, true); |
| 31 | path.get(path.size() - 1).putValue(value); | 40 | path.get(path.size() - 1).putValue(value); |
| 41 | |||
| 32 | if (value == null) { | 42 | if (value == null) { |
| 33 | removeDeadAlong(path); | 43 | removeDeadAlong(path); |
| 34 | } | 44 | } |
| @@ -38,6 +48,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 38 | @Nullable | 48 | @Nullable |
| 39 | public T remove(Entry<?> entry) { | 49 | public T remove(Entry<?> entry) { |
| 40 | List<HashTreeNode<T>> path = computePath(entry, false); | 50 | List<HashTreeNode<T>> path = computePath(entry, false); |
| 51 | |||
| 41 | if (path.isEmpty()) { | 52 | if (path.isEmpty()) { |
| 42 | return null; | 53 | return null; |
| 43 | } | 54 | } |
| @@ -53,9 +64,11 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 53 | @Nullable | 64 | @Nullable |
| 54 | public T get(Entry<?> entry) { | 65 | public T get(Entry<?> entry) { |
| 55 | HashTreeNode<T> node = findNode(entry); | 66 | HashTreeNode<T> node = findNode(entry); |
| 67 | |||
| 56 | if (node == null) { | 68 | if (node == null) { |
| 57 | return null; | 69 | return null; |
| 58 | } | 70 | } |
| 71 | |||
| 59 | return node.getValue(); | 72 | return node.getValue(); |
| 60 | } | 73 | } |
| 61 | 74 | ||
| @@ -67,18 +80,22 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 67 | @Override | 80 | @Override |
| 68 | public Collection<Entry<?>> getChildren(Entry<?> entry) { | 81 | public Collection<Entry<?>> getChildren(Entry<?> entry) { |
| 69 | HashTreeNode<T> leaf = findNode(entry); | 82 | HashTreeNode<T> leaf = findNode(entry); |
| 83 | |||
| 70 | if (leaf == null) { | 84 | if (leaf == null) { |
| 71 | return Collections.emptyList(); | 85 | return Collections.emptyList(); |
| 72 | } | 86 | } |
| 87 | |||
| 73 | return leaf.getChildren(); | 88 | return leaf.getChildren(); |
| 74 | } | 89 | } |
| 75 | 90 | ||
| 76 | @Override | 91 | @Override |
| 77 | public Collection<Entry<?>> getSiblings(Entry<?> entry) { | 92 | public Collection<Entry<?>> getSiblings(Entry<?> entry) { |
| 78 | Entry<?> parent = entry.getParent(); | 93 | Entry<?> parent = entry.getParent(); |
| 94 | |||
| 79 | if (parent == null) { | 95 | if (parent == null) { |
| 80 | return getSiblings(entry, root.keySet()); | 96 | return getSiblings(entry, root.keySet()); |
| 81 | } | 97 | } |
| 98 | |||
| 82 | return getSiblings(entry, getChildren(parent)); | 99 | return getSiblings(entry, getChildren(parent)); |
| 83 | } | 100 | } |
| 84 | 101 | ||
| @@ -92,15 +109,18 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 92 | @Nullable | 109 | @Nullable |
| 93 | public HashTreeNode<T> findNode(Entry<?> target) { | 110 | public HashTreeNode<T> findNode(Entry<?> target) { |
| 94 | List<Entry<?>> parentChain = target.getAncestry(); | 111 | List<Entry<?>> parentChain = target.getAncestry(); |
| 112 | |||
| 95 | if (parentChain.isEmpty()) { | 113 | if (parentChain.isEmpty()) { |
| 96 | return null; | 114 | return null; |
| 97 | } | 115 | } |
| 98 | 116 | ||
| 99 | HashTreeNode<T> node = root.get(parentChain.get(0)); | 117 | HashTreeNode<T> node = root.get(parentChain.get(0)); |
| 118 | |||
| 100 | for (int i = 1; i < parentChain.size(); i++) { | 119 | for (int i = 1; i < parentChain.size(); i++) { |
| 101 | if (node == null) { | 120 | if (node == null) { |
| 102 | return null; | 121 | return null; |
| 103 | } | 122 | } |
| 123 | |||
| 104 | node = node.getChild(parentChain.get(i)); | 124 | node = node.getChild(parentChain.get(i)); |
| 105 | } | 125 | } |
| 106 | 126 | ||
| @@ -109,6 +129,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 109 | 129 | ||
| 110 | private List<HashTreeNode<T>> computePath(Entry<?> target, boolean make) { | 130 | private List<HashTreeNode<T>> computePath(Entry<?> target, boolean make) { |
| 111 | List<Entry<?>> ancestry = target.getAncestry(); | 131 | List<Entry<?>> ancestry = target.getAncestry(); |
| 132 | |||
| 112 | if (ancestry.isEmpty()) { | 133 | if (ancestry.isEmpty()) { |
| 113 | return Collections.emptyList(); | 134 | return Collections.emptyList(); |
| 114 | } | 135 | } |
| @@ -117,6 +138,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 117 | 138 | ||
| 118 | Entry<?> rootEntry = ancestry.get(0); | 139 | Entry<?> rootEntry = ancestry.get(0); |
| 119 | HashTreeNode<T> node = make ? root.computeIfAbsent(rootEntry, HashTreeNode::new) : root.get(rootEntry); | 140 | HashTreeNode<T> node = make ? root.computeIfAbsent(rootEntry, HashTreeNode::new) : root.get(rootEntry); |
| 141 | |||
| 120 | if (node == null) { | 142 | if (node == null) { |
| 121 | return Collections.emptyList(); | 143 | return Collections.emptyList(); |
| 122 | } | 144 | } |
| @@ -126,6 +148,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 126 | for (int i = 1; i < ancestry.size(); i++) { | 148 | for (int i = 1; i < ancestry.size(); i++) { |
| 127 | Entry<?> ancestor = ancestry.get(i); | 149 | Entry<?> ancestor = ancestry.get(i); |
| 128 | node = make ? node.computeChild(ancestor) : node.getChild(ancestor); | 150 | node = make ? node.computeChild(ancestor) : node.getChild(ancestor); |
| 151 | |||
| 129 | if (node == null) { | 152 | if (node == null) { |
| 130 | return Collections.emptyList(); | 153 | return Collections.emptyList(); |
| 131 | } | 154 | } |
| @@ -139,6 +162,7 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 139 | private void removeDeadAlong(List<HashTreeNode<T>> path) { | 162 | private void removeDeadAlong(List<HashTreeNode<T>> path) { |
| 140 | for (int i = path.size() - 1; i >= 0; i--) { | 163 | for (int i = path.size() - 1; i >= 0; i--) { |
| 141 | HashTreeNode<T> node = path.get(i); | 164 | HashTreeNode<T> node = path.get(i); |
| 165 | |||
| 142 | if (node.isEmpty()) { | 166 | if (node.isEmpty()) { |
| 143 | if (i > 0) { | 167 | if (i > 0) { |
| 144 | HashTreeNode<T> parentNode = path.get(i - 1); | 168 | HashTreeNode<T> parentNode = path.get(i - 1); |
| @@ -156,17 +180,17 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 156 | @Nonnull | 180 | @Nonnull |
| 157 | public Iterator<EntryTreeNode<T>> iterator() { | 181 | public Iterator<EntryTreeNode<T>> iterator() { |
| 158 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); | 182 | Collection<EntryTreeNode<T>> nodes = new ArrayList<>(); |
| 183 | |||
| 159 | for (EntryTreeNode<T> node : root.values()) { | 184 | for (EntryTreeNode<T> node : root.values()) { |
| 160 | nodes.addAll(node.getNodesRecursively()); | 185 | nodes.addAll(node.getNodesRecursively()); |
| 161 | } | 186 | } |
| 187 | |||
| 162 | return nodes.iterator(); | 188 | return nodes.iterator(); |
| 163 | } | 189 | } |
| 164 | 190 | ||
| 165 | @Override | 191 | @Override |
| 166 | public Stream<Entry<?>> getAllEntries() { | 192 | public Stream<Entry<?>> getAllEntries() { |
| 167 | return StreamSupport.stream(spliterator(), false) | 193 | return StreamSupport.stream(spliterator(), false).filter(EntryTreeNode::hasValue).map(EntryTreeNode::getEntry); |
| 168 | .filter(EntryTreeNode::hasValue) | ||
| 169 | .map(EntryTreeNode::getEntry); | ||
| 170 | } | 194 | } |
| 171 | 195 | ||
| 172 | @Override | 196 | @Override |
| @@ -182,9 +206,11 @@ public class HashEntryTree<T> implements EntryTree<T> { | |||
| 182 | @Override | 206 | @Override |
| 183 | public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 207 | public HashEntryTree<T> translate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 184 | HashEntryTree<T> translatedTree = new HashEntryTree<>(); | 208 | HashEntryTree<T> translatedTree = new HashEntryTree<>(); |
| 209 | |||
| 185 | for (EntryTreeNode<T> node : this) { | 210 | for (EntryTreeNode<T> node : this) { |
| 186 | translatedTree.insert(translator.translate(node.getEntry()), node.getValue()); | 211 | translatedTree.insert(translator.translate(node.getEntry()), node.getValue()); |
| 187 | } | 212 | } |
| 213 | |||
| 188 | return translatedTree; | 214 | return translatedTree; |
| 189 | } | 215 | } |
| 190 | } | 216 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java index 0a990bd5..3ddaf81f 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/mapping/tree/HashTreeNode.java | |||
| @@ -1,14 +1,15 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.tree; | 1 | package cuchaz.enigma.translation.mapping.tree; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 4 | |||
| 5 | import javax.annotation.Nonnull; | ||
| 6 | import javax.annotation.Nullable; | ||
| 7 | import java.util.Collection; | 3 | import java.util.Collection; |
| 8 | import java.util.HashMap; | 4 | import java.util.HashMap; |
| 9 | import java.util.Iterator; | 5 | import java.util.Iterator; |
| 10 | import java.util.Map; | 6 | import java.util.Map; |
| 11 | 7 | ||
| 8 | import javax.annotation.Nonnull; | ||
| 9 | import javax.annotation.Nullable; | ||
| 10 | |||
| 11 | import cuchaz.enigma.translation.representation.entry.Entry; | ||
| 12 | |||
| 12 | public class HashTreeNode<T> implements EntryTreeNode<T>, Iterable<HashTreeNode<T>> { | 13 | public class HashTreeNode<T> implements EntryTreeNode<T>, Iterable<HashTreeNode<T>> { |
| 13 | private final Entry<?> entry; | 14 | private final Entry<?> entry; |
| 14 | private final Map<Entry<?>, HashTreeNode<T>> children = new HashMap<>(); | 15 | private final Map<Entry<?>, HashTreeNode<T>> children = new HashMap<>(); |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java index e8480a26..24204f89 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/AccessFlags.java | |||
| @@ -1,9 +1,10 @@ | |||
| 1 | package cuchaz.enigma.translation.representation; | 1 | package cuchaz.enigma.translation.representation; |
| 2 | 2 | ||
| 3 | import cuchaz.enigma.analysis.Access; | 3 | import java.lang.reflect.Modifier; |
| 4 | |||
| 4 | import org.objectweb.asm.Opcodes; | 5 | import org.objectweb.asm.Opcodes; |
| 5 | 6 | ||
| 6 | import java.lang.reflect.Modifier; | 7 | import cuchaz.enigma.analysis.Access; |
| 7 | 8 | ||
| 8 | public class AccessFlags { | 9 | public class AccessFlags { |
| 9 | public static final AccessFlags PRIVATE = new AccessFlags(Opcodes.ACC_PRIVATE); | 10 | public static final AccessFlags PRIVATE = new AccessFlags(Opcodes.ACC_PRIVATE); |
| @@ -110,15 +111,19 @@ public class AccessFlags { | |||
| 110 | @Override | 111 | @Override |
| 111 | public String toString() { | 112 | public String toString() { |
| 112 | StringBuilder builder = new StringBuilder(Access.get(this).toString().toLowerCase()); | 113 | StringBuilder builder = new StringBuilder(Access.get(this).toString().toLowerCase()); |
| 114 | |||
| 113 | if (isStatic()) { | 115 | if (isStatic()) { |
| 114 | builder.append(" static"); | 116 | builder.append(" static"); |
| 115 | } | 117 | } |
| 118 | |||
| 116 | if (isSynthetic()) { | 119 | if (isSynthetic()) { |
| 117 | builder.append(" synthetic"); | 120 | builder.append(" synthetic"); |
| 118 | } | 121 | } |
| 122 | |||
| 119 | if (isBridge()) { | 123 | if (isBridge()) { |
| 120 | builder.append(" bridge"); | 124 | builder.append(" bridge"); |
| 121 | } | 125 | } |
| 126 | |||
| 122 | return builder.toString(); | 127 | return builder.toString(); |
| 123 | } | 128 | } |
| 124 | } | 129 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java index 13c7cd48..0854699d 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/Lambda.java | |||
| @@ -34,25 +34,20 @@ public class Lambda implements Translatable { | |||
| 34 | MethodEntry samMethod = new MethodEntry(getInterface(), invokedName, samMethodType); | 34 | MethodEntry samMethod = new MethodEntry(getInterface(), invokedName, samMethodType); |
| 35 | EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod); | 35 | EntryMapping samMethodMapping = resolveMapping(resolver, mappings, samMethod); |
| 36 | 36 | ||
| 37 | return TranslateResult.of( | 37 | return TranslateResult.of(samMethodMapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, |
| 38 | samMethodMapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | 38 | new Lambda(samMethodMapping.targetName() != null ? samMethodMapping.targetName() : invokedName, invokedType.extendedTranslate(translator, resolver, mappings).getValue(), samMethodType.extendedTranslate(translator, resolver, mappings).getValue(), |
| 39 | new Lambda( | 39 | implMethod.extendedTranslate(translator, resolver, mappings).getValue(), instantiatedMethodType.extendedTranslate(translator, resolver, mappings).getValue())); |
| 40 | samMethodMapping.targetName() != null ? samMethodMapping.targetName() : invokedName, | ||
| 41 | invokedType.extendedTranslate(translator, resolver, mappings).getValue(), | ||
| 42 | samMethodType.extendedTranslate(translator, resolver, mappings).getValue(), | ||
| 43 | implMethod.extendedTranslate(translator, resolver, mappings).getValue(), | ||
| 44 | instantiatedMethodType.extendedTranslate(translator, resolver, mappings).getValue() | ||
| 45 | ) | ||
| 46 | ); | ||
| 47 | } | 40 | } |
| 48 | 41 | ||
| 49 | private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings, MethodEntry methodEntry) { | 42 | private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings, MethodEntry methodEntry) { |
| 50 | for (MethodEntry entry : resolver.resolveEntry(methodEntry, ResolutionStrategy.RESOLVE_ROOT)) { | 43 | for (MethodEntry entry : resolver.resolveEntry(methodEntry, ResolutionStrategy.RESOLVE_ROOT)) { |
| 51 | EntryMapping mapping = mappings.get(entry); | 44 | EntryMapping mapping = mappings.get(entry); |
| 45 | |||
| 52 | if (mapping != null) { | 46 | if (mapping != null) { |
| 53 | return mapping; | 47 | return mapping; |
| 54 | } | 48 | } |
| 55 | } | 49 | } |
| 50 | |||
| 56 | return EntryMapping.DEFAULT; | 51 | return EntryMapping.DEFAULT; |
| 57 | } | 52 | } |
| 58 | 53 | ||
| @@ -82,14 +77,16 @@ public class Lambda implements Translatable { | |||
| 82 | 77 | ||
| 83 | @Override | 78 | @Override |
| 84 | public boolean equals(Object o) { | 79 | public boolean equals(Object o) { |
| 85 | if (this == o) return true; | 80 | if (this == o) { |
| 86 | if (o == null || getClass() != o.getClass()) return false; | 81 | return true; |
| 82 | } | ||
| 83 | |||
| 84 | if (o == null || getClass() != o.getClass()) { | ||
| 85 | return false; | ||
| 86 | } | ||
| 87 | |||
| 87 | Lambda lambda = (Lambda) o; | 88 | Lambda lambda = (Lambda) o; |
| 88 | return Objects.equals(invokedName, lambda.invokedName) && | 89 | return Objects.equals(invokedName, lambda.invokedName) && Objects.equals(invokedType, lambda.invokedType) && Objects.equals(samMethodType, lambda.samMethodType) && Objects.equals(implMethod, lambda.implMethod) && Objects.equals(instantiatedMethodType, lambda.instantiatedMethodType); |
| 89 | Objects.equals(invokedType, lambda.invokedType) && | ||
| 90 | Objects.equals(samMethodType, lambda.samMethodType) && | ||
| 91 | Objects.equals(implMethod, lambda.implMethod) && | ||
| 92 | Objects.equals(instantiatedMethodType, lambda.instantiatedMethodType); | ||
| 93 | } | 90 | } |
| 94 | 91 | ||
| 95 | @Override | 92 | @Override |
| @@ -99,12 +96,6 @@ public class Lambda implements Translatable { | |||
| 99 | 96 | ||
| 100 | @Override | 97 | @Override |
| 101 | public String toString() { | 98 | public String toString() { |
| 102 | return "Lambda{" + | 99 | return "Lambda{" + "invokedName='" + invokedName + '\'' + ", invokedType=" + invokedType + ", samMethodType=" + samMethodType + ", implMethod=" + implMethod + ", instantiatedMethodType=" + instantiatedMethodType + '}'; |
| 103 | "invokedName='" + invokedName + '\'' + | ||
| 104 | ", invokedType=" + invokedType + | ||
| 105 | ", samMethodType=" + samMethodType + | ||
| 106 | ", implMethod=" + implMethod + | ||
| 107 | ", instantiatedMethodType=" + instantiatedMethodType + | ||
| 108 | '}'; | ||
| 109 | } | 100 | } |
| 110 | } | 101 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java index 998c9442..571488cc 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/MethodDescriptor.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation; | 12 | package cuchaz.enigma.translation.representation; |
| 13 | 13 | ||
| @@ -27,7 +27,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver; | |||
| 27 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 27 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 28 | 28 | ||
| 29 | public class MethodDescriptor implements Translatable { | 29 | public class MethodDescriptor implements Translatable { |
| 30 | |||
| 31 | private List<TypeDescriptor> argumentDescs; | 30 | private List<TypeDescriptor> argumentDescs; |
| 32 | private TypeDescriptor returnDesc; | 31 | private TypeDescriptor returnDesc; |
| 33 | 32 | ||
| @@ -35,8 +34,10 @@ public class MethodDescriptor implements Translatable { | |||
| 35 | try { | 34 | try { |
| 36 | this.argumentDescs = Lists.newArrayList(); | 35 | this.argumentDescs = Lists.newArrayList(); |
| 37 | int i = 0; | 36 | int i = 0; |
| 37 | |||
| 38 | while (i < desc.length()) { | 38 | while (i < desc.length()) { |
| 39 | char c = desc.charAt(i); | 39 | char c = desc.charAt(i); |
| 40 | |||
| 40 | if (c == '(') { | 41 | if (c == '(') { |
| 41 | assert (this.argumentDescs.isEmpty()); | 42 | assert (this.argumentDescs.isEmpty()); |
| 42 | assert (this.returnDesc == null); | 43 | assert (this.returnDesc == null); |
| @@ -50,6 +51,7 @@ public class MethodDescriptor implements Translatable { | |||
| 50 | i += type.length(); | 51 | i += type.length(); |
| 51 | } | 52 | } |
| 52 | } | 53 | } |
| 54 | |||
| 53 | this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i))); | 55 | this.returnDesc = new TypeDescriptor(TypeDescriptor.parseFirst(desc.substring(i))); |
| 54 | } catch (Exception ex) { | 56 | } catch (Exception ex) { |
| 55 | throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex); | 57 | throw new IllegalArgumentException("Unable to parse method descriptor: " + desc, ex); |
| @@ -73,9 +75,11 @@ public class MethodDescriptor implements Translatable { | |||
| 73 | public String toString() { | 75 | public String toString() { |
| 74 | StringBuilder buf = new StringBuilder(); | 76 | StringBuilder buf = new StringBuilder(); |
| 75 | buf.append("("); | 77 | buf.append("("); |
| 78 | |||
| 76 | for (TypeDescriptor desc : this.argumentDescs) { | 79 | for (TypeDescriptor desc : this.argumentDescs) { |
| 77 | buf.append(desc); | 80 | buf.append(desc); |
| 78 | } | 81 | } |
| 82 | |||
| 79 | buf.append(")"); | 83 | buf.append(")"); |
| 80 | buf.append(this.returnDesc); | 84 | buf.append(this.returnDesc); |
| 81 | return buf.toString(); | 85 | return buf.toString(); |
| @@ -108,23 +112,28 @@ public class MethodDescriptor implements Translatable { | |||
| 108 | return true; | 112 | return true; |
| 109 | } | 113 | } |
| 110 | } | 114 | } |
| 115 | |||
| 111 | return false; | 116 | return false; |
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | public MethodDescriptor remap(Function<String, String> remapper) { | 119 | public MethodDescriptor remap(Function<String, String> remapper) { |
| 115 | List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size()); | 120 | List<TypeDescriptor> argumentDescs = new ArrayList<>(this.argumentDescs.size()); |
| 121 | |||
| 116 | for (TypeDescriptor desc : this.argumentDescs) { | 122 | for (TypeDescriptor desc : this.argumentDescs) { |
| 117 | argumentDescs.add(desc.remap(remapper)); | 123 | argumentDescs.add(desc.remap(remapper)); |
| 118 | } | 124 | } |
| 125 | |||
| 119 | return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper)); | 126 | return new MethodDescriptor(argumentDescs, returnDesc.remap(remapper)); |
| 120 | } | 127 | } |
| 121 | 128 | ||
| 122 | @Override | 129 | @Override |
| 123 | public TranslateResult<MethodDescriptor> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 130 | public TranslateResult<MethodDescriptor> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 124 | List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size()); | 131 | List<TypeDescriptor> translatedArguments = new ArrayList<>(argumentDescs.size()); |
| 132 | |||
| 125 | for (TypeDescriptor argument : argumentDescs) { | 133 | for (TypeDescriptor argument : argumentDescs) { |
| 126 | translatedArguments.add(translator.translate(argument)); | 134 | translatedArguments.add(translator.translate(argument)); |
| 127 | } | 135 | } |
| 136 | |||
| 128 | return TranslateResult.ungrouped(new MethodDescriptor(translatedArguments, translator.translate(returnDesc))); | 137 | return TranslateResult.ungrouped(new MethodDescriptor(translatedArguments, translator.translate(returnDesc))); |
| 129 | } | 138 | } |
| 130 | 139 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java index 33b9797d..a8278fc7 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/Signature.java | |||
| @@ -35,6 +35,7 @@ public class Signature implements Translatable { | |||
| 35 | if (signature != null && !signature.isEmpty()) { | 35 | if (signature != null && !signature.isEmpty()) { |
| 36 | return new Signature(signature, true); | 36 | return new Signature(signature, true); |
| 37 | } | 37 | } |
| 38 | |||
| 38 | return new Signature(null, true); | 39 | return new Signature(null, true); |
| 39 | } | 40 | } |
| 40 | 41 | ||
| @@ -42,6 +43,7 @@ public class Signature implements Translatable { | |||
| 42 | if (signature != null && !signature.isEmpty()) { | 43 | if (signature != null && !signature.isEmpty()) { |
| 43 | return new Signature(signature, false); | 44 | return new Signature(signature, false); |
| 44 | } | 45 | } |
| 46 | |||
| 45 | return new Signature(null, false); | 47 | return new Signature(null, false); |
| 46 | } | 48 | } |
| 47 | 49 | ||
| @@ -57,13 +59,16 @@ public class Signature implements Translatable { | |||
| 57 | if (signature == null) { | 59 | if (signature == null) { |
| 58 | return this; | 60 | return this; |
| 59 | } | 61 | } |
| 62 | |||
| 60 | SignatureWriter writer = new SignatureWriter(); | 63 | SignatureWriter writer = new SignatureWriter(); |
| 61 | SignatureVisitor visitor = new TranslationSignatureVisitor(remapper, writer); | 64 | SignatureVisitor visitor = new TranslationSignatureVisitor(remapper, writer); |
| 65 | |||
| 62 | if (isType) { | 66 | if (isType) { |
| 63 | new SignatureReader(signature).acceptType(visitor); | 67 | new SignatureReader(signature).acceptType(visitor); |
| 64 | } else { | 68 | } else { |
| 65 | new SignatureReader(signature).accept(visitor); | 69 | new SignatureReader(signature).accept(visitor); |
| 66 | } | 70 | } |
| 71 | |||
| 67 | return new Signature(writer.toString(), isType); | 72 | return new Signature(writer.toString(), isType); |
| 68 | } | 73 | } |
| 69 | 74 | ||
| @@ -71,16 +76,16 @@ public class Signature implements Translatable { | |||
| 71 | public boolean equals(Object obj) { | 76 | public boolean equals(Object obj) { |
| 72 | if (obj instanceof Signature) { | 77 | if (obj instanceof Signature) { |
| 73 | Signature other = (Signature) obj; | 78 | Signature other = (Signature) obj; |
| 74 | return (other.signature == null && signature == null || other.signature != null | 79 | return (other.signature == null && signature == null || other.signature != null && signature != null && other.signature.equals(signature)) && other.isType == this.isType; |
| 75 | && signature != null && other.signature.equals(signature)) | ||
| 76 | && other.isType == this.isType; | ||
| 77 | } | 80 | } |
| 81 | |||
| 78 | return false; | 82 | return false; |
| 79 | } | 83 | } |
| 80 | 84 | ||
| 81 | @Override | 85 | @Override |
| 82 | public int hashCode() { | 86 | public int hashCode() { |
| 83 | int hash = (isType ? 1 : 0) << 16; | 87 | int hash = (isType ? 1 : 0) << 16; |
| 88 | |||
| 84 | if (signature != null) { | 89 | if (signature != null) { |
| 85 | hash |= signature.hashCode(); | 90 | hash |= signature.hashCode(); |
| 86 | } | 91 | } |
| @@ -97,5 +102,4 @@ public class Signature implements Translatable { | |||
| 97 | public TranslateResult<Signature> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 102 | public TranslateResult<Signature> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 98 | return TranslateResult.ungrouped(this.remap(name -> translator.translate(new ClassEntry(name)).getFullName())); | 103 | return TranslateResult.ungrouped(this.remap(name -> translator.translate(new ClassEntry(name)).getFullName())); |
| 99 | } | 104 | } |
| 100 | |||
| 101 | } | 105 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java index 6a1b82f0..fd53522d 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/TypeDescriptor.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation; | 12 | package cuchaz.enigma.translation.representation; |
| 13 | 13 | ||
| @@ -26,7 +26,6 @@ import cuchaz.enigma.translation.mapping.EntryResolver; | |||
| 26 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 26 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 27 | 27 | ||
| 28 | public class TypeDescriptor implements Translatable { | 28 | public class TypeDescriptor implements Translatable { |
| 29 | |||
| 30 | protected final String desc; | 29 | protected final String desc; |
| 31 | 30 | ||
| 32 | public TypeDescriptor(String desc) { | 31 | public TypeDescriptor(String desc) { |
| @@ -42,7 +41,6 @@ public class TypeDescriptor implements Translatable { | |||
| 42 | } | 41 | } |
| 43 | 42 | ||
| 44 | public static String parseFirst(String in) { | 43 | public static String parseFirst(String in) { |
| 45 | |||
| 46 | if (in == null || in.length() <= 0) { | 44 | if (in == null || in.length() <= 0) { |
| 47 | throw new IllegalArgumentException("No desc to parse, input is empty!"); | 45 | throw new IllegalArgumentException("No desc to parse, input is empty!"); |
| 48 | } | 46 | } |
| @@ -58,6 +56,7 @@ public class TypeDescriptor implements Translatable { | |||
| 58 | 56 | ||
| 59 | // then check for primitives | 57 | // then check for primitives |
| 60 | Primitive primitive = Primitive.get(c); | 58 | Primitive primitive = Primitive.get(c); |
| 59 | |||
| 61 | if (primitive != null) { | 60 | if (primitive != null) { |
| 62 | return in.substring(0, 1); | 61 | return in.substring(0, 1); |
| 63 | } | 62 | } |
| @@ -74,6 +73,7 @@ public class TypeDescriptor implements Translatable { | |||
| 74 | 73 | ||
| 75 | // then check for arrays | 74 | // then check for arrays |
| 76 | int dim = countArrayDimension(in); | 75 | int dim = countArrayDimension(in); |
| 76 | |||
| 77 | if (dim > 0) { | 77 | if (dim > 0) { |
| 78 | String arrayType = TypeDescriptor.parseFirst(in.substring(dim)); | 78 | String arrayType = TypeDescriptor.parseFirst(in.substring(dim)); |
| 79 | return in.substring(0, dim + arrayType.length()); | 79 | return in.substring(0, dim + arrayType.length()); |
| @@ -84,8 +84,11 @@ public class TypeDescriptor implements Translatable { | |||
| 84 | 84 | ||
| 85 | private static int countArrayDimension(String in) { | 85 | private static int countArrayDimension(String in) { |
| 86 | int i = 0; | 86 | int i = 0; |
| 87 | while (i < in.length() && in.charAt(i) == '[') | 87 | |
| 88 | while (i < in.length() && in.charAt(i) == '[') { | ||
| 88 | i++; | 89 | i++; |
| 90 | } | ||
| 91 | |||
| 89 | return i; | 92 | return i; |
| 90 | } | 93 | } |
| 91 | 94 | ||
| @@ -94,6 +97,7 @@ public class TypeDescriptor implements Translatable { | |||
| 94 | // include the parameters too | 97 | // include the parameters too |
| 95 | StringBuilder buf = new StringBuilder(); | 98 | StringBuilder buf = new StringBuilder(); |
| 96 | int depth = 0; | 99 | int depth = 0; |
| 100 | |||
| 97 | for (int i = 0; i < in.length(); i++) { | 101 | for (int i = 0; i < in.length(); i++) { |
| 98 | char c = in.charAt(i); | 102 | char c = in.charAt(i); |
| 99 | buf.append(c); | 103 | buf.append(c); |
| @@ -106,6 +110,7 @@ public class TypeDescriptor implements Translatable { | |||
| 106 | return buf.toString(); | 110 | return buf.toString(); |
| 107 | } | 111 | } |
| 108 | } | 112 | } |
| 113 | |||
| 109 | return null; | 114 | return null; |
| 110 | } | 115 | } |
| 111 | 116 | ||
| @@ -130,6 +135,7 @@ public class TypeDescriptor implements Translatable { | |||
| 130 | if (!isPrimitive()) { | 135 | if (!isPrimitive()) { |
| 131 | throw new IllegalStateException("not a primitive"); | 136 | throw new IllegalStateException("not a primitive"); |
| 132 | } | 137 | } |
| 138 | |||
| 133 | return Primitive.get(this.desc.charAt(0)); | 139 | return Primitive.get(this.desc.charAt(0)); |
| 134 | } | 140 | } |
| 135 | 141 | ||
| @@ -142,13 +148,13 @@ public class TypeDescriptor implements Translatable { | |||
| 142 | String name = this.desc.substring(1, this.desc.length() - 1); | 148 | String name = this.desc.substring(1, this.desc.length() - 1); |
| 143 | 149 | ||
| 144 | int pos = name.indexOf('<'); | 150 | int pos = name.indexOf('<'); |
| 151 | |||
| 145 | if (pos >= 0) { | 152 | if (pos >= 0) { |
| 146 | // remove the parameters from the class name | 153 | // remove the parameters from the class name |
| 147 | name = name.substring(0, pos); | 154 | name = name.substring(0, pos); |
| 148 | } | 155 | } |
| 149 | 156 | ||
| 150 | return new ClassEntry(name); | 157 | return new ClassEntry(name); |
| 151 | |||
| 152 | } else if (isArray() && getArrayType().isType()) { | 158 | } else if (isArray() && getArrayType().isType()) { |
| 153 | return getArrayType().getTypeEntry(); | 159 | return getArrayType().getTypeEntry(); |
| 154 | } else { | 160 | } else { |
| @@ -164,6 +170,7 @@ public class TypeDescriptor implements Translatable { | |||
| 164 | if (!isArray()) { | 170 | if (!isArray()) { |
| 165 | throw new IllegalStateException("not an array"); | 171 | throw new IllegalStateException("not an array"); |
| 166 | } | 172 | } |
| 173 | |||
| 167 | return countArrayDimension(this.desc); | 174 | return countArrayDimension(this.desc); |
| 168 | } | 175 | } |
| 169 | 176 | ||
| @@ -171,6 +178,7 @@ public class TypeDescriptor implements Translatable { | |||
| 171 | if (!isArray()) { | 178 | if (!isArray()) { |
| 172 | throw new IllegalStateException("not an array"); | 179 | throw new IllegalStateException("not an array"); |
| 173 | } | 180 | } |
| 181 | |||
| 174 | return new TypeDescriptor(this.desc.substring(getArrayDimension())); | 182 | return new TypeDescriptor(this.desc.substring(getArrayDimension())); |
| 175 | } | 183 | } |
| 176 | 184 | ||
| @@ -194,8 +202,10 @@ public class TypeDescriptor implements Translatable { | |||
| 194 | 202 | ||
| 195 | public TypeDescriptor remap(Function<String, String> remapper) { | 203 | public TypeDescriptor remap(Function<String, String> remapper) { |
| 196 | String desc = this.desc; | 204 | String desc = this.desc; |
| 205 | |||
| 197 | if (isType() || (isArray() && containsType())) { | 206 | if (isType() || (isArray() && containsType())) { |
| 198 | String replacedName = remapper.apply(this.getTypeEntry().getFullName()); | 207 | String replacedName = remapper.apply(this.getTypeEntry().getFullName()); |
| 208 | |||
| 199 | if (replacedName != null) { | 209 | if (replacedName != null) { |
| 200 | if (this.isType()) { | 210 | if (this.isType()) { |
| 201 | desc = "L" + replacedName + ";"; | 211 | desc = "L" + replacedName + ";"; |
| @@ -204,28 +214,31 @@ public class TypeDescriptor implements Translatable { | |||
| 204 | } | 214 | } |
| 205 | } | 215 | } |
| 206 | } | 216 | } |
| 217 | |||
| 207 | return new TypeDescriptor(desc); | 218 | return new TypeDescriptor(desc); |
| 208 | } | 219 | } |
| 209 | 220 | ||
| 210 | private static String getArrayPrefix(int dimension) { | 221 | private static String getArrayPrefix(int dimension) { |
| 211 | StringBuilder buf = new StringBuilder(); | 222 | StringBuilder buf = new StringBuilder(); |
| 223 | |||
| 212 | for (int i = 0; i < dimension; i++) { | 224 | for (int i = 0; i < dimension; i++) { |
| 213 | buf.append("["); | 225 | buf.append("["); |
| 214 | } | 226 | } |
| 227 | |||
| 215 | return buf.toString(); | 228 | return buf.toString(); |
| 216 | } | 229 | } |
| 217 | 230 | ||
| 218 | public int getSize() { | 231 | public int getSize() { |
| 219 | switch (desc.charAt(0)) { | 232 | switch (desc.charAt(0)) { |
| 220 | case 'J': | 233 | case 'J': |
| 221 | case 'D': | 234 | case 'D': |
| 222 | if (desc.length() == 1) { | 235 | if (desc.length() == 1) { |
| 223 | return 2; | 236 | return 2; |
| 224 | } else { | 237 | } else { |
| 225 | return 1; | ||
| 226 | } | ||
| 227 | default: | ||
| 228 | return 1; | 238 | return 1; |
| 239 | } | ||
| 240 | default: | ||
| 241 | return 1; | ||
| 229 | } | 242 | } |
| 230 | } | 243 | } |
| 231 | 244 | ||
| @@ -248,6 +261,7 @@ public class TypeDescriptor implements Translatable { | |||
| 248 | 261 | ||
| 249 | static { | 262 | static { |
| 250 | lookup = Maps.newTreeMap(); | 263 | lookup = Maps.newTreeMap(); |
| 264 | |||
| 251 | for (Primitive val : values()) { | 265 | for (Primitive val : values()) { |
| 252 | lookup.put(val.getCode(), val); | 266 | lookup.put(val.getCode(), val); |
| 253 | } | 267 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java index ab5a422f..cb2faf06 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassDefEntry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -39,8 +39,7 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> { | |||
| 39 | this(parent, className, signature, access, superClass, interfaces, null); | 39 | this(parent, className, signature, access, superClass, interfaces, null); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, | 42 | public ClassDefEntry(ClassEntry parent, String className, Signature signature, AccessFlags access, @Nullable ClassEntry superClass, ClassEntry[] interfaces, String javadocs) { |
| 43 | ClassEntry[] interfaces, String javadocs) { | ||
| 44 | super(parent, className, javadocs); | 43 | super(parent, className, javadocs); |
| 45 | Preconditions.checkNotNull(signature, "Class signature cannot be null"); | 44 | Preconditions.checkNotNull(signature, "Class signature cannot be null"); |
| 46 | Preconditions.checkNotNull(access, "Class access cannot be null"); | 45 | Preconditions.checkNotNull(access, "Class access cannot be null"); |
| @@ -87,10 +86,7 @@ public class ClassDefEntry extends ClassEntry implements DefEntry<ClassEntry> { | |||
| 87 | ClassEntry translatedSuper = translator.translate(superClass); | 86 | ClassEntry translatedSuper = translator.translate(superClass); |
| 88 | ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); | 87 | ClassEntry[] translatedInterfaces = Arrays.stream(interfaces).map(translator::translate).toArray(ClassEntry[]::new); |
| 89 | String docs = mapping.javadoc(); | 88 | String docs = mapping.javadoc(); |
| 90 | return TranslateResult.of( | 89 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs)); |
| 91 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 92 | new ClassDefEntry(parent, translatedName, translatedSignature, translatedAccess, translatedSuper, translatedInterfaces, docs) | ||
| 93 | ); | ||
| 94 | } | 90 | } |
| 95 | 91 | ||
| 96 | @Override | 92 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java index b0adb2c1..be5f0b38 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ClassEntry.java | |||
| @@ -1,16 +1,22 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| 14 | import java.util.List; | ||
| 15 | import java.util.Objects; | ||
| 16 | |||
| 17 | import javax.annotation.Nonnull; | ||
| 18 | import javax.annotation.Nullable; | ||
| 19 | |||
| 14 | import cuchaz.enigma.source.RenamableTokenType; | 20 | import cuchaz.enigma.source.RenamableTokenType; |
| 15 | import cuchaz.enigma.translation.TranslateResult; | 21 | import cuchaz.enigma.translation.TranslateResult; |
| 16 | import cuchaz.enigma.translation.Translator; | 22 | import cuchaz.enigma.translation.Translator; |
| @@ -19,11 +25,6 @@ import cuchaz.enigma.translation.mapping.IdentifierValidation; | |||
| 19 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 25 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 20 | import cuchaz.enigma.utils.validation.ValidationContext; | 26 | import cuchaz.enigma.utils.validation.ValidationContext; |
| 21 | 27 | ||
| 22 | import javax.annotation.Nonnull; | ||
| 23 | import javax.annotation.Nullable; | ||
| 24 | import java.util.List; | ||
| 25 | import java.util.Objects; | ||
| 26 | |||
| 27 | public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<ClassEntry> { | 28 | public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable<ClassEntry> { |
| 28 | private final String fullName; | 29 | private final String fullName; |
| 29 | 30 | ||
| @@ -37,6 +38,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 37 | 38 | ||
| 38 | public ClassEntry(@Nullable ClassEntry parent, String className, @Nullable String javadocs) { | 39 | public ClassEntry(@Nullable ClassEntry parent, String className, @Nullable String javadocs) { |
| 39 | super(parent, className, javadocs); | 40 | super(parent, className, javadocs); |
| 41 | |||
| 40 | if (parent != null) { | 42 | if (parent != null) { |
| 41 | fullName = parent.getFullName() + "$" + name; | 43 | fullName = parent.getFullName() + "$" + name; |
| 42 | } else { | 44 | } else { |
| @@ -61,9 +63,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 61 | @Override | 63 | @Override |
| 62 | public String getSimpleName() { | 64 | public String getSimpleName() { |
| 63 | int packagePos = name.lastIndexOf('/'); | 65 | int packagePos = name.lastIndexOf('/'); |
| 66 | |||
| 64 | if (packagePos > 0) { | 67 | if (packagePos > 0) { |
| 65 | return name.substring(packagePos + 1); | 68 | return name.substring(packagePos + 1); |
| 66 | } | 69 | } |
| 70 | |||
| 67 | return name; | 71 | return name; |
| 68 | } | 72 | } |
| 69 | 73 | ||
| @@ -77,6 +81,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 77 | if (this.isInnerClass()) { | 81 | if (this.isInnerClass()) { |
| 78 | return this.parent.getSimpleName() + "$" + this.name; | 82 | return this.parent.getSimpleName() + "$" + this.name; |
| 79 | } | 83 | } |
| 84 | |||
| 80 | return this.getSimpleName(); | 85 | return this.getSimpleName(); |
| 81 | } | 86 | } |
| 82 | 87 | ||
| @@ -89,10 +94,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 89 | 94 | ||
| 90 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 95 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 91 | String docs = mapping.javadoc(); | 96 | String docs = mapping.javadoc(); |
| 92 | return TranslateResult.of( | 97 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new ClassEntry(parent, translatedName, docs)); |
| 93 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 94 | new ClassEntry(parent, translatedName, docs) | ||
| 95 | ); | ||
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | @Override | 100 | @Override |
| @@ -160,12 +162,14 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 160 | if (parent == null) { | 162 | if (parent == null) { |
| 161 | return this; | 163 | return this; |
| 162 | } | 164 | } |
| 165 | |||
| 163 | return parent.getOutermostClass(); | 166 | return parent.getOutermostClass(); |
| 164 | } | 167 | } |
| 165 | 168 | ||
| 166 | public ClassEntry buildClassEntry(List<ClassEntry> classChain) { | 169 | public ClassEntry buildClassEntry(List<ClassEntry> classChain) { |
| 167 | assert (classChain.contains(this)); | 170 | assert (classChain.contains(this)); |
| 168 | StringBuilder buf = new StringBuilder(); | 171 | StringBuilder buf = new StringBuilder(); |
| 172 | |||
| 169 | for (ClassEntry chainEntry : classChain) { | 173 | for (ClassEntry chainEntry : classChain) { |
| 170 | if (buf.length() == 0) { | 174 | if (buf.length() == 0) { |
| 171 | buf.append(chainEntry.getFullName()); | 175 | buf.append(chainEntry.getFullName()); |
| @@ -178,6 +182,7 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 178 | break; | 182 | break; |
| 179 | } | 183 | } |
| 180 | } | 184 | } |
| 185 | |||
| 181 | return new ClassEntry(buf.toString()); | 186 | return new ClassEntry(buf.toString()); |
| 182 | } | 187 | } |
| 183 | 188 | ||
| @@ -188,9 +193,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 188 | 193 | ||
| 189 | public static String getParentPackage(String name) { | 194 | public static String getParentPackage(String name) { |
| 190 | int pos = name.lastIndexOf('/'); | 195 | int pos = name.lastIndexOf('/'); |
| 196 | |||
| 191 | if (pos > 0) { | 197 | if (pos > 0) { |
| 192 | return name.substring(0, pos); | 198 | return name.substring(0, pos); |
| 193 | } | 199 | } |
| 200 | |||
| 194 | return null; | 201 | return null; |
| 195 | } | 202 | } |
| 196 | 203 | ||
| @@ -215,9 +222,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 215 | } | 222 | } |
| 216 | 223 | ||
| 217 | int index = name.lastIndexOf('$'); | 224 | int index = name.lastIndexOf('$'); |
| 225 | |||
| 218 | if (index >= 0) { | 226 | if (index >= 0) { |
| 219 | return new ClassEntry(name.substring(0, index)); | 227 | return new ClassEntry(name.substring(0, index)); |
| 220 | } | 228 | } |
| 229 | |||
| 221 | return null; | 230 | return null; |
| 222 | } | 231 | } |
| 223 | 232 | ||
| @@ -227,18 +236,22 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 227 | } | 236 | } |
| 228 | 237 | ||
| 229 | int innerClassPos = name.lastIndexOf('$'); | 238 | int innerClassPos = name.lastIndexOf('$'); |
| 239 | |||
| 230 | if (innerClassPos > 0) { | 240 | if (innerClassPos > 0) { |
| 231 | return name.substring(innerClassPos + 1); | 241 | return name.substring(innerClassPos + 1); |
| 232 | } | 242 | } |
| 243 | |||
| 233 | return name; | 244 | return name; |
| 234 | } | 245 | } |
| 235 | 246 | ||
| 236 | @Override | 247 | @Override |
| 237 | public String getSourceRemapName() { | 248 | public String getSourceRemapName() { |
| 238 | ClassEntry outerClass = getOuterClass(); | 249 | ClassEntry outerClass = getOuterClass(); |
| 250 | |||
| 239 | if (outerClass != null) { | 251 | if (outerClass != null) { |
| 240 | return outerClass.getSourceRemapName() + "." + name; | 252 | return outerClass.getSourceRemapName() + "." + name; |
| 241 | } | 253 | } |
| 254 | |||
| 242 | return getSimpleName(); | 255 | return getSimpleName(); |
| 243 | } | 256 | } |
| 244 | 257 | ||
| @@ -246,9 +259,11 @@ public class ClassEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 246 | public int compareTo(ClassEntry entry) { | 259 | public int compareTo(ClassEntry entry) { |
| 247 | String fullName = getFullName(); | 260 | String fullName = getFullName(); |
| 248 | String otherFullName = entry.getFullName(); | 261 | String otherFullName = entry.getFullName(); |
| 262 | |||
| 249 | if (fullName.length() != otherFullName.length()) { | 263 | if (fullName.length() != otherFullName.length()) { |
| 250 | return fullName.length() - otherFullName.length(); | 264 | return fullName.length() - otherFullName.length(); |
| 251 | } | 265 | } |
| 266 | |||
| 252 | return fullName.compareTo(otherFullName); | 267 | return fullName.compareTo(otherFullName); |
| 253 | } | 268 | } |
| 254 | } | 269 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java index 956f32ca..9615ca8e 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/Entry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -111,34 +111,42 @@ public interface Entry<P extends Entry<?>> extends Translatable { | |||
| 111 | default ClassEntry getContainingClass() { | 111 | default ClassEntry getContainingClass() { |
| 112 | ClassEntry last = null; | 112 | ClassEntry last = null; |
| 113 | Entry<?> current = this; | 113 | Entry<?> current = this; |
| 114 | |||
| 114 | while (current != null) { | 115 | while (current != null) { |
| 115 | if (current instanceof ClassEntry) { | 116 | if (current instanceof ClassEntry) { |
| 116 | last = (ClassEntry) current; | 117 | last = (ClassEntry) current; |
| 117 | break; | 118 | break; |
| 118 | } | 119 | } |
| 120 | |||
| 119 | current = current.getParent(); | 121 | current = current.getParent(); |
| 120 | } | 122 | } |
| 123 | |||
| 121 | return Objects.requireNonNull(last, () -> String.format("%s has no containing class?", this)); | 124 | return Objects.requireNonNull(last, () -> String.format("%s has no containing class?", this)); |
| 122 | } | 125 | } |
| 123 | 126 | ||
| 124 | default ClassEntry getTopLevelClass() { | 127 | default ClassEntry getTopLevelClass() { |
| 125 | ClassEntry last = null; | 128 | ClassEntry last = null; |
| 126 | Entry<?> current = this; | 129 | Entry<?> current = this; |
| 130 | |||
| 127 | while (current != null) { | 131 | while (current != null) { |
| 128 | if (current instanceof ClassEntry) { | 132 | if (current instanceof ClassEntry) { |
| 129 | last = (ClassEntry) current; | 133 | last = (ClassEntry) current; |
| 130 | } | 134 | } |
| 135 | |||
| 131 | current = current.getParent(); | 136 | current = current.getParent(); |
| 132 | } | 137 | } |
| 138 | |||
| 133 | return Objects.requireNonNull(last, () -> String.format("%s has no top level class?", this)); | 139 | return Objects.requireNonNull(last, () -> String.format("%s has no top level class?", this)); |
| 134 | } | 140 | } |
| 135 | 141 | ||
| 136 | default List<Entry<?>> getAncestry() { | 142 | default List<Entry<?>> getAncestry() { |
| 137 | P parent = getParent(); | 143 | P parent = getParent(); |
| 138 | List<Entry<?>> entries = new ArrayList<>(); | 144 | List<Entry<?>> entries = new ArrayList<>(); |
| 145 | |||
| 139 | if (parent != null) { | 146 | if (parent != null) { |
| 140 | entries.addAll(parent.getAncestry()); | 147 | entries.addAll(parent.getAncestry()); |
| 141 | } | 148 | } |
| 149 | |||
| 142 | entries.add(this); | 150 | entries.add(this); |
| 143 | return entries; | 151 | return entries; |
| 144 | } | 152 | } |
| @@ -147,12 +155,15 @@ public interface Entry<P extends Entry<?>> extends Translatable { | |||
| 147 | @SuppressWarnings("unchecked") | 155 | @SuppressWarnings("unchecked") |
| 148 | default <E extends Entry<?>> E findAncestor(Class<E> type) { | 156 | default <E extends Entry<?>> E findAncestor(Class<E> type) { |
| 149 | List<Entry<?>> ancestry = getAncestry(); | 157 | List<Entry<?>> ancestry = getAncestry(); |
| 158 | |||
| 150 | for (int i = ancestry.size() - 1; i >= 0; i--) { | 159 | for (int i = ancestry.size() - 1; i >= 0; i--) { |
| 151 | Entry<?> ancestor = ancestry.get(i); | 160 | Entry<?> ancestor = ancestry.get(i); |
| 161 | |||
| 152 | if (type.isAssignableFrom(ancestor.getClass())) { | 162 | if (type.isAssignableFrom(ancestor.getClass())) { |
| 153 | return (E) ancestor; | 163 | return (E) ancestor; |
| 154 | } | 164 | } |
| 155 | } | 165 | } |
| 166 | |||
| 156 | return null; | 167 | return null; |
| 157 | } | 168 | } |
| 158 | 169 | ||
| @@ -167,6 +178,7 @@ public interface Entry<P extends Entry<?>> extends Translatable { | |||
| 167 | } | 178 | } |
| 168 | 179 | ||
| 169 | P parent = getParent(); | 180 | P parent = getParent(); |
| 181 | |||
| 170 | if (parent == null) { | 182 | if (parent == null) { |
| 171 | return this; | 183 | return this; |
| 172 | } | 184 | } |
| @@ -184,6 +196,7 @@ public interface Entry<P extends Entry<?>> extends Translatable { | |||
| 184 | if (parentType.equals(getParentType())) { | 196 | if (parentType.equals(getParentType())) { |
| 185 | return (Entry<C>) this; | 197 | return (Entry<C>) this; |
| 186 | } | 198 | } |
| 199 | |||
| 187 | return null; | 200 | return null; |
| 188 | } | 201 | } |
| 189 | } | 202 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java index 0efb6a99..492d72e7 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldDefEntry.java | |||
| @@ -1,16 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| 14 | import javax.annotation.Nonnull; | ||
| 15 | |||
| 14 | import com.google.common.base.Preconditions; | 16 | import com.google.common.base.Preconditions; |
| 15 | 17 | ||
| 16 | import cuchaz.enigma.source.RenamableTokenType; | 18 | import cuchaz.enigma.source.RenamableTokenType; |
| @@ -21,8 +23,6 @@ import cuchaz.enigma.translation.representation.AccessFlags; | |||
| 21 | import cuchaz.enigma.translation.representation.Signature; | 23 | import cuchaz.enigma.translation.representation.Signature; |
| 22 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 24 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 23 | 25 | ||
| 24 | import javax.annotation.Nonnull; | ||
| 25 | |||
| 26 | public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { | 26 | public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { |
| 27 | private final AccessFlags access; | 27 | private final AccessFlags access; |
| 28 | private final Signature signature; | 28 | private final Signature signature; |
| @@ -59,13 +59,9 @@ public class FieldDefEntry extends FieldEntry implements DefEntry<ClassEntry> { | |||
| 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); | 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); |
| 61 | String docs = mapping.javadoc(); | 61 | String docs = mapping.javadoc(); |
| 62 | return TranslateResult.of( | 62 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs)); |
| 63 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 64 | new FieldDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) | ||
| 65 | ); | ||
| 66 | } | 63 | } |
| 67 | 64 | ||
| 68 | |||
| 69 | @Override | 65 | @Override |
| 70 | public FieldDefEntry withName(String name) { | 66 | public FieldDefEntry withName(String name) { |
| 71 | return new FieldDefEntry(parent, name, desc, signature, access, javadocs); | 67 | return new FieldDefEntry(parent, name, desc, signature, access, javadocs); |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java index db940118..c1592a43 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/FieldEntry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -66,10 +66,7 @@ public class FieldEntry extends ParentedEntry<ClassEntry> implements Comparable< | |||
| 66 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { | 66 | protected TranslateResult<FieldEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 67 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 67 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 68 | String docs = mapping.javadoc(); | 68 | String docs = mapping.javadoc(); |
| 69 | return TranslateResult.of( | 69 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new FieldEntry(parent, translatedName, translator.translate(desc), docs)); |
| 70 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 71 | new FieldEntry(parent, translatedName, translator.translate(desc), docs) | ||
| 72 | ); | ||
| 73 | } | 70 | } |
| 74 | 71 | ||
| 75 | @Override | 72 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java index c151de4e..ac36a483 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableDefEntry.java | |||
| @@ -34,10 +34,7 @@ public class LocalVariableDefEntry extends LocalVariableEntry { | |||
| 34 | TypeDescriptor translatedDesc = translator.translate(desc); | 34 | TypeDescriptor translatedDesc = translator.translate(desc); |
| 35 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 35 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 36 | String javadoc = mapping.javadoc(); | 36 | String javadoc = mapping.javadoc(); |
| 37 | return TranslateResult.of( | 37 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc)); |
| 38 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 39 | new LocalVariableDefEntry(parent, index, translatedName, parameter, translatedDesc, javadoc) | ||
| 40 | ); | ||
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | @Override | 40 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java index 1cf1a832..d22188b2 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/LocalVariableEntry.java | |||
| @@ -17,7 +17,6 @@ import cuchaz.enigma.translation.mapping.EntryMapping; | |||
| 17 | * 19/10/2016 | 17 | * 19/10/2016 |
| 18 | */ | 18 | */ |
| 19 | public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Comparable<LocalVariableEntry> { | 19 | public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Comparable<LocalVariableEntry> { |
| 20 | |||
| 21 | protected final int index; | 20 | protected final int index; |
| 22 | protected final boolean parameter; | 21 | protected final boolean parameter; |
| 23 | 22 | ||
| @@ -53,10 +52,7 @@ public class LocalVariableEntry extends ParentedEntry<MethodEntry> implements Co | |||
| 53 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { | 52 | protected TranslateResult<LocalVariableEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 54 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 53 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 55 | String javadoc = mapping.javadoc(); | 54 | String javadoc = mapping.javadoc(); |
| 56 | return TranslateResult.of( | 55 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new LocalVariableEntry(parent, index, translatedName, parameter, javadoc)); |
| 57 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 58 | new LocalVariableEntry(parent, index, translatedName, parameter, javadoc) | ||
| 59 | ); | ||
| 60 | } | 56 | } |
| 61 | 57 | ||
| 62 | @Override | 58 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java index 30ef706e..c6a4ab73 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodDefEntry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -59,10 +59,7 @@ public class MethodDefEntry extends MethodEntry implements DefEntry<ClassEntry> | |||
| 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 59 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); | 60 | AccessFlags translatedAccess = mapping.accessModifier().transform(access); |
| 61 | String docs = mapping.javadoc(); | 61 | String docs = mapping.javadoc(); |
| 62 | return TranslateResult.of( | 62 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs)); |
| 63 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 64 | new MethodDefEntry(parent, translatedName, translatedDesc, translatedSignature, translatedAccess, docs) | ||
| 65 | ); | ||
| 66 | } | 63 | } |
| 67 | 64 | ||
| 68 | @Override | 65 | @Override |
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java index ab9c2d17..6fc3f0a0 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/MethodEntry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -24,7 +24,6 @@ import cuchaz.enigma.translation.mapping.EntryMapping; | |||
| 24 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 24 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 25 | 25 | ||
| 26 | public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable<MethodEntry> { | 26 | public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable<MethodEntry> { |
| 27 | |||
| 28 | protected final MethodDescriptor descriptor; | 27 | protected final MethodDescriptor descriptor; |
| 29 | 28 | ||
| 30 | public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) { | 29 | public MethodEntry(ClassEntry parent, String name, MethodDescriptor descriptor) { |
| @@ -61,10 +60,7 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable | |||
| 61 | protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { | 60 | protected TranslateResult<? extends MethodEntry> extendedTranslate(Translator translator, @Nonnull EntryMapping mapping) { |
| 62 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; | 61 | String translatedName = mapping.targetName() != null ? mapping.targetName() : name; |
| 63 | String docs = mapping.javadoc(); | 62 | String docs = mapping.javadoc(); |
| 64 | return TranslateResult.of( | 63 | return TranslateResult.of(mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, new MethodEntry(parent, translatedName, translator.translate(descriptor), docs)); |
| 65 | mapping.targetName() == null ? RenamableTokenType.OBFUSCATED : RenamableTokenType.DEOBFUSCATED, | ||
| 66 | new MethodEntry(parent, translatedName, translator.translate(descriptor), docs) | ||
| 67 | ); | ||
| 68 | } | 64 | } |
| 69 | 65 | ||
| 70 | @Override | 66 | @Override |
| @@ -97,6 +93,7 @@ public class MethodEntry extends ParentedEntry<ClassEntry> implements Comparable | |||
| 97 | MethodEntry methodEntry = (MethodEntry) entry; | 93 | MethodEntry methodEntry = (MethodEntry) entry; |
| 98 | return methodEntry.parent.equals(parent) && methodEntry.descriptor.canConflictWith(descriptor); | 94 | return methodEntry.parent.equals(parent) && methodEntry.descriptor.canConflictWith(descriptor); |
| 99 | } | 95 | } |
| 96 | |||
| 100 | return false; | 97 | return false; |
| 101 | } | 98 | } |
| 102 | 99 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java index 267bc11a..ff5ffa39 100644 --- a/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java +++ b/enigma/src/main/java/cuchaz/enigma/translation/representation/entry/ParentedEntry.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.representation.entry; | 12 | package cuchaz.enigma.translation.representation.entry; |
| 13 | 13 | ||
| @@ -80,9 +80,11 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> { | |||
| 80 | public TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 80 | public TranslateResult<? extends ParentedEntry<P>> extendedTranslate(Translator translator, EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 81 | P parent = getParent(); | 81 | P parent = getParent(); |
| 82 | EntryMapping mapping = resolveMapping(resolver, mappings); | 82 | EntryMapping mapping = resolveMapping(resolver, mappings); |
| 83 | |||
| 83 | if (parent == null) { | 84 | if (parent == null) { |
| 84 | return this.extendedTranslate(translator, mapping); | 85 | return this.extendedTranslate(translator, mapping); |
| 85 | } | 86 | } |
| 87 | |||
| 86 | P translatedParent = translator.translate(parent); | 88 | P translatedParent = translator.translate(parent); |
| 87 | return this.withParent(translatedParent).extendedTranslate(translator, mapping); | 89 | return this.withParent(translatedParent).extendedTranslate(translator, mapping); |
| 88 | } | 90 | } |
| @@ -90,10 +92,12 @@ public abstract class ParentedEntry<P extends Entry<?>> implements Entry<P> { | |||
| 90 | private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings) { | 92 | private EntryMapping resolveMapping(EntryResolver resolver, EntryMap<EntryMapping> mappings) { |
| 91 | for (ParentedEntry<P> entry : resolver.resolveEntry(this, ResolutionStrategy.RESOLVE_ROOT)) { | 93 | for (ParentedEntry<P> entry : resolver.resolveEntry(this, ResolutionStrategy.RESOLVE_ROOT)) { |
| 92 | EntryMapping mapping = mappings.get(entry); | 94 | EntryMapping mapping = mappings.get(entry); |
| 95 | |||
| 93 | if (mapping != null) { | 96 | if (mapping != null) { |
| 94 | return mapping; | 97 | return mapping; |
| 95 | } | 98 | } |
| 96 | } | 99 | } |
| 100 | |||
| 97 | return EntryMapping.DEFAULT; | 101 | return EntryMapping.DEFAULT; |
| 98 | } | 102 | } |
| 99 | } | 103 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java index 7d34b020..6732a59b 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java | |||
| @@ -5,16 +5,16 @@ import org.objectweb.asm.ClassWriter; | |||
| 5 | import org.objectweb.asm.tree.ClassNode; | 5 | import org.objectweb.asm.tree.ClassNode; |
| 6 | 6 | ||
| 7 | public class AsmUtil { | 7 | public class AsmUtil { |
| 8 | public static byte[] nodeToBytes(ClassNode node) { | 8 | public static byte[] nodeToBytes(ClassNode node) { |
| 9 | ClassWriter w = new ClassWriter(0); | 9 | ClassWriter w = new ClassWriter(0); |
| 10 | node.accept(w); | 10 | node.accept(w); |
| 11 | return w.toByteArray(); | 11 | return w.toByteArray(); |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | public static ClassNode bytesToNode(byte[] bytes) { | 14 | public static ClassNode bytesToNode(byte[] bytes) { |
| 15 | ClassReader r = new ClassReader(bytes); | 15 | ClassReader r = new ClassReader(bytes); |
| 16 | ClassNode node = new ClassNode(); | 16 | ClassNode node = new ClassNode(); |
| 17 | r.accept(node, 0); | 17 | r.accept(node, 0); |
| 18 | return node; | 18 | return node; |
| 19 | } | 19 | } |
| 20 | } | 20 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/I18n.java b/enigma/src/main/java/cuchaz/enigma/utils/I18n.java index 26e5b27a..95512026 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/I18n.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/I18n.java | |||
| @@ -5,7 +5,11 @@ import java.io.IOException; | |||
| 5 | import java.io.InputStream; | 5 | import java.io.InputStream; |
| 6 | import java.io.InputStreamReader; | 6 | import java.io.InputStreamReader; |
| 7 | import java.nio.charset.StandardCharsets; | 7 | import java.nio.charset.StandardCharsets; |
| 8 | import java.util.*; | 8 | import java.util.ArrayList; |
| 9 | import java.util.Arrays; | ||
| 10 | import java.util.Collections; | ||
| 11 | import java.util.Map; | ||
| 12 | import java.util.Objects; | ||
| 9 | import java.util.stream.Collectors; | 13 | import java.util.stream.Collectors; |
| 10 | import java.util.stream.Stream; | 14 | import java.util.stream.Stream; |
| 11 | 15 | ||
| @@ -33,12 +37,16 @@ public class I18n { | |||
| 33 | } catch (IOException e) { | 37 | } catch (IOException e) { |
| 34 | e.printStackTrace(); | 38 | e.printStackTrace(); |
| 35 | } | 39 | } |
| 40 | |||
| 36 | return Collections.emptyMap(); | 41 | return Collections.emptyMap(); |
| 37 | } | 42 | } |
| 38 | 43 | ||
| 39 | public static String translateOrNull(String key) { | 44 | public static String translateOrNull(String key) { |
| 40 | String value = translations.get(key); | 45 | String value = translations.get(key); |
| 41 | if (value != null) return value; | 46 | |
| 47 | if (value != null) { | ||
| 48 | return value; | ||
| 49 | } | ||
| 42 | 50 | ||
| 43 | return defaultTranslations.get(key); | 51 | return defaultTranslations.get(key); |
| 44 | } | 52 | } |
| @@ -50,6 +58,7 @@ public class I18n { | |||
| 50 | 58 | ||
| 51 | public static String translateOrEmpty(String key, Object... args) { | 59 | public static String translateOrEmpty(String key, Object... args) { |
| 52 | String text = translateOrNull(key); | 60 | String text = translateOrNull(key); |
| 61 | |||
| 53 | if (text != null) { | 62 | if (text != null) { |
| 54 | return String.format(text, args); | 63 | return String.format(text, args); |
| 55 | } else { | 64 | } else { |
| @@ -59,6 +68,7 @@ public class I18n { | |||
| 59 | 68 | ||
| 60 | public static String translateFormatted(String key, Object... args) { | 69 | public static String translateFormatted(String key, Object... args) { |
| 61 | String text = translateOrNull(key); | 70 | String text = translateOrNull(key); |
| 71 | |||
| 62 | if (text != null) { | 72 | if (text != null) { |
| 63 | return String.format(text, args); | 73 | return String.format(text, args); |
| 64 | } else if (args.length == 0) { | 74 | } else if (args.length == 0) { |
| @@ -84,6 +94,7 @@ public class I18n { | |||
| 84 | Stream<ResourceInfo> dirStream = resources.stream(); | 94 | Stream<ResourceInfo> dirStream = resources.stream(); |
| 85 | dirStream.forEach(context -> { | 95 | dirStream.forEach(context -> { |
| 86 | String file = context.getResourceName(); | 96 | String file = context.getResourceName(); |
| 97 | |||
| 87 | if (file.startsWith("lang/") && file.endsWith(".json")) { | 98 | if (file.startsWith("lang/") && file.endsWith(".json")) { |
| 88 | String fileName = file.substring(5, file.length() - 5); | 99 | String fileName = file.substring(5, file.length() - 5); |
| 89 | list.add(fileName); | 100 | list.add(fileName); |
| @@ -93,6 +104,7 @@ public class I18n { | |||
| 93 | } catch (IOException e) { | 104 | } catch (IOException e) { |
| 94 | e.printStackTrace(); | 105 | e.printStackTrace(); |
| 95 | } | 106 | } |
| 107 | |||
| 96 | return list; | 108 | return list; |
| 97 | } | 109 | } |
| 98 | 110 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Os.java b/enigma/src/main/java/cuchaz/enigma/utils/Os.java index b493c041..eaa93609 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/Os.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/Os.java | |||
| @@ -14,12 +14,12 @@ public enum Os { | |||
| 14 | public static Os getOs() { | 14 | public static Os getOs() { |
| 15 | if (os == null) { | 15 | if (os == null) { |
| 16 | String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); | 16 | String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT); |
| 17 | |||
| 17 | if (osName.contains("mac") || osName.contains("darwin")) { | 18 | if (osName.contains("mac") || osName.contains("darwin")) { |
| 18 | os = MAC; | 19 | os = MAC; |
| 19 | } else if (osName.contains("win")) { | 20 | } else if (osName.contains("win")) { |
| 20 | os = WINDOWS; | 21 | os = WINDOWS; |
| 21 | } else if (osName.contains("nix") || osName.contains("nux") | 22 | } else if (osName.contains("nix") || osName.contains("nux") || osName.contains("aix")) { |
| 22 | || osName.contains("aix")) { | ||
| 23 | os = LINUX; | 23 | os = LINUX; |
| 24 | } else if (osName.contains("sunos")) { | 24 | } else if (osName.contains("sunos")) { |
| 25 | os = SOLARIS; | 25 | os = SOLARIS; |
| @@ -27,7 +27,7 @@ public enum Os { | |||
| 27 | os = OTHER; | 27 | os = OTHER; |
| 28 | } | 28 | } |
| 29 | } | 29 | } |
| 30 | |||
| 30 | return os; | 31 | return os; |
| 31 | } | 32 | } |
| 32 | 33 | } | |
| 33 | } \ No newline at end of file | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Pair.java b/enigma/src/main/java/cuchaz/enigma/utils/Pair.java index bf02ceff..10752aca 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/Pair.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/Pair.java | |||
| @@ -3,24 +3,21 @@ package cuchaz.enigma.utils; | |||
| 3 | import java.util.Objects; | 3 | import java.util.Objects; |
| 4 | 4 | ||
| 5 | public class Pair<A, B> { | 5 | public class Pair<A, B> { |
| 6 | public final A a; | 6 | public final A a; |
| 7 | public final B b; | 7 | public final B b; |
| 8 | 8 | ||
| 9 | public Pair(A a, B b) { | 9 | public Pair(A a, B b) { |
| 10 | this.a = a; | 10 | this.a = a; |
| 11 | this.b = b; | 11 | this.b = b; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | @Override | 14 | @Override |
| 15 | public int hashCode() { | 15 | public int hashCode() { |
| 16 | return Objects.hashCode(a) * 31 + | 16 | return Objects.hashCode(a) * 31 + Objects.hashCode(b); |
| 17 | Objects.hashCode(b); | 17 | } |
| 18 | } | ||
| 19 | 18 | ||
| 20 | @Override | 19 | @Override |
| 21 | public boolean equals(Object o) { | 20 | public boolean equals(Object o) { |
| 22 | return o instanceof Pair && | 21 | return o instanceof Pair && Objects.equals(a, ((Pair<?, ?>) o).a) && Objects.equals(b, ((Pair<?, ?>) o).b); |
| 23 | Objects.equals(a, ((Pair<?, ?>) o).a) && | 22 | } |
| 24 | Objects.equals(b, ((Pair<?, ?>) o).b); | ||
| 25 | } | ||
| 26 | } | 23 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Result.java b/enigma/src/main/java/cuchaz/enigma/utils/Result.java index dcaabd58..354418ae 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/Result.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/Result.java | |||
| @@ -5,7 +5,6 @@ import java.util.Optional; | |||
| 5 | import java.util.function.Function; | 5 | import java.util.function.Function; |
| 6 | 6 | ||
| 7 | public final class Result<T, E> { | 7 | public final class Result<T, E> { |
| 8 | |||
| 9 | private final T ok; | 8 | private final T ok; |
| 10 | private final E err; | 9 | private final E err; |
| 11 | 10 | ||
| @@ -39,56 +38,85 @@ public final class Result<T, E> { | |||
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | public T unwrap() { | 40 | public T unwrap() { |
| 42 | if (this.isOk()) return this.ok; | 41 | if (this.isOk()) { |
| 42 | return this.ok; | ||
| 43 | } | ||
| 44 | |||
| 43 | throw new IllegalStateException(String.format("Called Result.unwrap on an Err value: %s", this.err)); | 45 | throw new IllegalStateException(String.format("Called Result.unwrap on an Err value: %s", this.err)); |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | public E unwrapErr() { | 48 | public E unwrapErr() { |
| 47 | if (this.isErr()) return this.err; | 49 | if (this.isErr()) { |
| 50 | return this.err; | ||
| 51 | } | ||
| 52 | |||
| 48 | throw new IllegalStateException(String.format("Called Result.unwrapErr on an Ok value: %s", this.ok)); | 53 | throw new IllegalStateException(String.format("Called Result.unwrapErr on an Ok value: %s", this.ok)); |
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | public T unwrapOr(T fallback) { | 56 | public T unwrapOr(T fallback) { |
| 52 | if (this.isOk()) return this.ok; | 57 | if (this.isOk()) { |
| 58 | return this.ok; | ||
| 59 | } | ||
| 60 | |||
| 53 | return fallback; | 61 | return fallback; |
| 54 | } | 62 | } |
| 55 | 63 | ||
| 56 | public T unwrapOrElse(Function<E, T> fn) { | 64 | public T unwrapOrElse(Function<E, T> fn) { |
| 57 | if (this.isOk()) return this.ok; | 65 | if (this.isOk()) { |
| 66 | return this.ok; | ||
| 67 | } | ||
| 68 | |||
| 58 | return fn.apply(this.err); | 69 | return fn.apply(this.err); |
| 59 | } | 70 | } |
| 60 | 71 | ||
| 61 | @SuppressWarnings("unchecked") | 72 | @SuppressWarnings("unchecked") |
| 62 | public <U> Result<U, E> map(Function<T, U> op) { | 73 | public <U> Result<U, E> map(Function<T, U> op) { |
| 63 | if (!this.isOk()) return (Result<U, E>) this; | 74 | if (!this.isOk()) { |
| 75 | return (Result<U, E>) this; | ||
| 76 | } | ||
| 77 | |||
| 64 | return Result.ok(op.apply(this.ok)); | 78 | return Result.ok(op.apply(this.ok)); |
| 65 | } | 79 | } |
| 66 | 80 | ||
| 67 | @SuppressWarnings("unchecked") | 81 | @SuppressWarnings("unchecked") |
| 68 | public <F> Result<T, F> mapErr(Function<E, F> op) { | 82 | public <F> Result<T, F> mapErr(Function<E, F> op) { |
| 69 | if (!this.isErr()) return (Result<T, F>) this; | 83 | if (!this.isErr()) { |
| 84 | return (Result<T, F>) this; | ||
| 85 | } | ||
| 86 | |||
| 70 | return Result.err(op.apply(this.err)); | 87 | return Result.err(op.apply(this.err)); |
| 71 | } | 88 | } |
| 72 | 89 | ||
| 73 | @SuppressWarnings("unchecked") | 90 | @SuppressWarnings("unchecked") |
| 74 | public <U> Result<U, E> and(Result<U, E> next) { | 91 | public <U> Result<U, E> and(Result<U, E> next) { |
| 75 | if (this.isErr()) return (Result<U, E>) this; | 92 | if (this.isErr()) { |
| 93 | return (Result<U, E>) this; | ||
| 94 | } | ||
| 95 | |||
| 76 | return next; | 96 | return next; |
| 77 | } | 97 | } |
| 78 | 98 | ||
| 79 | @SuppressWarnings("unchecked") | 99 | @SuppressWarnings("unchecked") |
| 80 | public <U> Result<U, E> andThen(Function<T, Result<U, E>> op) { | 100 | public <U> Result<U, E> andThen(Function<T, Result<U, E>> op) { |
| 81 | if (this.isErr()) return (Result<U, E>) this; | 101 | if (this.isErr()) { |
| 102 | return (Result<U, E>) this; | ||
| 103 | } | ||
| 104 | |||
| 82 | return op.apply(this.ok); | 105 | return op.apply(this.ok); |
| 83 | } | 106 | } |
| 84 | 107 | ||
| 85 | @Override | 108 | @Override |
| 86 | public boolean equals(Object o) { | 109 | public boolean equals(Object o) { |
| 87 | if (this == o) return true; | 110 | if (this == o) { |
| 88 | if (o == null || getClass() != o.getClass()) return false; | 111 | return true; |
| 112 | } | ||
| 113 | |||
| 114 | if (o == null || getClass() != o.getClass()) { | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | |||
| 89 | Result<?, ?> result = (Result<?, ?>) o; | 118 | Result<?, ?> result = (Result<?, ?>) o; |
| 90 | return Objects.equals(ok, result.ok) && | 119 | return Objects.equals(ok, result.ok) && Objects.equals(err, result.err); |
| 91 | Objects.equals(err, result.err); | ||
| 92 | } | 120 | } |
| 93 | 121 | ||
| 94 | @Override | 122 | @Override |
| @@ -104,5 +132,4 @@ public final class Result<T, E> { | |||
| 104 | return String.format("Result.Err(%s)", this.err); | 132 | return String.format("Result.Err(%s)", this.err); |
| 105 | } | 133 | } |
| 106 | } | 134 | } |
| 107 | |||
| 108 | } | 135 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java index 864154cc..2b4ed371 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/TristateChange.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.utils; | |||
| 3 | import java.util.Objects; | 3 | import java.util.Objects; |
| 4 | 4 | ||
| 5 | public final class TristateChange<T> { | 5 | public final class TristateChange<T> { |
| 6 | |||
| 7 | private static final TristateChange<?> UNCHANGED = new TristateChange<>(Type.UNCHANGED, null); | 6 | private static final TristateChange<?> UNCHANGED = new TristateChange<>(Type.UNCHANGED, null); |
| 8 | private static final TristateChange<?> RESET = new TristateChange<>(Type.RESET, null); | 7 | private static final TristateChange<?> RESET = new TristateChange<>(Type.RESET, null); |
| 9 | 8 | ||
| @@ -46,17 +45,25 @@ public final class TristateChange<T> { | |||
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | public T getNewValue() { | 47 | public T getNewValue() { |
| 49 | if (this.type != Type.SET) throw new IllegalStateException(String.format("No concrete value in %s", this)); | 48 | if (this.type != Type.SET) { |
| 49 | throw new IllegalStateException(String.format("No concrete value in %s", this)); | ||
| 50 | } | ||
| 51 | |||
| 50 | return this.val; | 52 | return this.val; |
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | @Override | 55 | @Override |
| 54 | public boolean equals(Object o) { | 56 | public boolean equals(Object o) { |
| 55 | if (this == o) return true; | 57 | if (this == o) { |
| 56 | if (o == null || getClass() != o.getClass()) return false; | 58 | return true; |
| 59 | } | ||
| 60 | |||
| 61 | if (o == null || getClass() != o.getClass()) { | ||
| 62 | return false; | ||
| 63 | } | ||
| 64 | |||
| 57 | TristateChange<?> that = (TristateChange<?>) o; | 65 | TristateChange<?> that = (TristateChange<?>) o; |
| 58 | return type == that.type && | 66 | return type == that.type && Objects.equals(val, that.val); |
| 59 | Objects.equals(val, that.val); | ||
| 60 | } | 67 | } |
| 61 | 68 | ||
| 62 | @Override | 69 | @Override |
| @@ -74,5 +81,4 @@ public final class TristateChange<T> { | |||
| 74 | RESET, | 81 | RESET, |
| 75 | SET, | 82 | SET, |
| 76 | } | 83 | } |
| 77 | |||
| 78 | } | 84 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/Utils.java b/enigma/src/main/java/cuchaz/enigma/utils/Utils.java index ad4e9368..081c9410 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/Utils.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/Utils.java | |||
| @@ -1,18 +1,16 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * <p> | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.utils; | 12 | package cuchaz.enigma.utils; |
| 13 | 13 | ||
| 14 | import com.google.common.io.CharStreams; | ||
| 15 | |||
| 16 | import java.io.IOException; | 14 | import java.io.IOException; |
| 17 | import java.io.InputStream; | 15 | import java.io.InputStream; |
| 18 | import java.io.InputStreamReader; | 16 | import java.io.InputStreamReader; |
| @@ -30,70 +28,80 @@ import java.util.function.Supplier; | |||
| 30 | import java.util.zip.ZipEntry; | 28 | import java.util.zip.ZipEntry; |
| 31 | import java.util.zip.ZipFile; | 29 | import java.util.zip.ZipFile; |
| 32 | 30 | ||
| 31 | import com.google.common.io.CharStreams; | ||
| 32 | |||
| 33 | public class Utils { | 33 | public class Utils { |
| 34 | public static String readStreamToString(InputStream in) throws IOException { | 34 | public static String readStreamToString(InputStream in) throws IOException { |
| 35 | return CharStreams.toString(new InputStreamReader(in, StandardCharsets.UTF_8)); | 35 | return CharStreams.toString(new InputStreamReader(in, StandardCharsets.UTF_8)); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | public static String readResourceToString(String path) throws IOException { | 38 | public static String readResourceToString(String path) throws IOException { |
| 39 | InputStream in = Utils.class.getResourceAsStream(path); | 39 | InputStream in = Utils.class.getResourceAsStream(path); |
| 40 | if (in == null) { | 40 | |
| 41 | throw new IllegalArgumentException("Resource not found! " + path); | 41 | if (in == null) { |
| 42 | } | 42 | throw new IllegalArgumentException("Resource not found! " + path); |
| 43 | return readStreamToString(in); | 43 | } |
| 44 | } | 44 | |
| 45 | 45 | return readStreamToString(in); | |
| 46 | public static void delete(Path path) throws IOException { | 46 | } |
| 47 | if (Files.exists(path)) { | 47 | |
| 48 | for (Path p : Files.walk(path).sorted(Comparator.reverseOrder()).toList()) { | 48 | public static void delete(Path path) throws IOException { |
| 49 | Files.delete(p); | 49 | if (Files.exists(path)) { |
| 50 | } | 50 | for (Path p : Files.walk(path).sorted(Comparator.reverseOrder()).toList()) { |
| 51 | } | 51 | Files.delete(p); |
| 52 | } | 52 | } |
| 53 | 53 | } | |
| 54 | public static byte[] zipSha1(Path path) throws IOException { | 54 | } |
| 55 | MessageDigest digest; | 55 | |
| 56 | try { | 56 | public static byte[] zipSha1(Path path) throws IOException { |
| 57 | digest = MessageDigest.getInstance("SHA-1"); | 57 | MessageDigest digest; |
| 58 | } catch (NoSuchAlgorithmException e) { | 58 | |
| 59 | // Algorithm guaranteed to be supported | 59 | try { |
| 60 | throw new RuntimeException(e); | 60 | digest = MessageDigest.getInstance("SHA-1"); |
| 61 | } | 61 | } catch (NoSuchAlgorithmException e) { |
| 62 | try (ZipFile zip = new ZipFile(path.toFile())) { | 62 | // Algorithm guaranteed to be supported |
| 63 | List<? extends ZipEntry> entries = Collections.list(zip.entries()); | 63 | throw new RuntimeException(e); |
| 64 | // only compare classes (some implementations may not generate directory entries) | 64 | } |
| 65 | entries.removeIf(entry -> !entry.getName().toLowerCase(Locale.ROOT).endsWith(".class")); | 65 | |
| 66 | // different implementations may add zip entries in a different order | 66 | try (ZipFile zip = new ZipFile(path.toFile())) { |
| 67 | entries.sort(Comparator.comparing(ZipEntry::getName)); | 67 | List<? extends ZipEntry> entries = Collections.list(zip.entries()); |
| 68 | byte[] buffer = new byte[8192]; | 68 | // only compare classes (some implementations may not generate directory entries) |
| 69 | for (ZipEntry entry : entries) { | 69 | entries.removeIf(entry -> !entry.getName().toLowerCase(Locale.ROOT).endsWith(".class")); |
| 70 | digest.update(entry.getName().getBytes(StandardCharsets.UTF_8)); | 70 | // different implementations may add zip entries in a different order |
| 71 | try (InputStream in = zip.getInputStream(entry)) { | 71 | entries.sort(Comparator.comparing(ZipEntry::getName)); |
| 72 | int n; | 72 | byte[] buffer = new byte[8192]; |
| 73 | while ((n = in.read(buffer)) != -1) { | 73 | |
| 74 | digest.update(buffer, 0, n); | 74 | for (ZipEntry entry : entries) { |
| 75 | } | 75 | digest.update(entry.getName().getBytes(StandardCharsets.UTF_8)); |
| 76 | } | 76 | |
| 77 | } | 77 | try (InputStream in = zip.getInputStream(entry)) { |
| 78 | } | 78 | int n; |
| 79 | return digest.digest(); | 79 | |
| 80 | } | 80 | while ((n = in.read(buffer)) != -1) { |
| 81 | 81 | digest.update(buffer, 0, n); | |
| 82 | public static void withLock(Lock l, Runnable op) { | 82 | } |
| 83 | try { | 83 | } |
| 84 | l.lock(); | 84 | } |
| 85 | op.run(); | 85 | } |
| 86 | } finally { | 86 | |
| 87 | l.unlock(); | 87 | return digest.digest(); |
| 88 | } | 88 | } |
| 89 | } | 89 | |
| 90 | 90 | public static void withLock(Lock l, Runnable op) { | |
| 91 | public static <R> R withLock(Lock l, Supplier<R> op) { | 91 | try { |
| 92 | try { | 92 | l.lock(); |
| 93 | l.lock(); | 93 | op.run(); |
| 94 | return op.get(); | 94 | } finally { |
| 95 | } finally { | 95 | l.unlock(); |
| 96 | l.unlock(); | 96 | } |
| 97 | } | 97 | } |
| 98 | } | 98 | |
| 99 | public static <R> R withLock(Lock l, Supplier<R> op) { | ||
| 100 | try { | ||
| 101 | l.lock(); | ||
| 102 | return op.get(); | ||
| 103 | } finally { | ||
| 104 | l.unlock(); | ||
| 105 | } | ||
| 106 | } | ||
| 99 | } | 107 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java index 6bcdbde6..b7e67f2b 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/Message.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.utils.validation; | |||
| 3 | import cuchaz.enigma.utils.I18n; | 3 | import cuchaz.enigma.utils.I18n; |
| 4 | 4 | ||
| 5 | public class Message { | 5 | public class Message { |
| 6 | |||
| 7 | public static final Message EMPTY_FIELD = create(Type.ERROR, "empty_field"); | 6 | public static final Message EMPTY_FIELD = create(Type.ERROR, "empty_field"); |
| 8 | public static final Message INVALID_IP = create(Type.ERROR, "invalid_ip"); | 7 | public static final Message INVALID_IP = create(Type.ERROR, "invalid_ip"); |
| 9 | public static final Message NOT_INT = create(Type.ERROR, "not_int"); | 8 | public static final Message NOT_INT = create(Type.ERROR, "not_int"); |
| @@ -46,5 +45,4 @@ public class Message { | |||
| 46 | WARNING, | 45 | WARNING, |
| 47 | ERROR, | 46 | ERROR, |
| 48 | } | 47 | } |
| 49 | |||
| 50 | } | 48 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java index 9ad58679..afcbf625 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/ParameterizedMessage.java | |||
| @@ -4,7 +4,6 @@ import java.util.Arrays; | |||
| 4 | import java.util.Objects; | 4 | import java.util.Objects; |
| 5 | 5 | ||
| 6 | public final class ParameterizedMessage { | 6 | public final class ParameterizedMessage { |
| 7 | |||
| 8 | public final Message message; | 7 | public final Message message; |
| 9 | private final Object[] params; | 8 | private final Object[] params; |
| 10 | private final Validatable target; | 9 | private final Validatable target; |
| @@ -25,11 +24,15 @@ public final class ParameterizedMessage { | |||
| 25 | 24 | ||
| 26 | @Override | 25 | @Override |
| 27 | public boolean equals(Object o) { | 26 | public boolean equals(Object o) { |
| 28 | if (this == o) return true; | 27 | if (this == o) { |
| 29 | if (!(o instanceof ParameterizedMessage that)) return false; | 28 | return true; |
| 30 | return Objects.equals(message, that.message) && | 29 | } |
| 31 | Arrays.equals(params, that.params) && | 30 | |
| 32 | Objects.equals(target, that.target); | 31 | if (!(o instanceof ParameterizedMessage that)) { |
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | return Objects.equals(message, that.message) && Arrays.equals(params, that.params) && Objects.equals(target, that.target); | ||
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | @Override | 38 | @Override |
| @@ -43,5 +46,4 @@ public final class ParameterizedMessage { | |||
| 43 | public String toString() { | 46 | public String toString() { |
| 44 | return String.format("ParameterizedMessage { message: %s, params: %s, target: %s }", message, Arrays.toString(params), target); | 47 | return String.format("ParameterizedMessage { message: %s, params: %s, target: %s }", message, Arrays.toString(params), target); |
| 45 | } | 48 | } |
| 46 | |||
| 47 | } | 49 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java index 5067d7e3..8a7a9ed9 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/PrintValidatable.java | |||
| @@ -4,7 +4,6 @@ import java.io.PrintStream; | |||
| 4 | import java.util.Arrays; | 4 | import java.util.Arrays; |
| 5 | 5 | ||
| 6 | public class PrintValidatable implements Validatable { | 6 | public class PrintValidatable implements Validatable { |
| 7 | |||
| 8 | public static final PrintValidatable INSTANCE = new PrintValidatable(); | 7 | public static final PrintValidatable INSTANCE = new PrintValidatable(); |
| 9 | 8 | ||
| 10 | @Override | 9 | @Override |
| @@ -16,9 +15,9 @@ public class PrintValidatable implements Validatable { | |||
| 16 | String text = message.getText(); | 15 | String text = message.getText(); |
| 17 | String longText = message.getLongText(); | 16 | String longText = message.getLongText(); |
| 18 | String type = switch (message.message.type) { | 17 | String type = switch (message.message.type) { |
| 19 | case INFO -> "info"; | 18 | case INFO -> "info"; |
| 20 | case WARNING -> "warning"; | 19 | case WARNING -> "warning"; |
| 21 | case ERROR -> "error"; | 20 | case ERROR -> "error"; |
| 22 | }; | 21 | }; |
| 23 | w.printf("%s: %s\n", type, text); | 22 | w.printf("%s: %s\n", type, text); |
| 24 | 23 | ||
| @@ -30,5 +29,4 @@ public class PrintValidatable implements Validatable { | |||
| 30 | @Override | 29 | @Override |
| 31 | public void clearMessages() { | 30 | public void clearMessages() { |
| 32 | } | 31 | } |
| 33 | |||
| 34 | } | 32 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java index 871b59d7..123c9b64 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/StandardValidation.java | |||
| @@ -1,17 +1,20 @@ | |||
| 1 | package cuchaz.enigma.utils.validation; | 1 | package cuchaz.enigma.utils.validation; |
| 2 | 2 | ||
| 3 | public class StandardValidation { | 3 | public class StandardValidation { |
| 4 | |||
| 5 | public static boolean notBlank(ValidationContext vc, String value) { | 4 | public static boolean notBlank(ValidationContext vc, String value) { |
| 6 | if (value.trim().isEmpty()) { | 5 | if (value.trim().isEmpty()) { |
| 7 | vc.raise(Message.EMPTY_FIELD); | 6 | vc.raise(Message.EMPTY_FIELD); |
| 8 | return false; | 7 | return false; |
| 9 | } | 8 | } |
| 9 | |||
| 10 | return true; | 10 | return true; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | public static boolean isInt(ValidationContext vc, String value) { | 13 | public static boolean isInt(ValidationContext vc, String value) { |
| 14 | if (!notBlank(vc, value)) return false; | 14 | if (!notBlank(vc, value)) { |
| 15 | return false; | ||
| 16 | } | ||
| 17 | |||
| 15 | try { | 18 | try { |
| 16 | Integer.parseInt(value); | 19 | Integer.parseInt(value); |
| 17 | return true; | 20 | return true; |
| @@ -22,13 +25,17 @@ public class StandardValidation { | |||
| 22 | } | 25 | } |
| 23 | 26 | ||
| 24 | public static boolean isIntInRange(ValidationContext vc, String value, int min, int max) { | 27 | public static boolean isIntInRange(ValidationContext vc, String value, int min, int max) { |
| 25 | if (!isInt(vc, value)) return false; | 28 | if (!isInt(vc, value)) { |
| 29 | return false; | ||
| 30 | } | ||
| 31 | |||
| 26 | int intVal = Integer.parseInt(value); | 32 | int intVal = Integer.parseInt(value); |
| 33 | |||
| 27 | if (intVal < min || intVal > max) { | 34 | if (intVal < min || intVal > max) { |
| 28 | vc.raise(Message.FIELD_OUT_OF_RANGE_INT, min, max); | 35 | vc.raise(Message.FIELD_OUT_OF_RANGE_INT, min, max); |
| 29 | return false; | 36 | return false; |
| 30 | } | 37 | } |
| 38 | |||
| 31 | return true; | 39 | return true; |
| 32 | } | 40 | } |
| 33 | |||
| 34 | } | 41 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java index 765ee084..39e8c410 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/Validatable.java | |||
| @@ -1,9 +1,7 @@ | |||
| 1 | package cuchaz.enigma.utils.validation; | 1 | package cuchaz.enigma.utils.validation; |
| 2 | 2 | ||
| 3 | public interface Validatable { | 3 | public interface Validatable { |
| 4 | |||
| 5 | void addMessage(ParameterizedMessage message); | 4 | void addMessage(ParameterizedMessage message); |
| 6 | 5 | ||
| 7 | void clearMessages(); | 6 | void clearMessages(); |
| 8 | |||
| 9 | } | 7 | } |
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java index 0ecb9fb3..416e8a05 100644 --- a/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java +++ b/enigma/src/main/java/cuchaz/enigma/utils/validation/ValidationContext.java | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | package cuchaz.enigma.utils.validation; | 1 | package cuchaz.enigma.utils.validation; |
| 2 | 2 | ||
| 3 | import java.util.*; | 3 | import java.util.ArrayList; |
| 4 | import java.util.Collections; | ||
| 5 | import java.util.HashSet; | ||
| 6 | import java.util.List; | ||
| 7 | import java.util.Set; | ||
| 4 | 8 | ||
| 5 | import javax.annotation.Nullable; | 9 | import javax.annotation.Nullable; |
| 6 | 10 | ||
| @@ -15,7 +19,6 @@ import cuchaz.enigma.utils.validation.Message.Type; | |||
| 15 | * multiple errors and displaying them to the user at the same time. | 19 | * multiple errors and displaying them to the user at the same time. |
| 16 | */ | 20 | */ |
| 17 | public class ValidationContext { | 21 | public class ValidationContext { |
| 18 | |||
| 19 | private Validatable activeElement = null; | 22 | private Validatable activeElement = null; |
| 20 | private final Set<Validatable> elements = new HashSet<>(); | 23 | private final Set<Validatable> elements = new HashSet<>(); |
| 21 | private final List<ParameterizedMessage> messages = new ArrayList<>(); | 24 | private final List<ParameterizedMessage> messages = new ArrayList<>(); |
| @@ -30,6 +33,7 @@ public class ValidationContext { | |||
| 30 | if (v != null) { | 33 | if (v != null) { |
| 31 | elements.add(v); | 34 | elements.add(v); |
| 32 | } | 35 | } |
| 36 | |||
| 33 | activeElement = v; | 37 | activeElement = v; |
| 34 | } | 38 | } |
| 35 | 39 | ||
| @@ -38,14 +42,16 @@ public class ValidationContext { | |||
| 38 | * that element about the message. | 42 | * that element about the message. |
| 39 | * | 43 | * |
| 40 | * @param message the message to raise | 44 | * @param message the message to raise |
| 41 | * @param args the arguments used when formatting the message text | 45 | * @param args the arguments used when formatting the message text |
| 42 | */ | 46 | */ |
| 43 | public void raise(Message message, Object... args) { | 47 | public void raise(Message message, Object... args) { |
| 44 | ParameterizedMessage pm = new ParameterizedMessage(message, args, this.activeElement); | 48 | ParameterizedMessage pm = new ParameterizedMessage(message, args, this.activeElement); |
| 49 | |||
| 45 | if (!this.messages.contains(pm)) { | 50 | if (!this.messages.contains(pm)) { |
| 46 | if (activeElement != null) { | 51 | if (activeElement != null) { |
| 47 | activeElement.addMessage(pm); | 52 | activeElement.addMessage(pm); |
| 48 | } | 53 | } |
| 54 | |||
| 49 | messages.add(pm); | 55 | messages.add(pm); |
| 50 | } | 56 | } |
| 51 | } | 57 | } |
| @@ -72,6 +78,7 @@ public class ValidationContext { | |||
| 72 | for (ParameterizedMessage message : this.messages) { | 78 | for (ParameterizedMessage message : this.messages) { |
| 73 | PrintValidatable.formatMessage(System.err, message); | 79 | PrintValidatable.formatMessage(System.err, message); |
| 74 | } | 80 | } |
| 81 | |||
| 75 | throw new IllegalStateException("Errors encountered; cannot continue! Check error log for details."); | 82 | throw new IllegalStateException("Errors encountered; cannot continue! Check error log for details."); |
| 76 | } | 83 | } |
| 77 | } | 84 | } |
| @@ -90,5 +97,4 @@ public class ValidationContext { | |||
| 90 | elements.clear(); | 97 | elements.clear(); |
| 91 | messages.clear(); | 98 | messages.clear(); |
| 92 | } | 99 | } |
| 93 | |||
| 94 | } | 100 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/ConfigTest.java b/enigma/src/test/java/cuchaz/enigma/ConfigTest.java index a44f0375..95689f82 100644 --- a/enigma/src/test/java/cuchaz/enigma/ConfigTest.java +++ b/enigma/src/test/java/cuchaz/enigma/ConfigTest.java | |||
| @@ -1,13 +1,12 @@ | |||
| 1 | package cuchaz.enigma; | 1 | package cuchaz.enigma; |
| 2 | 2 | ||
| 3 | import static org.junit.Assert.assertEquals; | ||
| 4 | |||
| 3 | import org.junit.Test; | 5 | import org.junit.Test; |
| 4 | 6 | ||
| 5 | import cuchaz.enigma.config.ConfigContainer; | 7 | import cuchaz.enigma.config.ConfigContainer; |
| 6 | 8 | ||
| 7 | import static org.junit.Assert.assertEquals; | ||
| 8 | |||
| 9 | public class ConfigTest { | 9 | public class ConfigTest { |
| 10 | |||
| 11 | @Test | 10 | @Test |
| 12 | public void serialize() { | 11 | public void serialize() { |
| 13 | ConfigContainer cc = new ConfigContainer(); | 12 | ConfigContainer cc = new ConfigContainer(); |
| @@ -17,15 +16,7 @@ public class ConfigTest { | |||
| 17 | cc.data().section("a").section("b").section("c").setInt("c", 5); | 16 | cc.data().section("a").section("b").section("c").setInt("c", 5); |
| 18 | cc.data().section("a").section("b").section("c").setDouble("d", 3.5); | 17 | cc.data().section("a").section("b").section("c").setDouble("d", 3.5); |
| 19 | cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); | 18 | cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); |
| 20 | assertEquals("a=a\n" + | 19 | assertEquals("a=a\n" + "\n" + "[a][b][c]\n" + "a=abcd\n" + "b=true\n" + "c=5\n" + "d=3.5\n" + "e=#123456\n", cc.serialize()); |
| 21 | "\n" + | ||
| 22 | "[a][b][c]\n" + | ||
| 23 | "a=abcd\n" + | ||
| 24 | "b=true\n" + | ||
| 25 | "c=5\n" + | ||
| 26 | "d=3.5\n" + | ||
| 27 | "e=#123456\n", | ||
| 28 | cc.serialize()); | ||
| 29 | } | 20 | } |
| 30 | 21 | ||
| 31 | @Test | 22 | @Test |
| @@ -37,14 +28,7 @@ public class ConfigTest { | |||
| 37 | cc.data().section("a").section("b").section("c").setInt("c", 5); | 28 | cc.data().section("a").section("b").section("c").setInt("c", 5); |
| 38 | cc.data().section("a").section("b").section("c").setDouble("d", 3.5); | 29 | cc.data().section("a").section("b").section("c").setDouble("d", 3.5); |
| 39 | cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); | 30 | cc.data().section("a").section("b").section("c").setRgbColor("e", 0x123456); |
| 40 | assertEquals(ConfigContainer.parse("a=a\n" + | 31 | assertEquals(ConfigContainer.parse("a=a\n" + "\n" + "[a][b][c]\n" + "a=abcd\n" + "b=true\n" + "c=5\n" + "d=3.5\n" + "e=#123456\n").data(), cc.data()); |
| 41 | "\n" + | ||
| 42 | "[a][b][c]\n" + | ||
| 43 | "a=abcd\n" + | ||
| 44 | "b=true\n" + | ||
| 45 | "c=5\n" + | ||
| 46 | "d=3.5\n" + | ||
| 47 | "e=#123456\n").data(), cc.data()); | ||
| 48 | } | 32 | } |
| 49 | 33 | ||
| 50 | @Test | 34 | @Test |
| @@ -52,12 +36,10 @@ public class ConfigTest { | |||
| 52 | ConfigContainer cc = new ConfigContainer(); | 36 | ConfigContainer cc = new ConfigContainer(); |
| 53 | String thing = "\\[],\\,./'\"`~!@#$%^&*()_+-=|}{\n\\\\\r\b\u0000\uffff\u1234"; | 37 | String thing = "\\[],\\,./'\"`~!@#$%^&*()_+-=|}{\n\\\\\r\b\u0000\uffff\u1234"; |
| 54 | cc.data().section(thing).setString(thing, thing); | 38 | cc.data().section(thing).setString(thing, thing); |
| 55 | cc.data().section(thing).setArray("arr", new String[] { thing, thing, thing, thing }); | 39 | cc.data().section(thing).setArray("arr", new String[]{thing, thing, thing, thing}); |
| 56 | 40 | ||
| 57 | assertEquals( | 41 | assertEquals( |
| 58 | "[\\\\[\\],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234]\n" + | 42 | "[\\\\[\\],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234]\n" + "\\\\\\[],\\\\,./'\"`~!@#$%^&*()_+-\\=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234=\\\\[],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n" + "arr=\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n", |
| 59 | "\\\\\\[],\\\\,./'\"`~!@#$%^&*()_+-\\=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234=\\\\[],\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n" + | ||
| 60 | "arr=\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234,\\\\\\\\[]\\\\,\\\\\\\\\\\\,./'\"`~!@#$%^&*()_+-=|}{\\n\\\\\\\\\\\\\\\\\\u000d\\u0008\\u0000\\uffff\\u1234\n", | ||
| 61 | cc.serialize()); | 43 | cc.serialize()); |
| 62 | 44 | ||
| 63 | ConfigContainer cc1 = ConfigContainer.parse(cc.serialize()); | 45 | ConfigContainer cc1 = ConfigContainer.parse(cc.serialize()); |
| @@ -77,10 +59,8 @@ public class ConfigTest { | |||
| 77 | assertEquals("", ConfigContainer.parse("[").serialize()); | 59 | assertEquals("", ConfigContainer.parse("[").serialize()); |
| 78 | assertEquals("[a]\na=b\nc=d\n", ConfigContainer.parse("[a]\na=b\n[\nc=d").serialize()); | 60 | assertEquals("[a]\na=b\nc=d\n", ConfigContainer.parse("[a]\na=b\n[\nc=d").serialize()); |
| 79 | 61 | ||
| 80 | |||
| 81 | // not technically syntax errors but never something that gets generated | 62 | // not technically syntax errors but never something that gets generated |
| 82 | assertEquals("", ConfigContainer.parse("[a]").serialize()); | 63 | assertEquals("", ConfigContainer.parse("[a]").serialize()); |
| 83 | assertEquals("", ConfigContainer.parse("[a]\n[b]").serialize()); | 64 | assertEquals("", ConfigContainer.parse("[a]\n[b]").serialize()); |
| 84 | } | 65 | } |
| 85 | |||
| 86 | } | 66 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java index 12515358..1678f59e 100644 --- a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java +++ b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java | |||
| @@ -1,30 +1,31 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.analysis.index.JarIndex; | ||
| 15 | import cuchaz.enigma.analysis.index.PackageVisibilityIndex; | ||
| 16 | import cuchaz.enigma.classprovider.JarClassProvider; | ||
| 17 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 18 | import org.junit.Test; | ||
| 19 | |||
| 20 | import java.nio.file.Path; | ||
| 21 | import java.nio.file.Paths; | ||
| 22 | |||
| 23 | import static cuchaz.enigma.TestEntryFactory.newClass; | 14 | import static cuchaz.enigma.TestEntryFactory.newClass; |
| 24 | import static org.hamcrest.MatcherAssert.assertThat; | 15 | import static org.hamcrest.MatcherAssert.assertThat; |
| 25 | import static org.hamcrest.Matchers.contains; | 16 | import static org.hamcrest.Matchers.contains; |
| 26 | import static org.hamcrest.Matchers.containsInAnyOrder; | 17 | import static org.hamcrest.Matchers.containsInAnyOrder; |
| 27 | 18 | ||
| 19 | import java.nio.file.Path; | ||
| 20 | import java.nio.file.Paths; | ||
| 21 | |||
| 22 | import org.junit.Test; | ||
| 23 | |||
| 24 | import cuchaz.enigma.analysis.index.JarIndex; | ||
| 25 | import cuchaz.enigma.analysis.index.PackageVisibilityIndex; | ||
| 26 | import cuchaz.enigma.classprovider.JarClassProvider; | ||
| 27 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | ||
| 28 | |||
| 28 | public class PackageVisibilityIndexTest { | 29 | public class PackageVisibilityIndexTest { |
| 29 | public static final Path JAR = Paths.get("build/test-obf/packageAccess.jar"); | 30 | public static final Path JAR = Paths.get("build/test-obf/packageAccess.jar"); |
| 30 | private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep"); | 31 | private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep"); |
| @@ -46,10 +47,6 @@ public class PackageVisibilityIndexTest { | |||
| 46 | PackageVisibilityIndex visibilityIndex = jarIndex.getPackageVisibilityIndex(); | 47 | PackageVisibilityIndex visibilityIndex = jarIndex.getPackageVisibilityIndex(); |
| 47 | assertThat(visibilityIndex.getPartition(BASE), containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER)); | 48 | assertThat(visibilityIndex.getPartition(BASE), containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER)); |
| 48 | System.out.println(visibilityIndex.getPartitions()); | 49 | System.out.println(visibilityIndex.getPartitions()); |
| 49 | assertThat(visibilityIndex.getPartitions(), containsInAnyOrder( | 50 | assertThat(visibilityIndex.getPartitions(), containsInAnyOrder(containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER), containsInAnyOrder(OTHER_PACKAGE_CHILD, OTHER_PACKAGE_CHILD_INNER), contains(KEEP))); |
| 50 | containsInAnyOrder(BASE, SAME_PACKAGE_CHILD, SAME_PACKAGE_CHILD_INNER), | ||
| 51 | containsInAnyOrder(OTHER_PACKAGE_CHILD, OTHER_PACKAGE_CHILD_INNER), | ||
| 52 | contains(KEEP) | ||
| 53 | )); | ||
| 54 | } | 51 | } |
| 55 | } | 52 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java index 2584d581..b19aa77e 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java +++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java | |||
| @@ -1,16 +1,20 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 16 | import static org.hamcrest.Matchers.containsInAnyOrder; | ||
| 17 | |||
| 14 | import java.nio.file.Files; | 18 | import java.nio.file.Files; |
| 15 | import java.nio.file.Path; | 19 | import java.nio.file.Path; |
| 16 | import java.nio.file.Paths; | 20 | import java.nio.file.Paths; |
| @@ -23,10 +27,6 @@ import cuchaz.enigma.source.Decompiler; | |||
| 23 | import cuchaz.enigma.source.Decompilers; | 27 | import cuchaz.enigma.source.Decompilers; |
| 24 | import cuchaz.enigma.source.SourceSettings; | 28 | import cuchaz.enigma.source.SourceSettings; |
| 25 | 29 | ||
| 26 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 28 | import static org.hamcrest.Matchers.containsInAnyOrder; | ||
| 29 | |||
| 30 | public class TestDeobfed { | 30 | public class TestDeobfed { |
| 31 | public static final Path OBF = Paths.get("build/test-obf/translation.jar"); | 31 | public static final Path OBF = Paths.get("build/test-obf/translation.jar"); |
| 32 | public static final Path DEOBF = Paths.get("build/test-deobf/translation.jar"); | 32 | public static final Path DEOBF = Paths.get("build/test-deobf/translation.jar"); |
| @@ -45,31 +45,9 @@ public class TestDeobfed { | |||
| 45 | 45 | ||
| 46 | @Test | 46 | @Test |
| 47 | public void obfEntries() { | 47 | public void obfEntries() { |
| 48 | assertThat(deobfProject.getJarIndex().getEntryIndex().getClasses(), containsInAnyOrder( | 48 | assertThat(deobfProject.getJarIndex().getEntryIndex().getClasses(), |
| 49 | newClass("cuchaz/enigma/inputs/Keep"), | 49 | containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), newClass("a"), newClass("b"), newClass("c"), newClass("d"), newClass("d$1"), newClass("e"), newClass("f"), newClass("g"), newClass("g$a"), newClass("g$a$a"), newClass("g$b"), newClass("g$b$a"), newClass("h"), |
| 50 | newClass("a"), | 50 | newClass("h$a"), newClass("h$a$a"), newClass("h$b"), newClass("h$b$a"), newClass("h$b$a$a"), newClass("h$b$a$b"), newClass("i"), newClass("i$a"), newClass("i$b"))); |
| 51 | newClass("b"), | ||
| 52 | newClass("c"), | ||
| 53 | newClass("d"), | ||
| 54 | newClass("d$1"), | ||
| 55 | newClass("e"), | ||
| 56 | newClass("f"), | ||
| 57 | newClass("g"), | ||
| 58 | newClass("g$a"), | ||
| 59 | newClass("g$a$a"), | ||
| 60 | newClass("g$b"), | ||
| 61 | newClass("g$b$a"), | ||
| 62 | newClass("h"), | ||
| 63 | newClass("h$a"), | ||
| 64 | newClass("h$a$a"), | ||
| 65 | newClass("h$b"), | ||
| 66 | newClass("h$b$a"), | ||
| 67 | newClass("h$b$a$a"), | ||
| 68 | newClass("h$b$a$b"), | ||
| 69 | newClass("i"), | ||
| 70 | newClass("i$a"), | ||
| 71 | newClass("i$b") | ||
| 72 | )); | ||
| 73 | } | 51 | } |
| 74 | 52 | ||
| 75 | @Test | 53 | @Test |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java index 38940ca1..587494e6 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java +++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java | |||
| @@ -1,24 +1,25 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.nio.file.Paths; | ||
| 16 | |||
| 17 | import org.junit.Test; | ||
| 18 | |||
| 14 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | 19 | import cuchaz.enigma.classprovider.ClasspathClassProvider; |
| 15 | import cuchaz.enigma.source.Decompiler; | 20 | import cuchaz.enigma.source.Decompiler; |
| 16 | import cuchaz.enigma.source.Decompilers; | 21 | import cuchaz.enigma.source.Decompilers; |
| 17 | import cuchaz.enigma.source.SourceSettings; | 22 | import cuchaz.enigma.source.SourceSettings; |
| 18 | import org.junit.Test; | ||
| 19 | |||
| 20 | import java.io.IOException; | ||
| 21 | import java.nio.file.Paths; | ||
| 22 | 23 | ||
| 23 | public class TestDeobfuscator { | 24 | public class TestDeobfuscator { |
| 24 | private EnigmaProject openProject() throws IOException { | 25 | private EnigmaProject openProject() throws IOException { |
| @@ -27,8 +28,7 @@ public class TestDeobfuscator { | |||
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | @Test | 30 | @Test |
| 30 | public void loadJar() | 31 | public void loadJar() throws Exception { |
| 31 | throws Exception { | ||
| 32 | openProject(); | 32 | openProject(); |
| 33 | } | 33 | } |
| 34 | 34 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java b/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java index 9e1425a2..833e217f 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java +++ b/enigma/src/test/java/cuchaz/enigma/TestEntryFactory.java | |||
| @@ -1,24 +1,24 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.analysis.EntryReference; | 14 | import cuchaz.enigma.analysis.EntryReference; |
| 15 | import cuchaz.enigma.translation.representation.*; | 15 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 16 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 16 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 17 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 17 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 18 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 18 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 19 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 19 | 20 | ||
| 20 | public class TestEntryFactory { | 21 | public class TestEntryFactory { |
| 21 | |||
| 22 | public static ClassEntry newClass(String name) { | 22 | public static ClassEntry newClass(String name) { |
| 23 | return new ClassEntry(name); | 23 | return new ClassEntry(name); |
| 24 | } | 24 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java index 6b609941..46086e56 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java +++ b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java | |||
| @@ -1,16 +1,25 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 15 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 16 | import static org.hamcrest.Matchers.is; | ||
| 17 | |||
| 18 | import java.nio.file.Path; | ||
| 19 | import java.nio.file.Paths; | ||
| 20 | |||
| 21 | import org.junit.Test; | ||
| 22 | |||
| 14 | import cuchaz.enigma.analysis.index.JarIndex; | 23 | import cuchaz.enigma.analysis.index.JarIndex; |
| 15 | import cuchaz.enigma.classprovider.CachingClassProvider; | 24 | import cuchaz.enigma.classprovider.CachingClassProvider; |
| 16 | import cuchaz.enigma.classprovider.JarClassProvider; | 25 | import cuchaz.enigma.classprovider.JarClassProvider; |
| @@ -18,17 +27,8 @@ import cuchaz.enigma.source.Decompiler; | |||
| 18 | import cuchaz.enigma.source.Decompilers; | 27 | import cuchaz.enigma.source.Decompilers; |
| 19 | import cuchaz.enigma.source.SourceSettings; | 28 | import cuchaz.enigma.source.SourceSettings; |
| 20 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 29 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 21 | import org.junit.Test; | ||
| 22 | |||
| 23 | import java.nio.file.Path; | ||
| 24 | import java.nio.file.Paths; | ||
| 25 | |||
| 26 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 27 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 28 | import static org.hamcrest.Matchers.is; | ||
| 29 | 30 | ||
| 30 | public class TestInnerClasses { | 31 | public class TestInnerClasses { |
| 31 | |||
| 32 | private static final ClassEntry SimpleOuter = newClass("d"); | 32 | private static final ClassEntry SimpleOuter = newClass("d"); |
| 33 | private static final ClassEntry SimpleInner = newClass("d$a"); | 33 | private static final ClassEntry SimpleInner = newClass("d$a"); |
| 34 | private static final ClassEntry ConstructorArgsOuter = newClass("c"); | 34 | private static final ClassEntry ConstructorArgsOuter = newClass("c"); |
| @@ -61,26 +61,19 @@ public class TestInnerClasses { | |||
| 61 | 61 | ||
| 62 | @Test | 62 | @Test |
| 63 | public void classTree() { | 63 | public void classTree() { |
| 64 | |||
| 65 | // root level | 64 | // root level |
| 66 | assertThat(index.getEntryIndex().hasClass(ClassTreeRoot), is(true)); | 65 | assertThat(index.getEntryIndex().hasClass(ClassTreeRoot), is(true)); |
| 67 | 66 | ||
| 68 | // level 1 | 67 | // level 1 |
| 69 | ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName() | 68 | ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName()); |
| 70 | + "$" + ClassTreeLevel1.getSimpleName()); | ||
| 71 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); | 69 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); |
| 72 | 70 | ||
| 73 | // level 2 | 71 | // level 2 |
| 74 | fullClassEntry = new ClassEntry(ClassTreeRoot.getName() | 72 | fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName() + "$" + ClassTreeLevel2.getSimpleName()); |
| 75 | + "$" + ClassTreeLevel1.getSimpleName() | ||
| 76 | + "$" + ClassTreeLevel2.getSimpleName()); | ||
| 77 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); | 73 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); |
| 78 | 74 | ||
| 79 | // level 3 | 75 | // level 3 |
| 80 | fullClassEntry = new ClassEntry(ClassTreeRoot.getName() | 76 | fullClassEntry = new ClassEntry(ClassTreeRoot.getName() + "$" + ClassTreeLevel1.getSimpleName() + "$" + ClassTreeLevel2.getSimpleName() + "$" + ClassTreeLevel3.getSimpleName()); |
| 81 | + "$" + ClassTreeLevel1.getSimpleName() | ||
| 82 | + "$" + ClassTreeLevel2.getSimpleName() | ||
| 83 | + "$" + ClassTreeLevel3.getSimpleName()); | ||
| 84 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); | 77 | assertThat(index.getEntryIndex().hasClass(fullClassEntry), is(true)); |
| 85 | } | 78 | } |
| 86 | 79 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java index 0790193d..05565b61 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java +++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java | |||
| @@ -1,16 +1,30 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod; | ||
| 15 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 16 | import static cuchaz.enigma.TestEntryFactory.newMethod; | ||
| 17 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 18 | import static org.hamcrest.Matchers.containsInAnyOrder; | ||
| 19 | import static org.hamcrest.Matchers.empty; | ||
| 20 | import static org.hamcrest.Matchers.is; | ||
| 21 | |||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.nio.file.Paths; | ||
| 24 | import java.util.Collection; | ||
| 25 | |||
| 26 | import org.junit.Test; | ||
| 27 | |||
| 14 | import cuchaz.enigma.analysis.EntryReference; | 28 | import cuchaz.enigma.analysis.EntryReference; |
| 15 | import cuchaz.enigma.analysis.index.JarIndex; | 29 | import cuchaz.enigma.analysis.index.JarIndex; |
| 16 | import cuchaz.enigma.classprovider.CachingClassProvider; | 30 | import cuchaz.enigma.classprovider.CachingClassProvider; |
| @@ -18,18 +32,8 @@ import cuchaz.enigma.classprovider.JarClassProvider; | |||
| 18 | import cuchaz.enigma.translation.representation.entry.ClassEntry; | 32 | import cuchaz.enigma.translation.representation.entry.ClassEntry; |
| 19 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 33 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 20 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 34 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 21 | import org.junit.Test; | ||
| 22 | |||
| 23 | import java.nio.file.Path; | ||
| 24 | import java.nio.file.Paths; | ||
| 25 | import java.util.Collection; | ||
| 26 | |||
| 27 | import static cuchaz.enigma.TestEntryFactory.*; | ||
| 28 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 29 | import static org.hamcrest.Matchers.*; | ||
| 30 | 35 | ||
| 31 | public class TestJarIndexConstructorReferences { | 36 | public class TestJarIndexConstructorReferences { |
| 32 | |||
| 33 | public static final Path JAR = Paths.get("build/test-obf/constructors.jar"); | 37 | public static final Path JAR = Paths.get("build/test-obf/constructors.jar"); |
| 34 | private JarIndex index; | 38 | private JarIndex index; |
| 35 | 39 | ||
| @@ -47,8 +51,7 @@ public class TestJarIndexConstructorReferences { | |||
| 47 | 51 | ||
| 48 | @Test | 52 | @Test |
| 49 | public void obfEntries() { | 53 | public void obfEntries() { |
| 50 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, | 54 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClass, subsubClass, defaultClass, callerClass)); |
| 51 | subClass, subsubClass, defaultClass, callerClass)); | ||
| 52 | } | 55 | } |
| 53 | 56 | ||
| 54 | @Test | 57 | @Test |
| @@ -56,50 +59,36 @@ public class TestJarIndexConstructorReferences { | |||
| 56 | public void baseDefault() { | 59 | public void baseDefault() { |
| 57 | MethodEntry source = newMethod(baseClass, "<init>", "()V"); | 60 | MethodEntry source = newMethod(baseClass, "<init>", "()V"); |
| 58 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToMethod(source); | 61 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToMethod(source); |
| 59 | assertThat(references, containsInAnyOrder( | 62 | assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "a", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(III)V"))); |
| 60 | newBehaviorReferenceByMethod(source, callerClass.getName(), "a", "()V"), | ||
| 61 | newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "()V"), | ||
| 62 | newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(III)V") | ||
| 63 | )); | ||
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | @Test | 65 | @Test |
| 67 | @SuppressWarnings("unchecked") | 66 | @SuppressWarnings("unchecked") |
| 68 | public void baseInt() { | 67 | public void baseInt() { |
| 69 | MethodEntry source = newMethod(baseClass, "<init>", "(I)V"); | 68 | MethodEntry source = newMethod(baseClass, "<init>", "(I)V"); |
| 70 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 69 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "b", "()V"))); |
| 71 | newBehaviorReferenceByMethod(source, callerClass.getName(), "b", "()V") | ||
| 72 | )); | ||
| 73 | } | 70 | } |
| 74 | 71 | ||
| 75 | @Test | 72 | @Test |
| 76 | @SuppressWarnings("unchecked") | 73 | @SuppressWarnings("unchecked") |
| 77 | public void subDefault() { | 74 | public void subDefault() { |
| 78 | MethodEntry source = newMethod(subClass, "<init>", "()V"); | 75 | MethodEntry source = newMethod(subClass, "<init>", "()V"); |
| 79 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 76 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "c", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(I)V"))); |
| 80 | newBehaviorReferenceByMethod(source, callerClass.getName(), "c", "()V"), | ||
| 81 | newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(I)V") | ||
| 82 | )); | ||
| 83 | } | 77 | } |
| 84 | 78 | ||
| 85 | @Test | 79 | @Test |
| 86 | @SuppressWarnings("unchecked") | 80 | @SuppressWarnings("unchecked") |
| 87 | public void subInt() { | 81 | public void subInt() { |
| 88 | MethodEntry source = newMethod(subClass, "<init>", "(I)V"); | 82 | MethodEntry source = newMethod(subClass, "<init>", "(I)V"); |
| 89 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 83 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), |
| 90 | newBehaviorReferenceByMethod(source, callerClass.getName(), "d", "()V"), | 84 | containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "d", "()V"), newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(II)V"), newBehaviorReferenceByMethod(source, subsubClass.getName(), "<init>", "(I)V"))); |
| 91 | newBehaviorReferenceByMethod(source, subClass.getName(), "<init>", "(II)V"), | ||
| 92 | newBehaviorReferenceByMethod(source, subsubClass.getName(), "<init>", "(I)V") | ||
| 93 | )); | ||
| 94 | } | 85 | } |
| 95 | 86 | ||
| 96 | @Test | 87 | @Test |
| 97 | @SuppressWarnings("unchecked") | 88 | @SuppressWarnings("unchecked") |
| 98 | public void subIntInt() { | 89 | public void subIntInt() { |
| 99 | MethodEntry source = newMethod(subClass, "<init>", "(II)V"); | 90 | MethodEntry source = newMethod(subClass, "<init>", "(II)V"); |
| 100 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 91 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "e", "()V"))); |
| 101 | newBehaviorReferenceByMethod(source, callerClass.getName(), "e", "()V") | ||
| 102 | )); | ||
| 103 | } | 92 | } |
| 104 | 93 | ||
| 105 | @Test | 94 | @Test |
| @@ -112,17 +101,13 @@ public class TestJarIndexConstructorReferences { | |||
| 112 | @SuppressWarnings("unchecked") | 101 | @SuppressWarnings("unchecked") |
| 113 | public void subsubInt() { | 102 | public void subsubInt() { |
| 114 | MethodEntry source = newMethod(subsubClass, "<init>", "(I)V"); | 103 | MethodEntry source = newMethod(subsubClass, "<init>", "(I)V"); |
| 115 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 104 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "f", "()V"))); |
| 116 | newBehaviorReferenceByMethod(source, callerClass.getName(), "f", "()V") | ||
| 117 | )); | ||
| 118 | } | 105 | } |
| 119 | 106 | ||
| 120 | @Test | 107 | @Test |
| 121 | @SuppressWarnings("unchecked") | 108 | @SuppressWarnings("unchecked") |
| 122 | public void defaultConstructable() { | 109 | public void defaultConstructable() { |
| 123 | MethodEntry source = newMethod(defaultClass, "<init>", "()V"); | 110 | MethodEntry source = newMethod(defaultClass, "<init>", "()V"); |
| 124 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder( | 111 | assertThat(index.getReferenceIndex().getReferencesToMethod(source), containsInAnyOrder(newBehaviorReferenceByMethod(source, callerClass.getName(), "g", "()V"))); |
| 125 | newBehaviorReferenceByMethod(source, callerClass.getName(), "g", "()V") | ||
| 126 | )); | ||
| 127 | } | 112 | } |
| 128 | } | 113 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java index a9045f9c..3f6f1511 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java +++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java | |||
| @@ -1,16 +1,34 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import static cuchaz.enigma.TestEntryFactory.newClass; | ||
| 15 | import static cuchaz.enigma.TestEntryFactory.newField; | ||
| 16 | import static cuchaz.enigma.TestEntryFactory.newMethod; | ||
| 17 | import static cuchaz.enigma.TestEntryFactory.newFieldReferenceByMethod; | ||
| 18 | import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod; | ||
| 19 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 20 | import static org.hamcrest.Matchers.contains; | ||
| 21 | import static org.hamcrest.Matchers.containsInAnyOrder; | ||
| 22 | import static org.hamcrest.Matchers.empty; | ||
| 23 | import static org.hamcrest.Matchers.is; | ||
| 24 | |||
| 25 | import java.nio.file.Path; | ||
| 26 | import java.nio.file.Paths; | ||
| 27 | import java.util.Collection; | ||
| 28 | |||
| 29 | import org.junit.Test; | ||
| 30 | import org.objectweb.asm.Opcodes; | ||
| 31 | |||
| 14 | import cuchaz.enigma.analysis.EntryReference; | 32 | import cuchaz.enigma.analysis.EntryReference; |
| 15 | import cuchaz.enigma.analysis.index.EntryIndex; | 33 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 16 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 34 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| @@ -24,19 +42,8 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 24 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 42 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 25 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 43 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 26 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 44 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 27 | import org.junit.Test; | ||
| 28 | import org.objectweb.asm.Opcodes; | ||
| 29 | |||
| 30 | import java.nio.file.Path; | ||
| 31 | import java.nio.file.Paths; | ||
| 32 | import java.util.Collection; | ||
| 33 | |||
| 34 | import static cuchaz.enigma.TestEntryFactory.*; | ||
| 35 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 36 | import static org.hamcrest.Matchers.*; | ||
| 37 | 45 | ||
| 38 | public class TestJarIndexInheritanceTree { | 46 | public class TestJarIndexInheritanceTree { |
| 39 | |||
| 40 | public static final Path JAR = Paths.get("build/test-obf/inheritanceTree.jar"); | 47 | public static final Path JAR = Paths.get("build/test-obf/inheritanceTree.jar"); |
| 41 | private JarIndex index; | 48 | private JarIndex index; |
| 42 | 49 | ||
| @@ -55,21 +62,17 @@ public class TestJarIndexInheritanceTree { | |||
| 55 | 62 | ||
| 56 | @Test | 63 | @Test |
| 57 | public void obfEntries() { | 64 | public void obfEntries() { |
| 58 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder( | 65 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClassA, subClassAA, subClassB)); |
| 59 | newClass("cuchaz/enigma/inputs/Keep"), baseClass, subClassA, subClassAA, subClassB | ||
| 60 | )); | ||
| 61 | } | 66 | } |
| 62 | 67 | ||
| 63 | @Test | 68 | @Test |
| 64 | public void translationIndex() { | 69 | public void translationIndex() { |
| 65 | |||
| 66 | InheritanceIndex index = this.index.getInheritanceIndex(); | 70 | InheritanceIndex index = this.index.getInheritanceIndex(); |
| 67 | 71 | ||
| 68 | // base class | 72 | // base class |
| 69 | assertThat(index.getParents(baseClass), is(empty())); | 73 | assertThat(index.getParents(baseClass), is(empty())); |
| 70 | assertThat(index.getAncestors(baseClass), is(empty())); | 74 | assertThat(index.getAncestors(baseClass), is(empty())); |
| 71 | assertThat(index.getChildren(baseClass), containsInAnyOrder(subClassA, subClassB | 75 | assertThat(index.getChildren(baseClass), containsInAnyOrder(subClassA, subClassB)); |
| 72 | )); | ||
| 73 | 76 | ||
| 74 | // subclass a | 77 | // subclass a |
| 75 | assertThat(index.getParents(subClassA), contains(baseClass)); | 78 | assertThat(index.getParents(subClassA), contains(baseClass)); |
| @@ -95,41 +98,22 @@ public class TestJarIndexInheritanceTree { | |||
| 95 | 98 | ||
| 96 | @Test | 99 | @Test |
| 97 | public void relatedMethodImplementations() { | 100 | public void relatedMethodImplementations() { |
| 98 | |||
| 99 | Collection<MethodEntry> entries; | 101 | Collection<MethodEntry> entries; |
| 100 | 102 | ||
| 101 | EntryResolver resolver = new IndexEntryResolver(index); | 103 | EntryResolver resolver = new IndexEntryResolver(index); |
| 102 | // getName() | 104 | // getName() |
| 103 | entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()Ljava/lang/String;")); | 105 | entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()Ljava/lang/String;")); |
| 104 | assertThat(entries, containsInAnyOrder( | 106 | assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()Ljava/lang/String;"), newMethod(subClassAA, "a", "()Ljava/lang/String;"))); |
| 105 | newMethod(baseClass, "a", "()Ljava/lang/String;"), | ||
| 106 | newMethod(subClassAA, "a", "()Ljava/lang/String;") | ||
| 107 | )); | ||
| 108 | entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()Ljava/lang/String;")); | 107 | entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()Ljava/lang/String;")); |
| 109 | assertThat(entries, containsInAnyOrder( | 108 | assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()Ljava/lang/String;"), newMethod(subClassAA, "a", "()Ljava/lang/String;"))); |
| 110 | newMethod(baseClass, "a", "()Ljava/lang/String;"), | ||
| 111 | newMethod(subClassAA, "a", "()Ljava/lang/String;") | ||
| 112 | )); | ||
| 113 | 109 | ||
| 114 | // doBaseThings() | 110 | // doBaseThings() |
| 115 | entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()V")); | 111 | entries = resolver.resolveEquivalentMethods(newMethod(baseClass, "a", "()V")); |
| 116 | assertThat(entries, containsInAnyOrder( | 112 | assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V"))); |
| 117 | newMethod(baseClass, "a", "()V"), | ||
| 118 | newMethod(subClassAA, "a", "()V"), | ||
| 119 | newMethod(subClassB, "a", "()V") | ||
| 120 | )); | ||
| 121 | entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()V")); | 113 | entries = resolver.resolveEquivalentMethods(newMethod(subClassAA, "a", "()V")); |
| 122 | assertThat(entries, containsInAnyOrder( | 114 | assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V"))); |
| 123 | newMethod(baseClass, "a", "()V"), | ||
| 124 | newMethod(subClassAA, "a", "()V"), | ||
| 125 | newMethod(subClassB, "a", "()V") | ||
| 126 | )); | ||
| 127 | entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "a", "()V")); | 115 | entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "a", "()V")); |
| 128 | assertThat(entries, containsInAnyOrder( | 116 | assertThat(entries, containsInAnyOrder(newMethod(baseClass, "a", "()V"), newMethod(subClassAA, "a", "()V"), newMethod(subClassB, "a", "()V"))); |
| 129 | newMethod(baseClass, "a", "()V"), | ||
| 130 | newMethod(subClassAA, "a", "()V"), | ||
| 131 | newMethod(subClassB, "a", "()V") | ||
| 132 | )); | ||
| 133 | 117 | ||
| 134 | // doBThings | 118 | // doBThings |
| 135 | entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "b", "()V")); | 119 | entries = resolver.resolveEquivalentMethods(newMethod(subClassB, "b", "()V")); |
| @@ -143,55 +127,38 @@ public class TestJarIndexInheritanceTree { | |||
| 143 | 127 | ||
| 144 | // name | 128 | // name |
| 145 | references = index.getReferenceIndex().getReferencesToField(nameField); | 129 | references = index.getReferenceIndex().getReferencesToField(nameField); |
| 146 | assertThat(references, containsInAnyOrder( | 130 | assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(nameField, baseClass.getName(), "<init>", "(Ljava/lang/String;)V"), newFieldReferenceByMethod(nameField, baseClass.getName(), "a", "()Ljava/lang/String;"))); |
| 147 | newFieldReferenceByMethod(nameField, baseClass.getName(), "<init>", "(Ljava/lang/String;)V"), | ||
| 148 | newFieldReferenceByMethod(nameField, baseClass.getName(), "a", "()Ljava/lang/String;") | ||
| 149 | )); | ||
| 150 | 131 | ||
| 151 | // numThings | 132 | // numThings |
| 152 | references = index.getReferenceIndex().getReferencesToField(numThingsField); | 133 | references = index.getReferenceIndex().getReferencesToField(numThingsField); |
| 153 | assertThat(references, containsInAnyOrder( | 134 | assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(numThingsField, subClassB.getName(), "<init>", "()V"), newFieldReferenceByMethod(numThingsField, subClassB.getName(), "b", "()V"))); |
| 154 | newFieldReferenceByMethod(numThingsField, subClassB.getName(), "<init>", "()V"), | ||
| 155 | newFieldReferenceByMethod(numThingsField, subClassB.getName(), "b", "()V") | ||
| 156 | )); | ||
| 157 | } | 135 | } |
| 158 | 136 | ||
| 159 | @Test | 137 | @Test |
| 160 | @SuppressWarnings("unchecked") | 138 | @SuppressWarnings("unchecked") |
| 161 | public void behaviorReferences() { | 139 | public void behaviorReferences() { |
| 162 | |||
| 163 | MethodEntry source; | 140 | MethodEntry source; |
| 164 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references; | 141 | Collection<EntryReference<MethodEntry, MethodDefEntry>> references; |
| 165 | 142 | ||
| 166 | // baseClass constructor | 143 | // baseClass constructor |
| 167 | source = newMethod(baseClass, "<init>", "(Ljava/lang/String;)V"); | 144 | source = newMethod(baseClass, "<init>", "(Ljava/lang/String;)V"); |
| 168 | references = index.getReferenceIndex().getReferencesToMethod(source); | 145 | references = index.getReferenceIndex().getReferencesToMethod(source); |
| 169 | assertThat(references, containsInAnyOrder( | 146 | assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassA.getName(), "<init>", "(Ljava/lang/String;)V"), newBehaviorReferenceByMethod(source, subClassB.getName(), "<init>", "()V"))); |
| 170 | newBehaviorReferenceByMethod(source, subClassA.getName(), "<init>", "(Ljava/lang/String;)V"), | ||
| 171 | newBehaviorReferenceByMethod(source, subClassB.getName(), "<init>", "()V") | ||
| 172 | )); | ||
| 173 | 147 | ||
| 174 | // subClassA constructor | 148 | // subClassA constructor |
| 175 | source = newMethod(subClassA, "<init>", "(Ljava/lang/String;)V"); | 149 | source = newMethod(subClassA, "<init>", "(Ljava/lang/String;)V"); |
| 176 | references = index.getReferenceIndex().getReferencesToMethod(source); | 150 | references = index.getReferenceIndex().getReferencesToMethod(source); |
| 177 | assertThat(references, containsInAnyOrder( | 151 | assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "<init>", "()V"))); |
| 178 | newBehaviorReferenceByMethod(source, subClassAA.getName(), "<init>", "()V") | ||
| 179 | )); | ||
| 180 | 152 | ||
| 181 | // baseClass.getName() | 153 | // baseClass.getName() |
| 182 | source = newMethod(baseClass, "a", "()Ljava/lang/String;"); | 154 | source = newMethod(baseClass, "a", "()Ljava/lang/String;"); |
| 183 | references = index.getReferenceIndex().getReferencesToMethod(source); | 155 | references = index.getReferenceIndex().getReferencesToMethod(source); |
| 184 | assertThat(references, containsInAnyOrder( | 156 | assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()Ljava/lang/String;"), newBehaviorReferenceByMethod(source, subClassB.getName(), "a", "()V"))); |
| 185 | newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()Ljava/lang/String;"), | ||
| 186 | newBehaviorReferenceByMethod(source, subClassB.getName(), "a", "()V") | ||
| 187 | )); | ||
| 188 | 157 | ||
| 189 | // subclassAA.getName() | 158 | // subclassAA.getName() |
| 190 | source = newMethod(subClassAA, "a", "()Ljava/lang/String;"); | 159 | source = newMethod(subClassAA, "a", "()Ljava/lang/String;"); |
| 191 | references = index.getReferenceIndex().getReferencesToMethod(source); | 160 | references = index.getReferenceIndex().getReferencesToMethod(source); |
| 192 | assertThat(references, containsInAnyOrder( | 161 | assertThat(references, containsInAnyOrder(newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()V"))); |
| 193 | newBehaviorReferenceByMethod(source, subClassAA.getName(), "a", "()V") | ||
| 194 | )); | ||
| 195 | } | 162 | } |
| 196 | 163 | ||
| 197 | @Test | 164 | @Test |
| @@ -225,6 +192,5 @@ public class TestJarIndexInheritanceTree { | |||
| 225 | assertThat(entryIndex.hasMethod(newMethod(subClassA, "b", "()V")), is(false)); | 192 | assertThat(entryIndex.hasMethod(newMethod(subClassA, "b", "()V")), is(false)); |
| 226 | assertThat(entryIndex.hasMethod(newMethod(subClassAA, "b", "()V")), is(false)); | 193 | assertThat(entryIndex.hasMethod(newMethod(subClassAA, "b", "()V")), is(false)); |
| 227 | assertThat(entryIndex.hasMethod(newMethod(subClassB, "b", "()V")), is(true)); | 194 | assertThat(entryIndex.hasMethod(newMethod(subClassB, "b", "()V")), is(true)); |
| 228 | |||
| 229 | } | 195 | } |
| 230 | } | 196 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java index 6e3755ca..dcbe95f3 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java +++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java | |||
| @@ -1,17 +1,41 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.analysis.*; | 14 | import static cuchaz.enigma.TestEntryFactory.newClass; |
| 15 | import static cuchaz.enigma.TestEntryFactory.newField; | ||
| 16 | import static cuchaz.enigma.TestEntryFactory.newFieldReferenceByMethod; | ||
| 17 | import static cuchaz.enigma.TestEntryFactory.newMethod; | ||
| 18 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 19 | import static org.hamcrest.Matchers.containsInAnyOrder; | ||
| 20 | import static org.hamcrest.Matchers.empty; | ||
| 21 | import static org.hamcrest.Matchers.hasSize; | ||
| 22 | import static org.hamcrest.Matchers.is; | ||
| 23 | import static org.hamcrest.Matchers.not; | ||
| 24 | import static org.hamcrest.Matchers.nullValue; | ||
| 25 | |||
| 26 | import java.nio.file.Path; | ||
| 27 | import java.nio.file.Paths; | ||
| 28 | import java.util.Collection; | ||
| 29 | import java.util.List; | ||
| 30 | |||
| 31 | import org.junit.Test; | ||
| 32 | |||
| 33 | import cuchaz.enigma.analysis.ClassImplementationsTreeNode; | ||
| 34 | import cuchaz.enigma.analysis.ClassInheritanceTreeNode; | ||
| 35 | import cuchaz.enigma.analysis.EntryReference; | ||
| 36 | import cuchaz.enigma.analysis.IndexTreeBuilder; | ||
| 37 | import cuchaz.enigma.analysis.MethodImplementationsTreeNode; | ||
| 38 | import cuchaz.enigma.analysis.MethodInheritanceTreeNode; | ||
| 15 | import cuchaz.enigma.analysis.index.EntryIndex; | 39 | import cuchaz.enigma.analysis.index.EntryIndex; |
| 16 | import cuchaz.enigma.analysis.index.InheritanceIndex; | 40 | import cuchaz.enigma.analysis.index.InheritanceIndex; |
| 17 | import cuchaz.enigma.analysis.index.JarIndex; | 41 | import cuchaz.enigma.analysis.index.JarIndex; |
| @@ -23,19 +47,8 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry; | |||
| 23 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 47 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 24 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; | 48 | import cuchaz.enigma.translation.representation.entry.MethodDefEntry; |
| 25 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 49 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 26 | import org.junit.Test; | ||
| 27 | |||
| 28 | import java.nio.file.Path; | ||
| 29 | import java.nio.file.Paths; | ||
| 30 | import java.util.Collection; | ||
| 31 | import java.util.List; | ||
| 32 | |||
| 33 | import static cuchaz.enigma.TestEntryFactory.*; | ||
| 34 | import static org.hamcrest.MatcherAssert.assertThat; | ||
| 35 | import static org.hamcrest.Matchers.*; | ||
| 36 | 50 | ||
| 37 | public class TestJarIndexLoneClass { | 51 | public class TestJarIndexLoneClass { |
| 38 | |||
| 39 | public static final Path JAR = Paths.get("build/test-obf/loneClass.jar"); | 52 | public static final Path JAR = Paths.get("build/test-obf/loneClass.jar"); |
| 40 | private JarIndex index; | 53 | private JarIndex index; |
| 41 | 54 | ||
| @@ -47,10 +60,7 @@ public class TestJarIndexLoneClass { | |||
| 47 | 60 | ||
| 48 | @Test | 61 | @Test |
| 49 | public void obfEntries() { | 62 | public void obfEntries() { |
| 50 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder( | 63 | assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder(newClass("cuchaz/enigma/inputs/Keep"), newClass("a"))); |
| 51 | newClass("cuchaz/enigma/inputs/Keep"), | ||
| 52 | newClass("a") | ||
| 53 | )); | ||
| 54 | } | 64 | } |
| 55 | 65 | ||
| 56 | @Test | 66 | @Test |
| @@ -112,9 +122,7 @@ public class TestJarIndexLoneClass { | |||
| 112 | @Test | 122 | @Test |
| 113 | public void relatedMethodImplementations() { | 123 | public void relatedMethodImplementations() { |
| 114 | Collection<MethodEntry> entries = index.getEntryResolver().resolveEquivalentMethods(newMethod("a", "a", "()Ljava/lang/String;")); | 124 | Collection<MethodEntry> entries = index.getEntryResolver().resolveEquivalentMethods(newMethod("a", "a", "()Ljava/lang/String;")); |
| 115 | assertThat(entries, containsInAnyOrder( | 125 | assertThat(entries, containsInAnyOrder(newMethod("a", "a", "()Ljava/lang/String;"))); |
| 116 | newMethod("a", "a", "()Ljava/lang/String;") | ||
| 117 | )); | ||
| 118 | } | 126 | } |
| 119 | 127 | ||
| 120 | @Test | 128 | @Test |
| @@ -122,10 +130,7 @@ public class TestJarIndexLoneClass { | |||
| 122 | public void fieldReferences() { | 130 | public void fieldReferences() { |
| 123 | FieldEntry source = newField("a", "a", "Ljava/lang/String;"); | 131 | FieldEntry source = newField("a", "a", "Ljava/lang/String;"); |
| 124 | Collection<EntryReference<FieldEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToField(source); | 132 | Collection<EntryReference<FieldEntry, MethodDefEntry>> references = index.getReferenceIndex().getReferencesToField(source); |
| 125 | assertThat(references, containsInAnyOrder( | 133 | assertThat(references, containsInAnyOrder(newFieldReferenceByMethod(source, "a", "<init>", "(Ljava/lang/String;)V"), newFieldReferenceByMethod(source, "a", "a", "()Ljava/lang/String;"))); |
| 126 | newFieldReferenceByMethod(source, "a", "<init>", "(Ljava/lang/String;)V"), | ||
| 127 | newFieldReferenceByMethod(source, "a", "a", "()Ljava/lang/String;") | ||
| 128 | )); | ||
| 129 | } | 134 | } |
| 130 | 135 | ||
| 131 | @Test | 136 | @Test |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java b/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java index a73880dd..918466b4 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java +++ b/enigma/src/test/java/cuchaz/enigma/TestMethodDescriptor.java | |||
| @@ -1,25 +1,28 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.MethodDescriptor; | 14 | import static org.hamcrest.MatcherAssert.assertThat; |
| 15 | import cuchaz.enigma.translation.representation.TypeDescriptor; | 15 | import static org.hamcrest.Matchers.contains; |
| 16 | import static org.hamcrest.Matchers.empty; | ||
| 17 | import static org.hamcrest.Matchers.is; | ||
| 18 | import static org.hamcrest.Matchers.not; | ||
| 19 | |||
| 16 | import org.junit.Test; | 20 | import org.junit.Test; |
| 17 | 21 | ||
| 18 | import static org.hamcrest.MatcherAssert.assertThat; | 22 | import cuchaz.enigma.translation.representation.MethodDescriptor; |
| 19 | import static org.hamcrest.Matchers.*; | 23 | import cuchaz.enigma.translation.representation.TypeDescriptor; |
| 20 | 24 | ||
| 21 | public class TestMethodDescriptor { | 25 | public class TestMethodDescriptor { |
| 22 | |||
| 23 | @Test | 26 | @Test |
| 24 | public void easiest() { | 27 | public void easiest() { |
| 25 | final MethodDescriptor sig = new MethodDescriptor("()V"); | 28 | final MethodDescriptor sig = new MethodDescriptor("()V"); |
| @@ -31,26 +34,19 @@ public class TestMethodDescriptor { | |||
| 31 | public void primitives() { | 34 | public void primitives() { |
| 32 | { | 35 | { |
| 33 | final MethodDescriptor sig = new MethodDescriptor("(I)V"); | 36 | final MethodDescriptor sig = new MethodDescriptor("(I)V"); |
| 34 | assertThat(sig.getArgumentDescs(), contains( | 37 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"))); |
| 35 | new TypeDescriptor("I") | ||
| 36 | )); | ||
| 37 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); | 38 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); |
| 38 | } | 39 | } |
| 40 | |||
| 39 | { | 41 | { |
| 40 | final MethodDescriptor sig = new MethodDescriptor("(I)I"); | 42 | final MethodDescriptor sig = new MethodDescriptor("(I)I"); |
| 41 | assertThat(sig.getArgumentDescs(), contains( | 43 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"))); |
| 42 | new TypeDescriptor("I") | ||
| 43 | )); | ||
| 44 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("I"))); | 44 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("I"))); |
| 45 | } | 45 | } |
| 46 | |||
| 46 | { | 47 | { |
| 47 | final MethodDescriptor sig = new MethodDescriptor("(IBCJ)Z"); | 48 | final MethodDescriptor sig = new MethodDescriptor("(IBCJ)Z"); |
| 48 | assertThat(sig.getArgumentDescs(), contains( | 49 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("B"), new TypeDescriptor("C"), new TypeDescriptor("J"))); |
| 49 | new TypeDescriptor("I"), | ||
| 50 | new TypeDescriptor("B"), | ||
| 51 | new TypeDescriptor("C"), | ||
| 52 | new TypeDescriptor("J") | ||
| 53 | )); | ||
| 54 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); | 50 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); |
| 55 | } | 51 | } |
| 56 | } | 52 | } |
| @@ -63,20 +59,16 @@ public class TestMethodDescriptor { | |||
| 63 | assertThat(sig.getArgumentDescs().get(0), is(new TypeDescriptor("[LFoo;"))); | 59 | assertThat(sig.getArgumentDescs().get(0), is(new TypeDescriptor("[LFoo;"))); |
| 64 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); | 60 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); |
| 65 | } | 61 | } |
| 62 | |||
| 66 | { | 63 | { |
| 67 | final MethodDescriptor sig = new MethodDescriptor("(LFoo;)LBar;"); | 64 | final MethodDescriptor sig = new MethodDescriptor("(LFoo;)LBar;"); |
| 68 | assertThat(sig.getArgumentDescs(), contains( | 65 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;"))); |
| 69 | new TypeDescriptor("LFoo;") | ||
| 70 | )); | ||
| 71 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); | 66 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); |
| 72 | } | 67 | } |
| 68 | |||
| 73 | { | 69 | { |
| 74 | final MethodDescriptor sig = new MethodDescriptor("(LFoo;LMoo;LZoo;)LBar;"); | 70 | final MethodDescriptor sig = new MethodDescriptor("(LFoo;LMoo;LZoo;)LBar;"); |
| 75 | assertThat(sig.getArgumentDescs(), contains( | 71 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;"), new TypeDescriptor("LMoo;"), new TypeDescriptor("LZoo;"))); |
| 76 | new TypeDescriptor("LFoo;"), | ||
| 77 | new TypeDescriptor("LMoo;"), | ||
| 78 | new TypeDescriptor("LZoo;") | ||
| 79 | )); | ||
| 80 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); | 72 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LBar;"))); |
| 81 | } | 73 | } |
| 82 | } | 74 | } |
| @@ -85,25 +77,19 @@ public class TestMethodDescriptor { | |||
| 85 | public void arrays() { | 77 | public void arrays() { |
| 86 | { | 78 | { |
| 87 | final MethodDescriptor sig = new MethodDescriptor("([I)V"); | 79 | final MethodDescriptor sig = new MethodDescriptor("([I)V"); |
| 88 | assertThat(sig.getArgumentDescs(), contains( | 80 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I"))); |
| 89 | new TypeDescriptor("[I") | ||
| 90 | )); | ||
| 91 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); | 81 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); |
| 92 | } | 82 | } |
| 83 | |||
| 93 | { | 84 | { |
| 94 | final MethodDescriptor sig = new MethodDescriptor("([I)[J"); | 85 | final MethodDescriptor sig = new MethodDescriptor("([I)[J"); |
| 95 | assertThat(sig.getArgumentDescs(), contains( | 86 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I"))); |
| 96 | new TypeDescriptor("[I") | ||
| 97 | )); | ||
| 98 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[J"))); | 87 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[J"))); |
| 99 | } | 88 | } |
| 89 | |||
| 100 | { | 90 | { |
| 101 | final MethodDescriptor sig = new MethodDescriptor("([I[Z[F)[D"); | 91 | final MethodDescriptor sig = new MethodDescriptor("([I[Z[F)[D"); |
| 102 | assertThat(sig.getArgumentDescs(), contains( | 92 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[I"), new TypeDescriptor("[Z"), new TypeDescriptor("[F"))); |
| 103 | new TypeDescriptor("[I"), | ||
| 104 | new TypeDescriptor("[Z"), | ||
| 105 | new TypeDescriptor("[F") | ||
| 106 | )); | ||
| 107 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[D"))); | 93 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[D"))); |
| 108 | } | 94 | } |
| 109 | } | 95 | } |
| @@ -112,20 +98,13 @@ public class TestMethodDescriptor { | |||
| 112 | public void mixed() { | 98 | public void mixed() { |
| 113 | { | 99 | { |
| 114 | final MethodDescriptor sig = new MethodDescriptor("(I[JLFoo;)Z"); | 100 | final MethodDescriptor sig = new MethodDescriptor("(I[JLFoo;)Z"); |
| 115 | assertThat(sig.getArgumentDescs(), contains( | 101 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("[J"), new TypeDescriptor("LFoo;"))); |
| 116 | new TypeDescriptor("I"), | ||
| 117 | new TypeDescriptor("[J"), | ||
| 118 | new TypeDescriptor("LFoo;") | ||
| 119 | )); | ||
| 120 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); | 102 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("Z"))); |
| 121 | } | 103 | } |
| 104 | |||
| 122 | { | 105 | { |
| 123 | final MethodDescriptor sig = new MethodDescriptor("(III)[LFoo;"); | 106 | final MethodDescriptor sig = new MethodDescriptor("(III)[LFoo;"); |
| 124 | assertThat(sig.getArgumentDescs(), contains( | 107 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("I"), new TypeDescriptor("I"))); |
| 125 | new TypeDescriptor("I"), | ||
| 126 | new TypeDescriptor("I"), | ||
| 127 | new TypeDescriptor("I") | ||
| 128 | )); | ||
| 129 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[LFoo;"))); | 108 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[LFoo;"))); |
| 130 | } | 109 | } |
| 131 | } | 110 | } |
| @@ -138,42 +117,37 @@ public class TestMethodDescriptor { | |||
| 138 | assertThat(sig.getArgumentDescs(), is(empty())); | 117 | assertThat(sig.getArgumentDescs(), is(empty())); |
| 139 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); | 118 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); |
| 140 | } | 119 | } |
| 120 | |||
| 141 | { | 121 | { |
| 142 | final MethodDescriptor oldSig = new MethodDescriptor("(IJLFoo;)V"); | 122 | final MethodDescriptor oldSig = new MethodDescriptor("(IJLFoo;)V"); |
| 143 | final MethodDescriptor sig = oldSig.remap(s -> null); | 123 | final MethodDescriptor sig = oldSig.remap(s -> null); |
| 144 | assertThat(sig.getArgumentDescs(), contains( | 124 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("I"), new TypeDescriptor("J"), new TypeDescriptor("LFoo;"))); |
| 145 | new TypeDescriptor("I"), | ||
| 146 | new TypeDescriptor("J"), | ||
| 147 | new TypeDescriptor("LFoo;") | ||
| 148 | )); | ||
| 149 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); | 125 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("V"))); |
| 150 | } | 126 | } |
| 127 | |||
| 151 | { | 128 | { |
| 152 | final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); | 129 | final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); |
| 153 | final MethodDescriptor sig = oldSig.remap(s -> { | 130 | final MethodDescriptor sig = oldSig.remap(s -> { |
| 154 | if (s.equals("Foo")) { | 131 | if (s.equals("Foo")) { |
| 155 | return "Bar"; | 132 | return "Bar"; |
| 156 | } | 133 | } |
| 134 | |||
| 157 | return null; | 135 | return null; |
| 158 | }); | 136 | }); |
| 159 | assertThat(sig.getArgumentDescs(), contains( | 137 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LBar;"), new TypeDescriptor("LBar;"))); |
| 160 | new TypeDescriptor("LBar;"), | ||
| 161 | new TypeDescriptor("LBar;") | ||
| 162 | )); | ||
| 163 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LMoo;"))); | 138 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LMoo;"))); |
| 164 | } | 139 | } |
| 140 | |||
| 165 | { | 141 | { |
| 166 | final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); | 142 | final MethodDescriptor oldSig = new MethodDescriptor("(LFoo;LBar;)LMoo;"); |
| 167 | final MethodDescriptor sig = oldSig.remap(s -> { | 143 | final MethodDescriptor sig = oldSig.remap(s -> { |
| 168 | if (s.equals("Moo")) { | 144 | if (s.equals("Moo")) { |
| 169 | return "Cow"; | 145 | return "Cow"; |
| 170 | } | 146 | } |
| 147 | |||
| 171 | return null; | 148 | return null; |
| 172 | }); | 149 | }); |
| 173 | assertThat(sig.getArgumentDescs(), contains( | 150 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("LFoo;"), new TypeDescriptor("LBar;"))); |
| 174 | new TypeDescriptor("LFoo;"), | ||
| 175 | new TypeDescriptor("LBar;") | ||
| 176 | )); | ||
| 177 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LCow;"))); | 151 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("LCow;"))); |
| 178 | } | 152 | } |
| 179 | } | 153 | } |
| @@ -188,18 +162,16 @@ public class TestMethodDescriptor { | |||
| 188 | } else if (s.equals("Bar")) { | 162 | } else if (s.equals("Bar")) { |
| 189 | return "Beer"; | 163 | return "Beer"; |
| 190 | } | 164 | } |
| 165 | |||
| 191 | return null; | 166 | return null; |
| 192 | }); | 167 | }); |
| 193 | assertThat(sig.getArgumentDescs(), contains( | 168 | assertThat(sig.getArgumentDescs(), contains(new TypeDescriptor("[LFood;"))); |
| 194 | new TypeDescriptor("[LFood;") | ||
| 195 | )); | ||
| 196 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[[[LBeer;"))); | 169 | assertThat(sig.getReturnDesc(), is(new TypeDescriptor("[[[LBeer;"))); |
| 197 | } | 170 | } |
| 198 | } | 171 | } |
| 199 | 172 | ||
| 200 | @Test | 173 | @Test |
| 201 | public void equals() { | 174 | public void equals() { |
| 202 | |||
| 203 | // base | 175 | // base |
| 204 | assertThat(new MethodDescriptor("()V"), is(new MethodDescriptor("()V"))); | 176 | assertThat(new MethodDescriptor("()V"), is(new MethodDescriptor("()V"))); |
| 205 | 177 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java b/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java index a5e8367b..8017ab61 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java +++ b/enigma/src/test/java/cuchaz/enigma/TestTokensConstructors.java | |||
| @@ -1,31 +1,33 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 15 | import org.junit.Ignore; | ||
| 16 | import org.junit.Test; | ||
| 17 | |||
| 18 | import java.nio.file.Paths; | ||
| 19 | |||
| 20 | import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod; | 14 | import static cuchaz.enigma.TestEntryFactory.newBehaviorReferenceByMethod; |
| 21 | import static cuchaz.enigma.TestEntryFactory.newMethod; | 15 | import static cuchaz.enigma.TestEntryFactory.newMethod; |
| 22 | import static org.hamcrest.MatcherAssert.assertThat; | 16 | import static org.hamcrest.MatcherAssert.assertThat; |
| 23 | import static org.hamcrest.Matchers.*; | 17 | import static org.hamcrest.Matchers.containsInAnyOrder; |
| 18 | import static org.hamcrest.Matchers.empty; | ||
| 19 | import static org.hamcrest.Matchers.is; | ||
| 20 | import static org.hamcrest.Matchers.nullValue; | ||
| 24 | 21 | ||
| 25 | public class TestTokensConstructors extends TokenChecker { | 22 | import java.nio.file.Paths; |
| 23 | |||
| 24 | import org.junit.Ignore; | ||
| 25 | import org.junit.Test; | ||
| 26 | |||
| 27 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | ||
| 26 | 28 | ||
| 27 | public TestTokensConstructors() | 29 | public class TestTokensConstructors extends TokenChecker { |
| 28 | throws Exception { | 30 | public TestTokensConstructors() throws Exception { |
| 29 | super(Paths.get("build/test-obf/constructors.jar")); | 31 | super(Paths.get("build/test-obf/constructors.jar")); |
| 30 | } | 32 | } |
| 31 | 33 | ||
| @@ -57,17 +59,10 @@ public class TestTokensConstructors extends TokenChecker { | |||
| 57 | @Ignore // TODO needs fixing, broke when compiling against J16 | 59 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 58 | public void baseDefaultReferences() { | 60 | public void baseDefaultReferences() { |
| 59 | MethodEntry source = newMethod("a", "<init>", "()V"); | 61 | MethodEntry source = newMethod("a", "<init>", "()V"); |
| 60 | assertThat( | 62 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "a", "()V")), containsInAnyOrder("a")); |
| 61 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "a", "()V")), | 63 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "()V")), is(empty()) // implicit call, not decompiled to token |
| 62 | containsInAnyOrder("a") | ||
| 63 | ); | ||
| 64 | assertThat( | ||
| 65 | getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "()V")), | ||
| 66 | is(empty()) // implicit call, not decompiled to token | ||
| 67 | ); | 64 | ); |
| 68 | assertThat( | 65 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(III)V")), is(empty()) // implicit call, not decompiled to token |
| 69 | getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(III)V")), | ||
| 70 | is(empty()) // implicit call, not decompiled to token | ||
| 71 | ); | 66 | ); |
| 72 | } | 67 | } |
| 73 | 68 | ||
| @@ -75,71 +70,44 @@ public class TestTokensConstructors extends TokenChecker { | |||
| 75 | @Ignore // TODO needs fixing, broke when compiling against J16 | 70 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 76 | public void baseIntReferences() { | 71 | public void baseIntReferences() { |
| 77 | MethodEntry source = newMethod("a", "<init>", "(I)V"); | 72 | MethodEntry source = newMethod("a", "<init>", "(I)V"); |
| 78 | assertThat( | 73 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "b", "()V")), containsInAnyOrder("a")); |
| 79 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "b", "()V")), | ||
| 80 | containsInAnyOrder("a") | ||
| 81 | ); | ||
| 82 | } | 74 | } |
| 83 | 75 | ||
| 84 | @Test | 76 | @Test |
| 85 | @Ignore // TODO needs fixing, broke when compiling against J16 | 77 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 86 | public void subDefaultReferences() { | 78 | public void subDefaultReferences() { |
| 87 | MethodEntry source = newMethod("d", "<init>", "()V"); | 79 | MethodEntry source = newMethod("d", "<init>", "()V"); |
| 88 | assertThat( | 80 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "c", "()V")), containsInAnyOrder("d")); |
| 89 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "c", "()V")), | 81 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(I)V")), containsInAnyOrder("this")); |
| 90 | containsInAnyOrder("d") | ||
| 91 | ); | ||
| 92 | assertThat( | ||
| 93 | getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(I)V")), | ||
| 94 | containsInAnyOrder("this") | ||
| 95 | ); | ||
| 96 | } | 82 | } |
| 97 | 83 | ||
| 98 | @Test | 84 | @Test |
| 99 | @Ignore // TODO needs fixing, broke when compiling against J16 | 85 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 100 | public void subIntReferences() { | 86 | public void subIntReferences() { |
| 101 | MethodEntry source = newMethod("d", "<init>", "(I)V"); | 87 | MethodEntry source = newMethod("d", "<init>", "(I)V"); |
| 102 | assertThat(getReferenceTokens( | 88 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "d", "()V")), containsInAnyOrder("d")); |
| 103 | newBehaviorReferenceByMethod(source, "b", "d", "()V")), | 89 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "d", "<init>", "(II)V")), containsInAnyOrder("this")); |
| 104 | containsInAnyOrder("d") | 90 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "e", "<init>", "(I)V")), containsInAnyOrder("super")); |
| 105 | ); | ||
| 106 | assertThat(getReferenceTokens( | ||
| 107 | newBehaviorReferenceByMethod(source, "d", "<init>", "(II)V")), | ||
| 108 | containsInAnyOrder("this") | ||
| 109 | ); | ||
| 110 | assertThat(getReferenceTokens( | ||
| 111 | newBehaviorReferenceByMethod(source, "e", "<init>", "(I)V")), | ||
| 112 | containsInAnyOrder("super") | ||
| 113 | ); | ||
| 114 | } | 91 | } |
| 115 | 92 | ||
| 116 | @Test | 93 | @Test |
| 117 | @Ignore // TODO needs fixing, broke when compiling against J16 | 94 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 118 | public void subIntIntReferences() { | 95 | public void subIntIntReferences() { |
| 119 | MethodEntry source = newMethod("d", "<init>", "(II)V"); | 96 | MethodEntry source = newMethod("d", "<init>", "(II)V"); |
| 120 | assertThat( | 97 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "e", "()V")), containsInAnyOrder("d")); |
| 121 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "e", "()V")), | ||
| 122 | containsInAnyOrder("d") | ||
| 123 | ); | ||
| 124 | } | 98 | } |
| 125 | 99 | ||
| 126 | @Test | 100 | @Test |
| 127 | @Ignore // TODO needs fixing, broke when compiling against J16 | 101 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 128 | public void subsubIntReferences() { | 102 | public void subsubIntReferences() { |
| 129 | MethodEntry source = newMethod("e", "<init>", "(I)V"); | 103 | MethodEntry source = newMethod("e", "<init>", "(I)V"); |
| 130 | assertThat( | 104 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "f", "()V")), containsInAnyOrder("e")); |
| 131 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "f", "()V")), | ||
| 132 | containsInAnyOrder("e") | ||
| 133 | ); | ||
| 134 | } | 105 | } |
| 135 | 106 | ||
| 136 | @Test | 107 | @Test |
| 137 | @Ignore // TODO needs fixing, broke when compiling against J16 | 108 | @Ignore // TODO needs fixing, broke when compiling against J16 |
| 138 | public void defaultConstructableReferences() { | 109 | public void defaultConstructableReferences() { |
| 139 | MethodEntry source = newMethod("c", "<init>", "()V"); | 110 | MethodEntry source = newMethod("c", "<init>", "()V"); |
| 140 | assertThat( | 111 | assertThat(getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "g", "()V")), containsInAnyOrder("c")); |
| 141 | getReferenceTokens(newBehaviorReferenceByMethod(source, "b", "g", "()V")), | ||
| 142 | containsInAnyOrder("c") | ||
| 143 | ); | ||
| 144 | } | 112 | } |
| 145 | } | 113 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTranslator.java b/enigma/src/test/java/cuchaz/enigma/TestTranslator.java index a420afe1..93b70176 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestTranslator.java +++ b/enigma/src/test/java/cuchaz/enigma/TestTranslator.java | |||
| @@ -1,27 +1,28 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.entry.Entry; | 14 | import static cuchaz.enigma.TestEntryFactory.newClass; |
| 15 | import static cuchaz.enigma.TestEntryFactory.newField; | ||
| 16 | import static cuchaz.enigma.TestEntryFactory.newMethod; | ||
| 17 | |||
| 15 | import org.junit.BeforeClass; | 18 | import org.junit.BeforeClass; |
| 16 | import org.junit.Test; | 19 | import org.junit.Test; |
| 17 | 20 | ||
| 18 | import static cuchaz.enigma.TestEntryFactory.*; | 21 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 19 | 22 | ||
| 20 | public class TestTranslator { | 23 | public class TestTranslator { |
| 21 | |||
| 22 | @BeforeClass | 24 | @BeforeClass |
| 23 | public static void beforeClass() | 25 | public static void beforeClass() throws Exception { |
| 24 | throws Exception { | ||
| 25 | //TODO FIx | 26 | //TODO FIx |
| 26 | //deobfuscator = new Enigma(new JarFile("build/test-obf/translation.jar")); | 27 | //deobfuscator = new Enigma(new JarFile("build/test-obf/translation.jar")); |
| 27 | //try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { | 28 | //try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { |
| @@ -94,7 +95,6 @@ public class TestTranslator { | |||
| 94 | 95 | ||
| 95 | @Test | 96 | @Test |
| 96 | public void innerClasses() { | 97 | public void innerClasses() { |
| 97 | |||
| 98 | // classes | 98 | // classes |
| 99 | assertMapping(newClass("g"), newClass("deobf/G_OuterClass")); | 99 | assertMapping(newClass("g"), newClass("deobf/G_OuterClass")); |
| 100 | assertMapping(newClass("g$a"), newClass("deobf/G_OuterClass$A_InnerClass")); | 100 | assertMapping(newClass("g$a"), newClass("deobf/G_OuterClass$A_InnerClass")); |
| @@ -120,7 +120,6 @@ public class TestTranslator { | |||
| 120 | 120 | ||
| 121 | @Test | 121 | @Test |
| 122 | public void testGenerics() { | 122 | public void testGenerics() { |
| 123 | |||
| 124 | // classes | 123 | // classes |
| 125 | assertMapping(newClass("i"), newClass("deobf/I_Generics")); | 124 | assertMapping(newClass("i"), newClass("deobf/I_Generics")); |
| 126 | assertMapping(newClass("i$a"), newClass("deobf/I_Generics$A_Type")); | 125 | assertMapping(newClass("i$a"), newClass("deobf/I_Generics$A_Type")); |
diff --git a/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java b/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java index b9ebe559..280dadc9 100644 --- a/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java +++ b/enigma/src/test/java/cuchaz/enigma/TestTypeDescriptor.java | |||
| @@ -1,26 +1,26 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 15 | import org.junit.Test; | ||
| 16 | |||
| 17 | import static cuchaz.enigma.TestEntryFactory.newClass; | 14 | import static cuchaz.enigma.TestEntryFactory.newClass; |
| 18 | import static org.hamcrest.MatcherAssert.assertThat; | 15 | import static org.hamcrest.MatcherAssert.assertThat; |
| 19 | import static org.hamcrest.Matchers.is; | 16 | import static org.hamcrest.Matchers.is; |
| 20 | import static org.hamcrest.Matchers.not; | 17 | import static org.hamcrest.Matchers.not; |
| 21 | 18 | ||
| 22 | public class TestTypeDescriptor { | 19 | import org.junit.Test; |
| 23 | 20 | ||
| 21 | import cuchaz.enigma.translation.representation.TypeDescriptor; | ||
| 22 | |||
| 23 | public class TestTypeDescriptor { | ||
| 24 | @Test | 24 | @Test |
| 25 | public void isVoid() { | 25 | public void isVoid() { |
| 26 | assertThat(new TypeDescriptor("V").isVoid(), is(true)); | 26 | assertThat(new TypeDescriptor("V").isVoid(), is(true)); |
| @@ -161,6 +161,7 @@ public class TestTypeDescriptor { | |||
| 161 | assertThat(TypeDescriptor.parseFirst("LFoo;LFoo;"), is(answer)); | 161 | assertThat(TypeDescriptor.parseFirst("LFoo;LFoo;"), is(answer)); |
| 162 | assertThat(TypeDescriptor.parseFirst("LFoo;[LFoo;"), is(answer)); | 162 | assertThat(TypeDescriptor.parseFirst("LFoo;[LFoo;"), is(answer)); |
| 163 | } | 163 | } |
| 164 | |||
| 164 | { | 165 | { |
| 165 | final String answer = "Ljava/lang/String;"; | 166 | final String answer = "Ljava/lang/String;"; |
| 166 | assertThat(TypeDescriptor.parseFirst("Ljava/lang/String;"), is(answer)); | 167 | assertThat(TypeDescriptor.parseFirst("Ljava/lang/String;"), is(answer)); |
| @@ -182,6 +183,7 @@ public class TestTypeDescriptor { | |||
| 182 | assertThat(TypeDescriptor.parseFirst("[I[I"), is(answer)); | 183 | assertThat(TypeDescriptor.parseFirst("[I[I"), is(answer)); |
| 183 | assertThat(TypeDescriptor.parseFirst("[ILFoo;"), is(answer)); | 184 | assertThat(TypeDescriptor.parseFirst("[ILFoo;"), is(answer)); |
| 184 | } | 185 | } |
| 186 | |||
| 185 | { | 187 | { |
| 186 | final String answer = "[[I"; | 188 | final String answer = "[[I"; |
| 187 | assertThat(TypeDescriptor.parseFirst("[[I"), is(answer)); | 189 | assertThat(TypeDescriptor.parseFirst("[[I"), is(answer)); |
| @@ -190,6 +192,7 @@ public class TestTypeDescriptor { | |||
| 190 | assertThat(TypeDescriptor.parseFirst("[[I[I"), is(answer)); | 192 | assertThat(TypeDescriptor.parseFirst("[[I[I"), is(answer)); |
| 191 | assertThat(TypeDescriptor.parseFirst("[[ILFoo;"), is(answer)); | 193 | assertThat(TypeDescriptor.parseFirst("[[ILFoo;"), is(answer)); |
| 192 | } | 194 | } |
| 195 | |||
| 193 | { | 196 | { |
| 194 | final String answer = "[LFoo;"; | 197 | final String answer = "[LFoo;"; |
| 195 | assertThat(TypeDescriptor.parseFirst("[LFoo;"), is(answer)); | 198 | assertThat(TypeDescriptor.parseFirst("[LFoo;"), is(answer)); |
diff --git a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java index fb3a8da5..5f510a42 100644 --- a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java +++ b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java | |||
| @@ -1,28 +1,34 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.nio.file.Path; | ||
| 16 | import java.util.Collection; | ||
| 17 | import java.util.List; | ||
| 18 | |||
| 14 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
| 20 | |||
| 15 | import cuchaz.enigma.analysis.EntryReference; | 21 | import cuchaz.enigma.analysis.EntryReference; |
| 16 | import cuchaz.enigma.classprovider.CachingClassProvider; | 22 | import cuchaz.enigma.classprovider.CachingClassProvider; |
| 17 | import cuchaz.enigma.classprovider.JarClassProvider; | 23 | import cuchaz.enigma.classprovider.JarClassProvider; |
| 18 | import cuchaz.enigma.source.*; | 24 | import cuchaz.enigma.source.Decompiler; |
| 25 | import cuchaz.enigma.source.Decompilers; | ||
| 26 | import cuchaz.enigma.source.Source; | ||
| 27 | import cuchaz.enigma.source.SourceIndex; | ||
| 28 | import cuchaz.enigma.source.SourceSettings; | ||
| 29 | import cuchaz.enigma.source.Token; | ||
| 19 | import cuchaz.enigma.translation.representation.entry.Entry; | 30 | import cuchaz.enigma.translation.representation.entry.Entry; |
| 20 | 31 | ||
| 21 | import java.io.IOException; | ||
| 22 | import java.nio.file.Path; | ||
| 23 | import java.util.Collection; | ||
| 24 | import java.util.List; | ||
| 25 | |||
| 26 | public class TokenChecker { | 32 | public class TokenChecker { |
| 27 | private final Decompiler decompiler; | 33 | private final Decompiler decompiler; |
| 28 | 34 | ||
| @@ -41,9 +47,11 @@ public class TokenChecker { | |||
| 41 | 47 | ||
| 42 | // get the token value | 48 | // get the token value |
| 43 | Token token = index.getDeclarationToken(entry); | 49 | Token token = index.getDeclarationToken(entry); |
| 50 | |||
| 44 | if (token == null) { | 51 | if (token == null) { |
| 45 | return null; | 52 | return null; |
| 46 | } | 53 | } |
| 54 | |||
| 47 | return string.substring(token.start, token.end); | 55 | return string.substring(token.start, token.end); |
| 48 | } | 56 | } |
| 49 | 57 | ||
| @@ -56,9 +64,11 @@ public class TokenChecker { | |||
| 56 | 64 | ||
| 57 | // get the token values | 65 | // get the token values |
| 58 | List<String> values = Lists.newArrayList(); | 66 | List<String> values = Lists.newArrayList(); |
| 67 | |||
| 59 | for (Token token : index.getReferenceTokens((EntryReference<Entry<?>, Entry<?>>) reference)) { | 68 | for (Token token : index.getReferenceTokens((EntryReference<Entry<?>, Entry<?>>) reference)) { |
| 60 | values.add(string.substring(token.start, token.end)); | 69 | values.add(string.substring(token.start, token.end)); |
| 61 | } | 70 | } |
| 71 | |||
| 62 | return values; | 72 | return values; |
| 63 | } | 73 | } |
| 64 | } | 74 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java b/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java index 4dbe8e2f..46d5380a 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/Keep.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs; | 12 | package cuchaz.enigma.inputs; |
| 13 | 13 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java index f07e1f8b..a82db77d 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/BaseClass.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.constructors; | 12 | package cuchaz.enigma.inputs.constructors; |
| 13 | 13 | ||
| 14 | // a | 14 | // a |
| 15 | public class BaseClass { | 15 | public class BaseClass { |
| 16 | |||
| 17 | // <init>()V | 16 | // <init>()V |
| 18 | public BaseClass() { | 17 | public BaseClass() { |
| 19 | System.out.println("Default constructor"); | 18 | System.out.println("Default constructor"); |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java index 71439fd1..e81df1bd 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/Caller.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.constructors; | 12 | package cuchaz.enigma.inputs.constructors; |
| 13 | 13 | ||
| 14 | // b | 14 | // b |
| 15 | public class Caller { | 15 | public class Caller { |
| 16 | |||
| 17 | // a()V | 16 | // a()V |
| 18 | public void callBaseDefault() { | 17 | public void callBaseDefault() { |
| 19 | // a.<init>()V | 18 | // a.<init>()V |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java index c3d41705..55aa767c 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/DefaultConstructable.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.constructors; | 12 | package cuchaz.enigma.inputs.constructors; |
| 13 | 13 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java index bc56b3b2..1a90eba7 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubClass.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.constructors; | 12 | package cuchaz.enigma.inputs.constructors; |
| 13 | 13 | ||
| 14 | // d extends a | 14 | // d extends a |
| 15 | public class SubClass extends BaseClass { | 15 | public class SubClass extends BaseClass { |
| 16 | |||
| 17 | // <init>()V | 16 | // <init>()V |
| 18 | public SubClass() { | 17 | public SubClass() { |
| 19 | // a.<init>()V | 18 | // a.<init>()V |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java index 87b69d32..ec5ac444 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/constructors/SubSubClass.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.constructors; | 12 | package cuchaz.enigma.inputs.constructors; |
| 13 | 13 | ||
| 14 | // e extends d | 14 | // e extends d |
| 15 | public class SubSubClass extends SubClass { | 15 | public class SubSubClass extends SubClass { |
| 16 | |||
| 17 | // <init>(I)V | 16 | // <init>(I)V |
| 18 | public SubSubClass(int i) { | 17 | public SubSubClass(int i) { |
| 19 | // c.<init>(I)V | 18 | // c.<init>(I)V |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java index b9c4929c..87e849fd 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/BaseClass.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.inheritanceTree; | 12 | package cuchaz.enigma.inputs.inheritanceTree; |
| 13 | 13 | ||
| 14 | // a | 14 | // a |
| 15 | public abstract class BaseClass { | 15 | public abstract class BaseClass { |
| 16 | |||
| 17 | // a | 16 | // a |
| 18 | private String name; | 17 | private String name; |
| 19 | 18 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java index 50e963c0..ba8c1b78 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassA.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.inheritanceTree; | 12 | package cuchaz.enigma.inputs.inheritanceTree; |
| 13 | 13 | ||
| 14 | // b extends a | 14 | // b extends a |
| 15 | public abstract class SubclassA extends BaseClass { | 15 | public abstract class SubclassA extends BaseClass { |
| 16 | |||
| 17 | // <init>(Ljava/lang/String;)V | 16 | // <init>(Ljava/lang/String;)V |
| 18 | protected SubclassA(String name) { | 17 | protected SubclassA(String name) { |
| 19 | // call to a.<init>(Ljava/lang/String)V | 18 | // call to a.<init>(Ljava/lang/String)V |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java index d0dd664d..cfc696a8 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubclassB.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.inheritanceTree; | 12 | package cuchaz.enigma.inputs.inheritanceTree; |
| 13 | 13 | ||
| 14 | // c extends a | 14 | // c extends a |
| 15 | public class SubclassB extends BaseClass { | 15 | public class SubclassB extends BaseClass { |
| 16 | |||
| 17 | // a | 16 | // a |
| 18 | private int numThings; | 17 | private int numThings; |
| 19 | 18 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java index c5845702..d3bb62ee 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/inheritanceTree/SubsubclassAA.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.inheritanceTree; | 12 | package cuchaz.enigma.inputs.inheritanceTree; |
| 13 | 13 | ||
| 14 | // d extends b | 14 | // d extends b |
| 15 | public class SubsubclassAA extends SubclassA { | 15 | public class SubsubclassAA extends SubclassA { |
| 16 | |||
| 17 | protected SubsubclassAA() { | 16 | protected SubsubclassAA() { |
| 18 | // call to b.<init>(Ljava/lang/String;)V | 17 | // call to b.<init>(Ljava/lang/String;)V |
| 19 | super("AA"); | 18 | super("AA"); |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java index f652d875..515205a3 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/A_Anonymous.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | public class A_Anonymous { | 14 | public class A_Anonymous { |
| 15 | |||
| 16 | public void foo() { | 15 | public void foo() { |
| 17 | Runnable runnable = new Runnable() { | 16 | Runnable runnable = new Runnable() { |
| 18 | @Override | 17 | @Override |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java index d1b7601f..6ec27ac6 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/B_AnonymousWithScopeArgs.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | public class B_AnonymousWithScopeArgs { | 14 | public class B_AnonymousWithScopeArgs { |
| 15 | |||
| 16 | public static void foo(final D_Simple arg) { | 15 | public static void foo(final D_Simple arg) { |
| 17 | System.out.println(new Object() { | 16 | System.out.println(new Object() { |
| 18 | @Override | 17 | @Override |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java index 94061faa..223c424c 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/C_ConstructorArgs.java | |||
| @@ -1,19 +1,18 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | @SuppressWarnings("unused") | 14 | @SuppressWarnings("unused") |
| 15 | public class C_ConstructorArgs { | 15 | public class C_ConstructorArgs { |
| 16 | |||
| 17 | Inner i; | 16 | Inner i; |
| 18 | 17 | ||
| 19 | public void foo() { | 18 | public void foo() { |
| @@ -21,10 +20,9 @@ public class C_ConstructorArgs { | |||
| 21 | } | 20 | } |
| 22 | 21 | ||
| 23 | class Inner { | 22 | class Inner { |
| 24 | |||
| 25 | private int a; | 23 | private int a; |
| 26 | 24 | ||
| 27 | public Inner(int a) { | 25 | Inner(int a) { |
| 28 | this.a = a; | 26 | this.a = a; |
| 29 | } | 27 | } |
| 30 | } | 28 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java index 71b3a6d8..f401d5f1 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/D_Simple.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | public class D_Simple { | 14 | public class D_Simple { |
| 15 | |||
| 16 | class Inner { | 15 | class Inner { |
| 17 | // nothing to do | 16 | // nothing to do |
| 18 | } | 17 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java index 976ec426..0056bc60 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/E_AnonymousWithOuterAccess.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | public class E_AnonymousWithOuterAccess { | 14 | public class E_AnonymousWithOuterAccess { |
| 15 | |||
| 16 | // reproduction of error case documented at: | 15 | // reproduction of error case documented at: |
| 17 | // https://bitbucket.org/cuchaz/enigma/issue/61/stackoverflowerror-when-deobfuscating | 16 | // https://bitbucket.org/cuchaz/enigma/issue/61/stackoverflowerror-when-deobfuscating |
| 18 | 17 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java index b1de3c9a..b2e9e2d1 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/innerClasses/F_ClassTree.java | |||
| @@ -1,28 +1,24 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.innerClasses; | 12 | package cuchaz.enigma.inputs.innerClasses; |
| 13 | 13 | ||
| 14 | public class F_ClassTree { | 14 | public class F_ClassTree { |
| 15 | |||
| 16 | public class Level1 { | 15 | public class Level1 { |
| 17 | |||
| 18 | public int f1; | 16 | public int f1; |
| 19 | 17 | ||
| 20 | public class Level2 { | 18 | public class Level2 { |
| 21 | |||
| 22 | public int f2; | 19 | public int f2; |
| 23 | 20 | ||
| 24 | public class Level3 { | 21 | public class Level3 { |
| 25 | |||
| 26 | public int f3; | 22 | public int f3; |
| 27 | } | 23 | } |
| 28 | } | 24 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java index ddc4e319..e50d37fd 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/loneClass/LoneClass.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.loneClass; | 12 | package cuchaz.enigma.inputs.loneClass; |
| 13 | 13 | ||
| 14 | public class LoneClass { | 14 | public class LoneClass { |
| 15 | |||
| 16 | private String name; | 15 | private String name; |
| 17 | 16 | ||
| 18 | public LoneClass(String name) { | 17 | public LoneClass(String name) { |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java index cf0f6574..aa8de19a 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/SamePackageChild.java | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | package cuchaz.enigma.inputs.packageAccess; | 1 | package cuchaz.enigma.inputs.packageAccess; |
| 2 | 2 | ||
| 3 | public class SamePackageChild extends Base { | 3 | public class SamePackageChild extends Base { |
| 4 | |||
| 5 | class Inner { | 4 | class Inner { |
| 6 | final int value; | 5 | final int value; |
| 7 | 6 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java index 19fb19c2..5bcb763c 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/packageAccess/sub/OtherPackageChild.java | |||
| @@ -3,7 +3,6 @@ package cuchaz.enigma.inputs.packageAccess.sub; | |||
| 3 | import cuchaz.enigma.inputs.packageAccess.Base; | 3 | import cuchaz.enigma.inputs.packageAccess.Base; |
| 4 | 4 | ||
| 5 | public class OtherPackageChild extends Base { | 5 | public class OtherPackageChild extends Base { |
| 6 | |||
| 7 | class Inner { | 6 | class Inner { |
| 8 | final int value; | 7 | final int value; |
| 9 | 8 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java index 26f3718c..b411e0af 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/A_Basic.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | public class A_Basic { | 14 | public class A_Basic { |
| 15 | |||
| 16 | public int one; | 15 | public int one; |
| 17 | public float two; | 16 | public float two; |
| 18 | public String three; | 17 | public String three; |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java index fd7f6e7e..d5e9a255 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/B_BaseClass.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | public class B_BaseClass { | 14 | public class B_BaseClass { |
| 15 | |||
| 16 | public int f1; | 15 | public int f1; |
| 17 | public char f2; | 16 | public char f2; |
| 18 | 17 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java index 9d74e443..fd9e217c 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/C_SubClass.java | |||
| @@ -1,18 +1,17 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | public class C_SubClass extends B_BaseClass { | 14 | public class C_SubClass extends B_BaseClass { |
| 15 | |||
| 16 | public char f2; // shadows B_BaseClass.f2 | 15 | public char f2; // shadows B_BaseClass.f2 |
| 17 | public int f3; | 16 | public int f3; |
| 18 | public int f4; | 17 | public int f4; |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java index 99c83bbf..56cccc7d 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/D_AnonymousTesting.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| @@ -15,7 +15,6 @@ import java.util.ArrayList; | |||
| 15 | import java.util.List; | 15 | import java.util.List; |
| 16 | 16 | ||
| 17 | public class D_AnonymousTesting { | 17 | public class D_AnonymousTesting { |
| 18 | |||
| 19 | public List<Object> getObjs() { | 18 | public List<Object> getObjs() { |
| 20 | List<Object> objs = new ArrayList<Object>(); | 19 | List<Object> objs = new ArrayList<Object>(); |
| 21 | objs.add(new Object() { | 20 | objs.add(new Object() { |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java index 0b8cf2a5..f44bdbff 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/E_Bridges.java | |||
| @@ -1,20 +1,19 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | import java.util.Iterator; | 14 | import java.util.Iterator; |
| 15 | 15 | ||
| 16 | public class E_Bridges implements Iterator<Object> { | 16 | public class E_Bridges implements Iterator<Object> { |
| 17 | |||
| 18 | @Override | 17 | @Override |
| 19 | public boolean hasNext() { | 18 | public boolean hasNext() { |
| 20 | return false; | 19 | return false; |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java index 8a92792a..ac1d7b5f 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/F_ObjectMethods.java | |||
| @@ -1,21 +1,19 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | @SuppressWarnings("FinalizeCalledExplicitly") | 14 | @SuppressWarnings("FinalizeCalledExplicitly") |
| 15 | public class F_ObjectMethods { | 15 | public class F_ObjectMethods { |
| 16 | 16 | public void callEmAll() throws Throwable { | |
| 17 | public void callEmAll() | ||
| 18 | throws Throwable { | ||
| 19 | clone(); | 17 | clone(); |
| 20 | equals(this); | 18 | equals(this); |
| 21 | finalize(); | 19 | finalize(); |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java index a1e6a85c..4d992358 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/G_OuterClass.java | |||
| @@ -1,30 +1,29 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | public class G_OuterClass { | 14 | public class G_OuterClass { |
| 15 | |||
| 16 | public class A_InnerClass { | 15 | public class A_InnerClass { |
| 17 | |||
| 18 | public int f1; | 16 | public int f1; |
| 19 | public String f2; | 17 | public String f2; |
| 20 | 18 | ||
| 21 | public void m1() {} | 19 | public void m1() { |
| 20 | } | ||
| 22 | 21 | ||
| 23 | public class A_InnerInnerClass { | 22 | public class A_InnerInnerClass { |
| 24 | |||
| 25 | public int f3; | 23 | public int f3; |
| 26 | 24 | ||
| 27 | public void m2() {} | 25 | public void m2() { |
| 26 | } | ||
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | 29 | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java index 013c55ae..d996dc89 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/H_NamelessClass.java | |||
| @@ -1,30 +1,29 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| 14 | public class H_NamelessClass { | 14 | public class H_NamelessClass { |
| 15 | |||
| 16 | public class A_InnerClass { | 15 | public class A_InnerClass { |
| 17 | |||
| 18 | public int f1; | 16 | public int f1; |
| 19 | public String f2; | 17 | public String f2; |
| 20 | 18 | ||
| 21 | public void m1() {} | 19 | public void m1() { |
| 20 | } | ||
| 22 | 21 | ||
| 23 | public class A_InnerInnerClass { | 22 | public class A_InnerInnerClass { |
| 24 | |||
| 25 | public int f3; | 23 | public int f3; |
| 26 | 24 | ||
| 27 | public void m2() {} | 25 | public void m2() { |
| 26 | } | ||
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | 29 | ||
| @@ -32,9 +31,11 @@ public class H_NamelessClass { | |||
| 32 | public class A_NamedInnerClass { | 31 | public class A_NamedInnerClass { |
| 33 | public int f4; | 32 | public int f4; |
| 34 | 33 | ||
| 35 | public class A_AnotherInnerClass {} | 34 | public class A_AnotherInnerClass { |
| 35 | } | ||
| 36 | 36 | ||
| 37 | public class B_YetAnotherInnerClass {} | 37 | public class B_YetAnotherInnerClass { |
| 38 | } | ||
| 38 | } | 39 | } |
| 39 | } | 40 | } |
| 40 | } | 41 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java b/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java index fd2ebdd5..9a9048c7 100644 --- a/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java +++ b/enigma/src/test/java/cuchaz/enigma/inputs/translation/I_Generics.java | |||
| @@ -1,13 +1,13 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.inputs.translation; | 12 | package cuchaz.enigma.inputs.translation; |
| 13 | 13 | ||
| @@ -15,7 +15,6 @@ import java.util.List; | |||
| 15 | import java.util.Map; | 15 | import java.util.Map; |
| 16 | 16 | ||
| 17 | public class I_Generics { | 17 | public class I_Generics { |
| 18 | |||
| 19 | public List<Integer> f1; | 18 | public List<Integer> f1; |
| 20 | public List<A_Type> f2; | 19 | public List<A_Type> f2; |
| 21 | public Map<A_Type, A_Type> f3; | 20 | public Map<A_Type, A_Type> f3; |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java index e8319430..15ec44e4 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestComments.java | |||
| @@ -5,6 +5,8 @@ import java.net.URISyntaxException; | |||
| 5 | import java.nio.file.Path; | 5 | import java.nio.file.Path; |
| 6 | import java.nio.file.Paths; | 6 | import java.nio.file.Paths; |
| 7 | 7 | ||
| 8 | import org.junit.Test; | ||
| 9 | |||
| 8 | import cuchaz.enigma.ProgressListener; | 10 | import cuchaz.enigma.ProgressListener; |
| 9 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 11 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 10 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; | 12 | import cuchaz.enigma.translation.mapping.serde.MappingParseException; |
| @@ -12,28 +14,24 @@ import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | |||
| 12 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; | 14 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; |
| 13 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; | 15 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; |
| 14 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 16 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 15 | import org.junit.Test; | ||
| 16 | 17 | ||
| 17 | public class TestComments { | 18 | public class TestComments { |
| 18 | private static Path DIRECTORY; | 19 | private static Path DIRECTORY; |
| 19 | |||
| 20 | static { | ||
| 21 | try { | ||
| 22 | DIRECTORY = Paths.get(TestTinyV2InnerClasses.class.getResource("/comments/").toURI()); | ||
| 23 | } catch (URISyntaxException e) { | ||
| 24 | throw new RuntimeException(e); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | 20 | ||
| 28 | @Test | 21 | static { |
| 29 | public void testParseAndWrite() throws IOException, MappingParseException { | 22 | try { |
| 30 | ProgressListener progressListener = ProgressListener.none(); | 23 | DIRECTORY = Paths.get(TestTinyV2InnerClasses.class.getResource("/comments/").toURI()); |
| 31 | MappingSaveParameters params = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 24 | } catch (URISyntaxException e) { |
| 32 | EntryTree<EntryMapping> mappings = EnigmaMappingsReader.DIRECTORY.read( | 25 | throw new RuntimeException(e); |
| 33 | DIRECTORY, progressListener, params); | 26 | } |
| 27 | } | ||
| 34 | 28 | ||
| 35 | new TinyV2Writer("intermediary", "named") | 29 | @Test |
| 36 | .write(mappings, DIRECTORY.resolve("convertedtiny.tiny"), progressListener, params); | 30 | public void testParseAndWrite() throws IOException, MappingParseException { |
| 37 | } | 31 | ProgressListener progressListener = ProgressListener.none(); |
| 32 | MappingSaveParameters params = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | ||
| 33 | EntryTree<EntryMapping> mappings = EnigmaMappingsReader.DIRECTORY.read(DIRECTORY, progressListener, params); | ||
| 38 | 34 | ||
| 39 | } \ No newline at end of file | 35 | new TinyV2Writer("intermediary", "named").write(mappings, DIRECTORY.resolve("convertedtiny.tiny"), progressListener, params); |
| 36 | } | ||
| 37 | } | ||
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java index 510dd3cd..681fd3f2 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestReadWriteCycle.java | |||
| @@ -1,5 +1,11 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.io.File; | ||
| 4 | import java.io.IOException; | ||
| 5 | |||
| 6 | import org.junit.Assert; | ||
| 7 | import org.junit.Test; | ||
| 8 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 9 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 10 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; | 11 | import cuchaz.enigma.translation.mapping.serde.MappingFormat; |
| @@ -12,46 +18,25 @@ import cuchaz.enigma.translation.representation.entry.Entry; | |||
| 12 | import cuchaz.enigma.translation.representation.entry.FieldEntry; | 18 | import cuchaz.enigma.translation.representation.entry.FieldEntry; |
| 13 | import cuchaz.enigma.translation.representation.entry.MethodEntry; | 19 | import cuchaz.enigma.translation.representation.entry.MethodEntry; |
| 14 | import cuchaz.enigma.utils.Pair; | 20 | import cuchaz.enigma.utils.Pair; |
| 15 | import org.junit.Assert; | ||
| 16 | import org.junit.Test; | ||
| 17 | |||
| 18 | import java.io.File; | ||
| 19 | import java.io.IOException; | ||
| 20 | 21 | ||
| 21 | /** | 22 | /** |
| 22 | * Tests that a MappingFormat can write out a fixed set of mappings and read them back without losing any information. | 23 | * Tests that a MappingFormat can write out a fixed set of mappings and read them back without losing any information. |
| 23 | * Javadoc skipped for Tiny (v1) as it doesn't support them. | 24 | * Javadoc skipped for Tiny (v1) as it doesn't support them. |
| 24 | */ | 25 | */ |
| 25 | public class TestReadWriteCycle { | 26 | public class TestReadWriteCycle { |
| 26 | |||
| 27 | private final MappingSaveParameters parameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); | 27 | private final MappingSaveParameters parameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); |
| 28 | 28 | ||
| 29 | private final Pair<ClassEntry, EntryMapping> testClazz = new Pair<>( | 29 | private final Pair<ClassEntry, EntryMapping> testClazz = new Pair<>(new ClassEntry("a/b/c"), new EntryMapping("alpha/beta/charlie", "this is a test class")); |
| 30 | new ClassEntry("a/b/c"), | ||
| 31 | new EntryMapping("alpha/beta/charlie", "this is a test class") | ||
| 32 | ); | ||
| 33 | 30 | ||
| 34 | private final Pair<FieldEntry, EntryMapping> testField1 = new Pair<>( | 31 | private final Pair<FieldEntry, EntryMapping> testField1 = new Pair<>(FieldEntry.parse("a/b/c", "field1", "I"), new EntryMapping("mapped1", "this is field 1")); |
| 35 | FieldEntry.parse("a/b/c", "field1", "I"), | ||
| 36 | new EntryMapping("mapped1", "this is field 1") | ||
| 37 | ); | ||
| 38 | 32 | ||
| 39 | private final Pair<FieldEntry, EntryMapping> testField2 = new Pair<>( | 33 | private final Pair<FieldEntry, EntryMapping> testField2 = new Pair<>(FieldEntry.parse("a/b/c", "field2", "I"), new EntryMapping("mapped2", "this is field 2")); |
| 40 | FieldEntry.parse("a/b/c", "field2", "I"), | ||
| 41 | new EntryMapping("mapped2", "this is field 2") | ||
| 42 | ); | ||
| 43 | 34 | ||
| 44 | private final Pair<MethodEntry, EntryMapping> testMethod1 = new Pair<>( | 35 | private final Pair<MethodEntry, EntryMapping> testMethod1 = new Pair<>(MethodEntry.parse("a/b/c", "method1", "()V"), new EntryMapping("mapped3", "this is method1")); |
| 45 | MethodEntry.parse("a/b/c", "method1", "()V"), | ||
| 46 | new EntryMapping("mapped3", "this is method1") | ||
| 47 | ); | ||
| 48 | 36 | ||
| 49 | private final Pair<MethodEntry, EntryMapping> testMethod2 = new Pair<>( | 37 | private final Pair<MethodEntry, EntryMapping> testMethod2 = new Pair<>(MethodEntry.parse("a/b/c", "method2", "()V"), new EntryMapping("mapped4", "this is method 2")); |
| 50 | MethodEntry.parse("a/b/c", "method2", "()V"), | ||
| 51 | new EntryMapping("mapped4", "this is method 2") | ||
| 52 | ); | ||
| 53 | 38 | ||
| 54 | private void insertMapping(EntryTree<EntryMapping> mappings, Pair<? extends Entry<?>, EntryMapping> mappingPair){ | 39 | private void insertMapping(EntryTree<EntryMapping> mappings, Pair<? extends Entry<?>, EntryMapping> mappingPair) { |
| 55 | mappings.insert(mappingPair.a, mappingPair.b); | 40 | mappings.insert(mappingPair.a, mappingPair.b); |
| 56 | } | 41 | } |
| 57 | 42 | ||
| @@ -71,8 +56,8 @@ public class TestReadWriteCycle { | |||
| 71 | Assert.assertTrue("Test mapping insertion failed: testMethod2", testMappings.contains(testMethod2.a)); | 56 | Assert.assertTrue("Test mapping insertion failed: testMethod2", testMappings.contains(testMethod2.a)); |
| 72 | 57 | ||
| 73 | File tempFile = File.createTempFile("readWriteCycle", tmpNameSuffix); | 58 | File tempFile = File.createTempFile("readWriteCycle", tmpNameSuffix); |
| 74 | tempFile.delete();//remove the auto created file | 59 | //remove the auto created file |
| 75 | 60 | tempFile.delete(); | |
| 76 | 61 | ||
| 77 | mappingFormat.write(testMappings, tempFile.toPath(), ProgressListener.none(), parameters); | 62 | mappingFormat.write(testMappings, tempFile.toPath(), ProgressListener.none(), parameters); |
| 78 | Assert.assertTrue("Written file not created", tempFile.exists()); | 63 | Assert.assertTrue("Written file not created", tempFile.exists()); |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java index 60c70b73..659ac53d 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java | |||
| @@ -1,25 +1,25 @@ | |||
| 1 | /******************************************************************************* | 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2015 Jeff Martin. | 2 | * Copyright (c) 2015 Jeff Martin. |
| 3 | * All rights reserved. This program and the accompanying materials | 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the GNU Lesser General Public | 4 | * are made available under the terms of the GNU Lesser General Public |
| 5 | * License v3.0 which accompanies this distribution, and is available at | 5 | * License v3.0 which accompanies this distribution, and is available at |
| 6 | * http://www.gnu.org/licenses/lgpl.html | 6 | * http://www.gnu.org/licenses/lgpl.html |
| 7 | * | 7 | * |
| 8 | * Contributors: | 8 | * <p>Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | 11 | ||
| 12 | package cuchaz.enigma.translation.mapping; | 12 | package cuchaz.enigma.translation.mapping; |
| 13 | 13 | ||
| 14 | import java.nio.file.Path; | ||
| 15 | import java.nio.file.Paths; | ||
| 16 | |||
| 14 | import cuchaz.enigma.Enigma; | 17 | import cuchaz.enigma.Enigma; |
| 15 | import cuchaz.enigma.EnigmaProject; | 18 | import cuchaz.enigma.EnigmaProject; |
| 16 | import cuchaz.enigma.ProgressListener; | 19 | import cuchaz.enigma.ProgressListener; |
| 17 | import cuchaz.enigma.classprovider.ClasspathClassProvider; | 20 | import cuchaz.enigma.classprovider.ClasspathClassProvider; |
| 18 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; | 21 | import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; |
| 19 | 22 | ||
| 20 | import java.nio.file.Path; | ||
| 21 | import java.nio.file.Paths; | ||
| 22 | |||
| 23 | public final class TestTinyV2InnerClasses { | 23 | public final class TestTinyV2InnerClasses { |
| 24 | private Path jar; | 24 | private Path jar; |
| 25 | private Path mappings; | 25 | private Path mappings; |
| @@ -29,10 +29,9 @@ public final class TestTinyV2InnerClasses { | |||
| 29 | mappings = Paths.get(TestTinyV2InnerClasses.class.getResource("/tinyV2InnerClasses/").toURI()); | 29 | mappings = Paths.get(TestTinyV2InnerClasses.class.getResource("/tinyV2InnerClasses/").toURI()); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | // @Test | 32 | // @Test |
| 33 | public void testMappings() throws Exception { | 33 | public void testMappings() throws Exception { |
| 34 | EnigmaProject project = Enigma.create().openJar(jar, new ClasspathClassProvider(), ProgressListener.none()); | 34 | EnigmaProject project = Enigma.create().openJar(jar, new ClasspathClassProvider(), ProgressListener.none()); |
| 35 | project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters())); | 35 | project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters())); |
| 36 | |||
| 37 | } | 36 | } |
| 38 | } | 37 | } |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java index 6e4d7b99..cc08b852 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestV2Main.java | |||
| @@ -1,5 +1,8 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping; | 1 | package cuchaz.enigma.translation.mapping; |
| 2 | 2 | ||
| 3 | import java.nio.file.Path; | ||
| 4 | import java.nio.file.Paths; | ||
| 5 | |||
| 3 | import cuchaz.enigma.ProgressListener; | 6 | import cuchaz.enigma.ProgressListener; |
| 4 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; | 7 | import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; |
| 5 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; | 8 | import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; |
| @@ -7,9 +10,6 @@ import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; | |||
| 7 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; | 10 | import cuchaz.enigma.translation.mapping.serde.tinyv2.TinyV2Writer; |
| 8 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | 11 | import cuchaz.enigma.translation.mapping.tree.EntryTree; |
| 9 | 12 | ||
| 10 | import java.nio.file.Path; | ||
| 11 | import java.nio.file.Paths; | ||
| 12 | |||
| 13 | public final class TestV2Main { | 13 | public final class TestV2Main { |
| 14 | public static void main(String... args) throws Exception { | 14 | public static void main(String... args) throws Exception { |
| 15 | Path path = Paths.get(TestV2Main.class.getResource("/tinyV2InnerClasses/").toURI()); | 15 | Path path = Paths.get(TestV2Main.class.getResource("/tinyV2InnerClasses/").toURI()); |
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java index 1026f576..bd1ec20a 100644 --- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java +++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/serde/recaf/TestRecaf.java | |||
| @@ -1,11 +1,6 @@ | |||
| 1 | package cuchaz.enigma.translation.mapping.serde.recaf; | 1 | package cuchaz.enigma.translation.mapping.serde.recaf; |
| 2 | 2 | ||
| 3 | import com.google.common.collect.Sets; | 3 | import static org.junit.Assert.assertEquals; |
| 4 | import com.google.common.jimfs.Jimfs; | ||
| 5 | import cuchaz.enigma.ProgressListener; | ||
| 6 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 7 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 8 | import org.junit.Test; | ||
| 9 | 4 | ||
| 10 | import java.io.InputStream; | 5 | import java.io.InputStream; |
| 11 | import java.nio.charset.StandardCharsets; | 6 | import java.nio.charset.StandardCharsets; |
| @@ -15,32 +10,37 @@ import java.nio.file.Path; | |||
| 15 | import java.util.HashSet; | 10 | import java.util.HashSet; |
| 16 | import java.util.Set; | 11 | import java.util.Set; |
| 17 | 12 | ||
| 18 | import static org.junit.Assert.assertEquals; | 13 | import com.google.common.collect.Sets; |
| 14 | import com.google.common.jimfs.Jimfs; | ||
| 15 | import org.junit.Test; | ||
| 19 | 16 | ||
| 20 | public class TestRecaf { | 17 | import cuchaz.enigma.ProgressListener; |
| 18 | import cuchaz.enigma.translation.mapping.EntryMapping; | ||
| 19 | import cuchaz.enigma.translation.mapping.tree.EntryTree; | ||
| 21 | 20 | ||
| 22 | @Test | 21 | public class TestRecaf { |
| 23 | public void testIntegrity() throws Exception { | 22 | @Test |
| 24 | Set<String> contents; | 23 | public void testIntegrity() throws Exception { |
| 25 | try (InputStream in = getClass().getResourceAsStream("/recaf.mappings")) { | 24 | Set<String> contents; |
| 26 | contents = Sets.newHashSet(new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R")); | ||
| 27 | } | ||
| 28 | 25 | ||
| 29 | try (FileSystem fs = Jimfs.newFileSystem()) { | 26 | try (InputStream in = getClass().getResourceAsStream("/recaf.mappings")) { |
| 27 | contents = Sets.newHashSet(new String(in.readAllBytes(), StandardCharsets.UTF_8).split("\\R")); | ||
| 28 | } | ||
| 30 | 29 | ||
| 31 | Path path = fs.getPath("recaf.mappings"); | 30 | try (FileSystem fs = Jimfs.newFileSystem()) { |
| 32 | Files.writeString(path, String.join("\n", contents)); | 31 | Path path = fs.getPath("recaf.mappings"); |
| 32 | Files.writeString(path, String.join("\n", contents)); | ||
| 33 | 33 | ||
| 34 | RecafMappingsWriter writer = RecafMappingsWriter.INSTANCE; | 34 | RecafMappingsWriter writer = RecafMappingsWriter.INSTANCE; |
| 35 | RecafMappingsReader reader = RecafMappingsReader.INSTANCE; | 35 | RecafMappingsReader reader = RecafMappingsReader.INSTANCE; |
| 36 | 36 | ||
| 37 | EntryTree<EntryMapping> mappings = reader.read(path, ProgressListener.none(), null); | 37 | EntryTree<EntryMapping> mappings = reader.read(path, ProgressListener.none(), null); |
| 38 | writer.write(mappings, path, ProgressListener.none(), null); | 38 | writer.write(mappings, path, ProgressListener.none(), null); |
| 39 | 39 | ||
| 40 | reader.read(path, ProgressListener.none(), null); | 40 | reader.read(path, ProgressListener.none(), null); |
| 41 | Set<String> newContents = new HashSet<>(Files.readAllLines(path)); | 41 | Set<String> newContents = new HashSet<>(Files.readAllLines(path)); |
| 42 | 42 | ||
| 43 | assertEquals(contents, newContents); | 43 | assertEquals(contents, newContents); |
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | } | 46 | } |