[
  {
    "path": ".gitignore",
    "content": "# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n"
  },
  {
    "path": ".idea/.gitignore",
    "content": "# Default ignored files\n/shelf/\n/workspace.xml\n# Datasource local storage ignored files\n/../../../../../../:\\Users\\Unix\\IdeaProjects\\Obfuscator\\.idea/dataSources/\n/dataSources.local.xml\n# Editor-based HTTP Client requests\n/httpRequests/\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 AlpheratzTeam\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Java Obfuscator\n\nJava Obfuscator for protecting your Java applications. You can find further instruction on compilation and usage below.\n\n[![Discord Badge](https://discordapp.com/api/guilds/615439391132876850/widget.png)](https://discord.gg/Teh8Sqb)\n\n***\n\n## Getting Started\n\ntodo\n\n***\n\n### TODO\n\n- ~~boolean obf~~\n- new string encryption\n- ~~java -> kotlin~~\n- ~~insn builder~~\n- ~~number obf~~\n- ~~crc32 error~~\n- class/method/field renamer\n- decompilators crasher\n- website (?)\n- gui (c++, jni)\n- configuration toml/json\n\n***\n"
  },
  {
    "path": "build.gradle.kts",
    "content": "import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\nplugins {\n    kotlin(\"jvm\") version \"1.4.10\"\n    application\n}\n\ngroup = \"pl.alpheratzteam\"\nversion = \"1.0-SNAPSHOT\"\n\nrepositories {\n    mavenCentral()\n    maven(\"http://oss.sonatype.org/content/groups/public/\")\n}\n\ndependencies {\n    implementation(\"org.ow2.asm:asm:9.0\")\n    implementation(\"org.ow2.asm:asm-tree:9.0\")\n    implementation(\"org.ow2.asm:asm-commons:9.0\")\n    implementation(\"org.ow2.asm:asm-util:9.0\")\n    testImplementation(kotlin(\"test-junit\"))\n    implementation(kotlin(\"reflect\"))\n}\n\ntasks.test {\n    useJUnit()\n}\n\ntasks.withType<KotlinCompile> {\n    kotlinOptions.jvmTarget = \"1.8\"\n}\n\napplication {\n    mainClassName = \"pl.alpheratzteam.obfuscator.MainKt\"\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.6.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "kotlin.code.style=official\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto execute\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto execute\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle.kts",
    "content": "\nrootProject.name = \"Obfuscator\"\n\n"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/Obfuscator.kt",
    "content": "package pl.alpheratzteam.obfuscator\n\nimport org.objectweb.asm.tree.ClassNode\nimport pl.alpheratzteam.obfuscator.transformer.*\nimport pl.alpheratzteam.obfuscator.util.JarUtil\nimport java.io.File\n\n/**\n * @author Unix\n * @since 16.12.2020\n */\n\nclass Obfuscator {\n\n    private val dataFolder = File(\"obfuscator\") // base folder\n\n    val classes = mutableMapOf<String, ClassNode>() // classes from jar\n    val assets = mutableMapOf<String, ByteArray>() // assets from jar\n\n    /**\n     * The main startup method of the obfuscator.\n     */\n    fun onStart() {\n        val jarFile = File(dataFolder, \"jars\").apply { // create files\n            dataFolder.mkdir()\n            mkdir()\n        }\n\n        JarUtil.loadJar(File(jarFile, \"input.jar\")).apply { // load classes, assets from jar\n            println(\"Loading jar...\")\n        }.run {\n            println(\"Loaded jar!\")\n            println(\"Starting transformers...\")\n            classes.putAll(first)\n            assets.putAll(second)\n        }\n\n        val transformers = mutableListOf(ThrowableTransformer()) // modifiers\n        transformers.forEach {\n            val name = it.javaClass.simpleName\n            var time = System.currentTimeMillis()\n            println(\"Running $name transformer...\")\n            it.transform(this) // modify classes\n            time = System.currentTimeMillis() - time\n            println(\"Finished running $name transformer. [$time ms]\")\n            println(\"---------------------------------------\")\n        }\n\n        JarUtil.saveJar(File(jarFile, \"output.jar\"), Pair(classes, assets)).apply { // save output\n            println(\"Saving jar...\")\n        }.run {\n            println(\"Saved jar!\")\n        }\n    }\n    \n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/api/number/NumberData.kt",
    "content": "package pl.alpheratzteam.obfuscator.api.number\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.FieldNode\n\n/**\n * @author Unix\n * @since 03.04.2021\n */\n\nclass NumberData<T : Number>(val fieldName: String, val numberType: NumberType) {\n\n    val numbers = mutableMapOf<Int, T>()\n    var size = 0\n\n    fun addNumber(id: Int, number: T) {\n        numbers[id] = number\n    }\n\n    fun getFieldNode() : FieldNode {\n        return FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, numberType.descriptor, null, null)\n    }\n\n}\n\n//class NumberData<T : Number>(val fieldName: String, val numberType: NumberType, val opcodes: Array<Int>) {\n//\n//    val numbers = mutableMapOf<Int, T>()\n//    var size = 0\n//\n//    fun addNumber(id: Int, number: Any) {\n//        numbers[id] = number as T\n//    }\n//\n//    fun getFieldNode() : FieldNode {\n//        return FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, numberType.descriptor, null, null)\n//    }\n//\n//    fun isNumber(abstractInsnNode: AbstractInsnNode) : Boolean {\n//        return when(numberType) {\n//            NumberType.INTEGER -> ASMUtil.isIntInsn(abstractInsnNode)\n//            NumberType.DOUBLE -> ASMUtil.isDoubleInsn(abstractInsnNode)\n//            NumberType.FLOAT -> ASMUtil.isFloatInsn(abstractInsnNode)\n//            NumberType.LONG -> ASMUtil.isLongInsn(abstractInsnNode)\n//        }\n//    }\n//\n//    fun getNumber(abstractInsnNode: AbstractInsnNode) : Number {\n//        return when(numberType) {\n//            NumberType.INTEGER -> ASMUtil.getIntFromInsn(abstractInsnNode)\n//            NumberType.DOUBLE -> ASMUtil.getDoubleFromInsn(abstractInsnNode)\n//            NumberType.FLOAT -> ASMUtil.getFloatFromInsn(abstractInsnNode)\n//            NumberType.LONG -> ASMUtil.getLongFromInsn(abstractInsnNode)\n//        }\n//    }\n//\n//}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/api/number/NumberType.kt",
    "content": "package pl.alpheratzteam.obfuscator.api.number\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.InsnNode\n\n/**\n * @author Unix\n * @since 03.04.2021\n */\n\nenum class NumberType(val store: Int, val opcode: Int, val descriptor: String) {\n\n    INTEGER(IASTORE, T_INT, \"[I\"),\n    DOUBLE(DASTORE, T_DOUBLE, \"[D\"),\n    FLOAT(FASTORE, T_FLOAT, \"[F\"),\n    LONG(LASTORE, T_LONG, \"[J\")\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/api/transformer/Transformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.api.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\n\n/**\n * @author Unix\n * @since 16.12.2020\n */\n\ninterface Transformer {\n\n    /**\n     * This method transform some classes by obfuscator.\n     * @param obfuscator as instance of obfuscator.\n     * @see [ClassNode] class to transform.\n     */\n    fun transform(obfuscator: Obfuscator)\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/main.kt",
    "content": "import pl.alpheratzteam.obfuscator.Obfuscator\n\n/**\n * @author Unix\n * @since 16.12.2020\n */\n\n/**\n * This method starts the obfuscator.\n * @see [Obfuscator] obfuscator class.\n */\nfun main() {\n    Obfuscator().onStart() // start application\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/AntiDebugTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.insnBuilder\nimport org.objectweb.asm.tree.LabelNode\nimport org.objectweb.asm.tree.MethodInsnNode\nimport org.objectweb.asm.tree.MethodNode\nimport pl.alpheratzteam.obfuscator.util.StringUtil\n\n/**\n * @author Unix\n * @since 17.12.2020\n */\n\nclass AntiDebugTransformer : Transformer {\n\n    private val debugTypes = arrayOf(\"-Xbootclasspath\", \"-Xdebug\", \"-agentlib\", \"-Xrunjdwp:\", \"-verbose\")\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach { classNode ->\n            classNode.methods.find { it.name.equals(\"<clinit>\") }.also {\n                val methodNode = makeMethod()\n                it?.instructions?.insertBefore(it.instructions.last, MethodInsnNode(INVOKESTATIC, classNode.name, methodNode.name, methodNode.desc, false))\n                classNode.methods.add(methodNode)\n            }\n        }\n    }\n\n    private fun makeMethod(): MethodNode {\n        val method = MethodNode()\n        with(method) {\n            access = ACC_PRIVATE or ACC_STATIC\n            name = StringUtil.generateString(8)\n            desc = \"()V\"\n            signature = null\n            exceptions = null\n            maxStack = 2\n            instructions = insnBuilder {\n                invokestatic(\"java/lang/management/ManagementFactory\", \"getRuntimeMXBean\", \"()Ljava/lang/management/RuntimeMXBean;\", false)\n                invokeinterface(\"java/lang/management/RuntimeMXBean\", \"getInputArguments\", \"()Ljava/util/List;\", true)\n                invokeinterface(\"java/util/List\", \"iterator\", \"()Ljava/util/Iterator;\", true)\n                astore(1)\n                val label1 = LabelNode()\n                +label1\n                frame(F_APPEND, 1, arrayOf(\"java/util/Iterator\"), 0, null)\n                aload(1)\n                invokeinterface(\"java/util/Iterator\", \"hasNext\", \"()Z\", true)\n                val label2 = LabelNode()\n                ifeq(label2)\n                aload(1)\n                invokeinterface(\"java/util/Iterator\", \"next\", \"()Ljava/lang/Object;\", true)\n                checkcast(\"java/lang/String\")\n                astore(2)\n                +LabelNode()\n                aload(2)\n                ldc(\"-javaagent:\")\n                invokevirtual(\"java/lang/String\", \"startsWith\", \"(Ljava/lang/String;)Z\", false)\n                val label4 = LabelNode()\n                debugTypes.forEach {\n                    ifne(label4)\n                    aload(2)\n                    ldc(it)\n                    invokevirtual(\"java/lang/String\", \"startsWith\", \"(Ljava/lang/String;)Z\", false)\n                }\n                val label5 = LabelNode()\n                ifeq(label5)\n                +label4\n                frame(F_APPEND, 1, arrayOf(\"java/lang/String\"), 0, null)\n                insn(ICONST_0)\n                invokestatic(\"java/lang/System\", \"exit\", \"(I)V\", false)\n                +label5\n                frame(F_CHOP, 1, null, 0, null)\n                goto(label1)\n                +label2\n                frame(F_CHOP, 1, null, 0, null)\n                _return()\n            }\n        }\n        return method\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/BadAnnotationTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.tree.AnnotationNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.RandomUtil\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport java.util.Objects\n\n/**\n * @author Unix\n * @since 17.12.2020\n */\n\nclass BadAnnotationTransformer : Transformer {\n\n    private val annotations: MutableList<AnnotationNode> = mutableListOf()\n\n    init {\n        val string = StringUtil.generateString(RandomUtil.int(10, 64))\n        repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode(\"L$string;\")) }\n        repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode(string)) }\n        repeat((0..RandomUtil.int(1, 10)).count()) { annotations.add(AnnotationNode(\"@$string\")) }\n    }\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.run {\n                if (Objects.isNull(visibleAnnotations)) {\n                    visibleAnnotations = mutableListOf()\n                }\n\n                if (Objects.isNull(invisibleAnnotations)) {\n                    invisibleAnnotations = mutableListOf()\n                }\n\n                val pair = change(visibleAnnotations, invisibleAnnotations)\n                visibleAnnotations = pair.first\n                invisibleAnnotations = pair.second\n            }\n\n            it.methods.forEach {\n                it.run {\n                    if (Objects.isNull(visibleAnnotations)) {\n                        visibleAnnotations = mutableListOf()\n                    }\n\n                    if (Objects.isNull(invisibleAnnotations)) {\n                        invisibleAnnotations = mutableListOf()\n                    }\n\n                    val pair = change(visibleAnnotations, invisibleAnnotations)\n                    visibleAnnotations = pair.first\n                    invisibleAnnotations = pair.second\n                }\n            }\n\n            it.fields.forEach {\n                it.run {\n                    if (Objects.isNull(visibleAnnotations)) {\n                        visibleAnnotations = mutableListOf()\n                    }\n\n                    if (Objects.isNull(invisibleAnnotations)) {\n                        invisibleAnnotations = mutableListOf()\n                    }\n\n                    val pair = change(visibleAnnotations, invisibleAnnotations)\n                    visibleAnnotations = pair.first\n                    invisibleAnnotations = pair.second\n                }\n            }\n        }\n    }\n\n    fun change(visibleAnnotations: MutableList<AnnotationNode>, invisibleAnnotations: MutableList<AnnotationNode>): Pair<List<AnnotationNode>, List<AnnotationNode>> {\n        visibleAnnotations.addAll(annotations)\n        invisibleAnnotations.addAll(annotations)\n        return Pair(visibleAnnotations, invisibleAnnotations)\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/BooleanObfuscationTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.RandomUtil\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport pl.alpheratzteam.obfuscator.util.insnBuilder\nimport java.util.concurrent.atomic.AtomicInteger\n\n/**\n * @author Unix\n * @since 07.04.2021\n */\n\nclass BooleanObfuscationTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach { classNode ->\n            val fieldName = StringUtil.generateString(8)\n            val ints = mutableListOf<Int>()\n            classNode.fields.add(FieldNode(ACC_STATIC + ACC_PRIVATE, fieldName, \"[I\", null, null))\n            classNode.methods.forEach { methodNode ->\n                methodNode.instructions.forEach {\n                    if (it.previous is InsnNode && it is VarInsnNode) {\n                        val value = RandomUtil.int(10, 2000)\n                        val insnNode = it.previous as InsnNode\n                        if (insnNode.opcode == 4 || insnNode.opcode == 3) {\n                            methodNode.instructions.insertBefore(it, makeInsn(classNode, fieldName, ints.size, ints.size + 1))\n                            methodNode.instructions.remove(it.previous)\n                            ints.add(value)\n\n                            when (insnNode.opcode) {\n                                4 -> ints.add(value)\n                                3 -> ints.add(value + RandomUtil.int(10, 2000))\n                            }\n                        }\n                    }\n                }\n            }\n\n            classNode.methods.filter { it.name.equals(\"<clinit>\") }.forEach { it.instructions = makeClinit(it, classNode.name, fieldName, ints) }\n        }\n    }\n\n    private fun makeClinit(methodNode: MethodNode, className: String, fieldName: String, ints: List<Int>): InsnList {\n        val insnNode = methodNode.instructions\n        return insnBuilder {\n            ldc(ints.size)\n            newintarray()\n            putstatic(className, fieldName, \"[I\")\n\n            val size = AtomicInteger()\n            ints.forEach {\n                getstatic(className, fieldName, \"[I\")\n                ldc(size.getAndIncrement())\n                ldc(it)\n                iastore()\n            }\n\n            +insnNode\n            _return()\n        }\n    }\n\n    fun makeInsn(classNode: ClassNode, fieldName: String, first: Int, second: Int) : InsnList {\n        return insnBuilder {\n            getstatic(classNode.name, fieldName, \"[I\")\n            ldc(first)\n            iaload()\n            getstatic(classNode.name, fieldName, \"[I\")\n            ldc(second)\n            iaload()\n            val labelNode = LabelNode()\n            if_icmpne(labelNode)\n            insn(ICONST_1)\n            val labelNode2 = LabelNode()\n            goto(labelNode2)\n            +labelNode\n            frame(F_SAME, 0, null, 0, null)\n            insn(ICONST_0)\n            +labelNode2\n            frame(F_SAME1, 0, null, 1, arrayOf(INTEGER))\n            istore(0)\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/DebugInfoRemoverTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.ClassReader\nimport org.objectweb.asm.ClassWriter\nimport org.objectweb.asm.tree.ClassNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass DebugInfoRemoverTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        val classes = mutableMapOf<String, ClassNode>()\n        obfuscator.classes.values.forEach {\n            val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)\n            it.accept(classWriter)\n\n            val newClassNode = ClassNode()\n            ClassReader(classWriter.toByteArray()).accept(newClassNode, ClassReader.SKIP_DEBUG)\n            classes[newClassNode.name] = newClassNode\n        }\n\n        obfuscator.classes.clear()\n        obfuscator.classes.putAll(classes)\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FakeInstructionsTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.ASMUtil\nimport org.objectweb.asm.tree.InsnNode\nimport org.objectweb.asm.tree.IntInsnNode\nimport org.objectweb.asm.tree.LdcInsnNode\nimport pl.alpheratzteam.obfuscator.util.RandomUtil\nimport java.util.concurrent.atomic.AtomicInteger\n\n\n/**\n * @author Unix\n * @since 16.04.2021\n */\n\nclass FakeInstructionsTransformer : Transformer {\n\n    // https://github.com/sim0n/Caesium/blob/master/src/main/java/dev/sim0n/caesium/mutator/impl/PolymorphMutator.java\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.methods.filter { ASMUtil.hasInstructions(it) }.forEach {\n                val index = AtomicInteger()\n                val instructions = it.instructions\n\n                it.instructions.forEach {\n                    if (it is LdcInsnNode) {\n                        if (RandomUtil.boolean()) {\n                            instructions.insertBefore(\n                                it,\n                                IntInsnNode(BIPUSH, RandomUtil.int(-64, 64))\n                            )\n                            instructions.insertBefore(it, InsnNode(POP))\n                        }\n                    } else if (index.getAndIncrement() % 6 == 0) {\n                        if (RandomUtil.float() > 0.6) {\n                            instructions.insertBefore(\n                                it,\n                                IntInsnNode(BIPUSH, RandomUtil.int(-27, 37))\n                            )\n                            instructions.insertBefore(it, InsnNode(POP))\n                        } else {\n                            instructions.insertBefore(it, InsnNode(NOP))\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FlowTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.FieldInsnNode\nimport org.objectweb.asm.tree.FieldNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport org.objectweb.asm.tree.InsnNode\nimport org.objectweb.asm.tree.JumpInsnNode\nimport pl.alpheratzteam.obfuscator.util.ConditionUtil\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass FlowTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach { classNode ->\n            var hasField = false\n            val fieldName = StringUtil.generateString(8)\n            classNode.methods.forEach { methodNode ->\n                methodNode.instructions.filter { it.opcode == GOTO }.forEach {\n                    hasField = true\n                    with(methodNode) {\n                        instructions.insertBefore(it, FieldInsnNode(GETSTATIC, classNode.name, fieldName, \"Z\"))\n                        instructions.insert(it, InsnNode(ATHROW))\n                        instructions.insert(it, InsnNode(ACONST_NULL))\n                        instructions.set(it, JumpInsnNode(IFEQ, (it as JumpInsnNode).label))\n                    }\n                }\n            }\n\n            ConditionUtil.checkCondition(hasField) {\n                classNode.fields.add(FieldNode(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, fieldName, \"Z\", null, null))\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/FullAccessTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass FullAccessTransformer : Transformer {\n\n    private val accesses = intArrayOf(ACC_ANNOTATION, ACC_FINAL, ACC_ENUM, ACC_INTERFACE, ACC_MANDATED,\n        ACC_MODULE, ACC_OPEN, ACC_STRICT, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_TRANSIENT, ACC_TRANSITIVE, ACC_VARARGS, ACC_DEPRECATED\n    ) // separate (enum): class, method, field\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            with (it) {\n//                access = changeAccess(access) // change classNode\n                methods.filter { !it.name.startsWith(\"<\") }.forEach { it.access = changeAccess(it.access) } // change methodNode\n                fields.forEach { it.access = changeAccess(it.access) } // change fieldNode\n            }\n        }\n    }\n\n    private fun changeAccess(access: Int): Int {\n        var newAccess: Int = access\n        accesses.filter { access and it == 0 }.forEach { newAccess = newAccess or it }\n        return newAccess\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/HideCodeTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.ASMUtil\nimport pl.alpheratzteam.obfuscator.util.ConditionUtil\nimport java.util.Objects\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass HideCodeTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            ConditionUtil.checkCondition(!(ASMUtil.isSynthetic(it.access) && Objects.isNull(it.visibleAnnotations))) {\n                it.access = it.access or ACC_SYNTHETIC\n            }\n\n            it.methods.forEach {\n                ConditionUtil.checkCondition(!ASMUtil.isSynthetic(it.access)) {\n                    it.access = it.access or ACC_SYNTHETIC\n                }\n\n                ConditionUtil.checkCondition(!it.name.startsWith(\"<\") && ASMUtil.isBridge(it.access)) {\n                    it.access = it.access or ACC_BRIDGE\n                }\n            }\n\n            it.fields.filter { ASMUtil.isStatic(it.access) }.forEach {\n                it.access = it.access or ACC_SYNTHETIC\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/LocalVariableTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport java.util.*\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass LocalVariableTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.flatMap { it.value.methods }\n            .filter { Objects.nonNull(it.localVariables) }\n            .flatMap { it.localVariables }\n            .forEach { it.name = StringUtil.generateString(16) }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/MarkerTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.MethodNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.insnBuilder\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass MarkerTransformer : Transformer {\n\n    private val methodName = \"hello\"\n    private val text = \"your text here\"\n\n    override fun transform(obfuscator: Obfuscator) {\n        val methodNode = makeMethod()\n        obfuscator.classes.values.forEach { it.methods.add(methodNode) }\n    }\n\n    private fun makeMethod(): MethodNode {\n        val method = MethodNode()\n        with(method) {\n            access = ACC_PRIVATE or ACC_STATIC\n            name = methodName\n            desc = \"()V\"\n            signature = null\n            exceptions = null\n            instructions = insnBuilder {\n                getstatic(\"java/lang/System\", \"out\", \"Ljava/io/PrintStream;\")\n                ldc(text)\n                invokevirtual(\"java/io/PrintStream\", \"println\", \"(Ljava/lang/String;)V\", false)\n                _return()\n            }\n        }\n        return method\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/NumberTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.tree.InsnList\nimport org.objectweb.asm.tree.MethodNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.number.NumberData\nimport pl.alpheratzteam.obfuscator.api.number.NumberType.DOUBLE\nimport pl.alpheratzteam.obfuscator.api.number.NumberType.FLOAT\nimport pl.alpheratzteam.obfuscator.api.number.NumberType.LONG\nimport pl.alpheratzteam.obfuscator.api.number.NumberType.INTEGER\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.*\n\n/**\n * @author Unix\n * @since 17.12.2020\n */\n\nclass NumberTransformer : Transformer {\n\n    // TODO: 04.04.2021 cleanup code, static initialization\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach { classNode ->\n            val intNumbers = NumberData<Int>(StringUtil.generateString(8), INTEGER)\n            val doubleNumbers = NumberData<Double>(StringUtil.generateString(8), DOUBLE)\n            val floatNumbers = NumberData<Float>(StringUtil.generateString(8), FLOAT)\n            val longNumbers = NumberData<Long>(StringUtil.generateString(8), LONG)\n\n            classNode.fields.add(intNumbers.getFieldNode())\n            classNode.fields.add(doubleNumbers.getFieldNode())\n            classNode.fields.add(floatNumbers.getFieldNode())\n            classNode.fields.add(longNumbers.getFieldNode())\n\n            classNode.methods.forEach { methodNode ->\n                methodNode.instructions.forEach {\n                    ConditionUtil.checkCondition(ASMUtil.isIntInsn(it)) { // int\n                        val fieldNumber = RandomUtil.int(10, 3000)\n                        val originalNumber = ASMUtil.getIntFromInsn(it)\n                        val fakeNumber = RandomUtil.int(10, 3000)\n                        val calcNumber = originalNumber xor fakeNumber * fieldNumber\n\n                        intNumbers.addNumber(intNumbers.size, fieldNumber)\n                        methodNode.instructions.insertBefore(it, insnBuilder {\n                            ldc(calcNumber)\n                            ldc(fakeNumber)\n                            getstatic(classNode.name, intNumbers.fieldName, intNumbers.numberType.descriptor)\n                            ldc(intNumbers.size)\n                            iaload()\n                            imul()\n                            ixor()\n                        })\n                        methodNode.instructions.remove(it)\n                        ++intNumbers.size\n                    }\n\n                    ConditionUtil.checkCondition(ASMUtil.isDoubleInsn(it)) { // double\n                        val fieldNumber = RandomUtil.int(10, 3000).toDouble()\n                        val originalNumber = ASMUtil.getDoubleFromInsn(it)\n                        val fakeNumber = RandomUtil.int(10, 3000).toDouble()\n                        val calcNumber = originalNumber * fakeNumber * fieldNumber\n\n                        doubleNumbers.addNumber(doubleNumbers.size, fieldNumber)\n                        methodNode.instructions.insertBefore(it, insnBuilder {\n                            ldc(calcNumber)\n                            ldc(fakeNumber)\n                            getstatic(classNode.name, doubleNumbers.fieldName, doubleNumbers.numberType.descriptor)\n                            ldc(doubleNumbers.size)\n                            daload()\n                            dmul()\n                            ddiv()\n                        })\n                        methodNode.instructions.remove(it)\n                        ++doubleNumbers.size\n                    }\n\n                    ConditionUtil.checkCondition(ASMUtil.isFloatInsn(it)) { // float\n                        val fieldNumber = RandomUtil.int(10, 3000).toFloat()\n                        val originalNumber = ASMUtil.getFloatFromInsn(it)\n                        val fakeNumber = RandomUtil.int(10, 3000).toFloat()\n                        val calcNumber = originalNumber * fakeNumber * fieldNumber\n\n                        floatNumbers.addNumber(floatNumbers.size, fieldNumber)\n                        methodNode.instructions.insertBefore(it, insnBuilder {\n                            ldc(calcNumber)\n                            ldc(fakeNumber)\n                            getstatic(classNode.name, floatNumbers.fieldName, floatNumbers.numberType.descriptor)\n                            ldc(floatNumbers.size)\n                            faload()\n                            fmul()\n                            fdiv()\n                        })\n                        methodNode.instructions.remove(it)\n                        ++floatNumbers.size\n                    }\n\n                    ConditionUtil.checkCondition(ASMUtil.isLongInsn(it)) { // long\n                        val fieldNumber = RandomUtil.int(10, 3000).toLong()\n                        val originalNumber = ASMUtil.getLongFromInsn(it)\n                        val fakeNumber = RandomUtil.int(10, 3000).toLong()\n                        val calcNumber = originalNumber xor fakeNumber * fieldNumber\n\n                        longNumbers.addNumber(longNumbers.size, fieldNumber)\n                        methodNode.instructions.insertBefore(it, insnBuilder {\n                            ldc(calcNumber)\n                            ldc(fakeNumber)\n                            getstatic(classNode.name, longNumbers.fieldName, longNumbers.numberType.descriptor)\n                            ldc(longNumbers.size)\n                            laload()\n                            lmul()\n                            lxor()\n                        })\n                        methodNode.instructions.remove(it)\n                        ++longNumbers.size\n                    }\n                }\n            }\n\n            with (classNode) {\n                methods.filter { it.name.equals(\"<clinit>\") }.forEach {\n                    it.instructions = makeClinit(it, classNode.name, intNumbers)\n                    it.instructions = makeClinit(it, classNode.name, doubleNumbers)\n                    it.instructions = makeClinit(it, classNode.name, floatNumbers)\n                    it.instructions = makeClinit(it, classNode.name, longNumbers)\n                }\n            }\n        }\n    }\n\n    private fun <T : Number> makeClinit(methodNode: MethodNode, className: String, numberData: NumberData<T>): InsnList {\n        val insnNode = methodNode.instructions\n        return insnBuilder {\n            ldc(numberData.size)\n            newarray(numberData.numberType.opcode)\n            putstatic(className, numberData.fieldName, numberData.numberType.descriptor)\n            numberData.numbers.forEach { (key, value) ->\n                getstatic(className, numberData.fieldName, numberData.numberType.descriptor)\n                ldc(key)\n                when (numberData.numberType) {\n                    INTEGER -> ldc(value as Int)\n                    LONG -> ldc(value as Long)\n                    DOUBLE -> ldc(value as Double)\n                    FLOAT -> ldc(value as Float)\n                }\n                insn(numberData.numberType.store)\n            }\n\n            +insnNode\n            _return()\n        }\n    }\n\n}\n\n// FIXME: 07.04.2021 V error - Exception in thread \"main\" java.lang.NegativeArraySizeException: -1\n//class NumberTransformer : Transformer {\n//\n//    // TODO: 04.04.2021 static initialization, unique string generator\n//\n//    override fun transform(obfuscator: Obfuscator) {\n//        obfuscator.classes.values.forEach { classNode ->\n//            val numberDatas = listOf(NumberData<Int>(StringUtil.generateString(8), INTEGER, arrayOf(IALOAD, IMUL, IXOR)), NumberData<Long>(StringUtil.generateString(8), LONG, arrayOf(LALOAD, LMUL, LXOR)),\n//                NumberData<Double>(StringUtil.generateString(8), DOUBLE, arrayOf(DALOAD, DMUL, DDIV)), NumberData<Float>(StringUtil.generateString(8), FLOAT, arrayOf(FALOAD, FMUL, FDIV)))\n//\n//            numberDatas.forEach { classNode.fields.add(it.getFieldNode()) }\n//\n//            classNode.methods.forEach { methodNode ->\n//                numberDatas.forEach { numberData ->\n//                    methodNode.instructions.forEach { abstractInsnNode ->\n//                        ConditionUtil.checkCondition(numberData.isNumber(abstractInsnNode)) {\n//                            val fieldNumber = RandomUtil.int(10, 3000)\n//                            val originalNumber = numberData.getNumber(abstractInsnNode)\n//                            val fakeNumber = RandomUtil.int(10, 3000)\n//                            methodNode.instructions.insertBefore(abstractInsnNode, insnBuilder {\n//                                when (numberData.numberType) {\n//                                    INTEGER -> {\n//                                        numberData.addNumber(numberData.size, fieldNumber)\n//                                        ldc((originalNumber.toInt() xor fakeNumber * fieldNumber))\n//                                    }\n//                                    DOUBLE -> {\n//                                        numberData.addNumber(numberData.size, fieldNumber.toDouble())\n//                                        ldc((originalNumber.toDouble() * fakeNumber * fieldNumber))\n//                                    }\n//                                    FLOAT -> {\n//                                        numberData.addNumber(numberData.size, fieldNumber.toFloat())\n//                                        ldc((originalNumber.toFloat() * fakeNumber * fieldNumber))\n//                                    }\n//                                    LONG -> {\n//                                        numberData.addNumber(numberData.size, fieldNumber.toLong())\n//                                        ldc((originalNumber.toLong() xor fakeNumber.toLong() * fieldNumber))\n//                                    }\n//                                }\n//\n//                                ldc(fakeNumber)\n//                                getstatic(classNode.name, numberData.fieldName, numberData.numberType.descriptor)\n//                                ldc(numberData.size)\n//                                numberData.opcodes.forEach { insn(it) }\n//                            })\n//\n//                            methodNode.instructions.remove(abstractInsnNode)\n//                            ++numberData.size\n//                        }\n//                    }\n//                }\n//            }\n//\n//            with (classNode) {\n//                methods.filter { it.name.equals(\"<clinit>\") }.forEach { methodNode ->\n//                    val insnList = InsnList()\n//                    numberDatas.forEach { insnList.add(makeClinit(classNode.name, it)) }\n//\n//                    if (Objects.isNull(methodNode.instructions)) {\n//                        methodNode.instructions = InsnList()\n//                    }\n//\n//                    val cachedInsnNode = methodNode.instructions\n//                    methodNode.instructions.clear()\n//                    methodNode.instructions.add(insnBuilder {\n//                        +insnList\n//                        +cachedInsnNode\n//                        _return()\n//                    })\n//                }\n//            }\n//        }\n//    }\n//\n//    private fun <T : Number> makeClinit(className: String, numberData: NumberData<T>): InsnList {\n//        return insnBuilder {\n//            ldc(numberData.size)\n//            newarray(numberData.numberType.opcode)\n//            putstatic(className, numberData.fieldName, numberData.numberType.descriptor)\n//            numberData.numbers.forEach { (key, value) ->\n//                getstatic(className, numberData.fieldName, numberData.numberType.descriptor)\n//                ldc(key)\n//                when (numberData.numberType) {\n//                    INTEGER -> ldc(value as Int)\n//                    LONG -> ldc(value as Long)\n//                    DOUBLE -> ldc(value as Double)\n//                    FLOAT -> ldc(value as Float)\n//                }\n//                insn(numberData.numberType.store)\n//            }\n//        }\n//    }\n//\n//}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/ShuffleMemberTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass ShuffleMemberTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.attrs?.shuffle()\n            it.methods?.shuffle()\n            it.methods?.forEach {\n                it.localVariables?.shuffle()\n                it.parameters?.shuffle()\n                it.attrs?.shuffle()\n            }\n            it.fields?.shuffle()\n            it.fields?.forEach { it.attrs?.shuffle() }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/SignatureTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.StringUtil\n\n/**\n * @author Unix\n * @since 16.12.2020\n */\n\nclass SignatureTransformer : Transformer {\n    override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.signature = StringUtil.makeUnreadable(StringUtil.generateString(4)) }\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/SourceFileTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.StringUtil\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass SourceFileTransformer : Transformer {\n    override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.sourceFile = StringUtil.generateString(Byte.MAX_VALUE.toInt()) }\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/ThrowableTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.F_SAME\nimport org.objectweb.asm.tree.*\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.ASMUtil\nimport pl.alpheratzteam.obfuscator.util.RandomUtil\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport pl.alpheratzteam.obfuscator.util.insnBuilder\nimport java.io.IOException\nimport java.lang.annotation.AnnotationTypeMismatchException\nimport java.nio.BufferUnderflowException\nimport java.util.*\nimport kotlin.reflect.KClass\n\n/**\n * @author Unix\n * @since 03.04.2021\n */\n\nclass ThrowableTransformer : Transformer {\n\n    private val exceptions = listOf(get(Exception::class), get(IOException::class), get(BufferUnderflowException::class), get(ExceptionInInitializerError::class),\n        get(ArrayIndexOutOfBoundsException::class), get(ArrayStoreException::class), get(AnnotationTypeMismatchException::class))\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.methods.filter { !it.name.startsWith(\"<\") }.forEach { methodNode ->\n                methodNode.instructions\n                    .asSequence()\n                    .filter { ASMUtil.isInstruction(it) && !Objects.isNull(it.next) }\n                    .forEach { methodNode.instructions.insertBefore(it.next, makeInsn()) }\n            }\n        }\n    }\n\n    fun makeInsn() : InsnList {\n        return insnBuilder {\n            +LabelNode()\n            val bool = RandomUtil.boolean()\n            val type = RandomUtil.int(1, 3)\n            when (type) {\n                1 -> {\n                    val string = StringUtil.generateString(2)\n                    ldc(string)\n                    when {\n                        bool -> {\n                            ldc(string + StringUtil.generateString(2))\n                        }\n                        else -> {\n                            ldc(string)\n                        }\n                    }\n                    invokevirtual(\"java/lang/String\", \"equals\", \"(Ljava/lang/Object;)Z\", false)\n                }\n                2 -> {\n                    when (RandomUtil.int(1, 3)) {\n                        1 -> {\n                            ldc(RandomUtil.float(1.0, 200.0))\n                            when (RandomUtil.int(1, 3)) {\n                                1 -> invokestatic(\"java/lang/Float\", \"isInfinite\", \"(F)Z\", false)\n                                2 -> invokestatic(\"java/lang/Float\", \"isNaN\", \"(F)Z\", false)\n                            }\n                        }\n                        2 -> {\n                            ldc(RandomUtil.double(1.0, 200.0))\n                            when (RandomUtil.int(1, 3)) {\n                                1 -> invokestatic(\"java/lang/Double\", \"isInfinite\", \"(D)Z\", false)\n                                2 -> invokestatic(\"java/lang/Double\", \"isNaN\", \"(D)Z\", false)\n                            }\n                        }\n                    }\n                }\n            }\n//            val string = StringUtil.generateString(2)\n//            ldc(string)\n//            ldc(string + StringUtil.generateString(2))\n//            invokevirtual(\"java/lang/String\", \"equals\", \"(Ljava/lang/Object;)Z\", false)\n            val labelNode = LabelNode()\n            when (type) {\n                1 -> {\n                    when {\n                        bool -> {\n                            ifeq(labelNode)\n                        }\n                        else -> {\n                            ifne(labelNode)\n                        }\n                    }\n                }\n                else -> ifeq(labelNode)\n            }\n            val labelNode1 = LabelNode()\n            +labelNode1\n\n            when (RandomUtil.int(1, 3)) {\n                1 -> {\n                    val exception: String? = exceptions[RandomUtil.int(exceptions.size)]\n                    exception?.let {\n                        new(it)\n                        dup()\n                        invokespecial(it, \"<init>\", \"()V\", false)\n                    }\n                }\n                else -> aconst_null()\n            }\n\n            athrow()\n            +labelNode\n            frame(F_SAME, 0, null, 0, null)\n            +LabelNode()\n        }\n    }\n\n    fun <T : Any> get(any: KClass<T>) = any.qualifiedName?.replace(\".\", \"/\")\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/TrashCodeTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.LabelNode\nimport org.objectweb.asm.tree.MethodInsnNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.StringUtil\nimport pl.alpheratzteam.obfuscator.util.insnBuilder\nimport pl.alpheratzteam.obfuscator.util.RandomUtil\nimport pl.alpheratzteam.obfuscator.util.printlnAsm\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass TrashCodeTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.methods.filter { !it.name.startsWith(\"<\") }.forEach { methodNode ->\n                methodNode.instructions.filter { it is MethodInsnNode }.map { it as MethodInsnNode }\n                    .filter { !it.owner.startsWith(\"\\u0000\") }.forEach {\n                    methodNode.instructions.insertBefore(it.next, insnBuilder {\n                        val bool = RandomUtil.boolean()\n\n                        +LabelNode()\n\n                        // TODO: 17.04.2021 code cleanup.\n\n                        val type = RandomUtil.int(1, 3)\n                        when (type) {\n                            1 -> {\n                                val string = StringUtil.generateString(2)\n                                ldc(string)\n                                when {\n                                    bool -> {\n                                        ldc(string + StringUtil.generateString(2))\n                                    }\n                                    else -> {\n                                        ldc(string)\n                                    }\n                                }\n                                invokevirtual(\"java/lang/String\", \"equals\", \"(Ljava/lang/Object;)Z\", false)\n                            }\n                            2 -> {\n                                when (RandomUtil.int(1, 3)) {\n                                    1 -> {\n                                        ldc(RandomUtil.float(1.0, 200.0))\n                                        when (RandomUtil.int(1, 3)) {\n                                            1 -> invokestatic(\"java/lang/Float\", \"isInfinite\", \"(F)Z\", false)\n                                            2 -> invokestatic(\"java/lang/Float\", \"isNaN\", \"(F)Z\", false)\n                                        }\n                                    }\n                                    2 -> {\n                                        ldc(RandomUtil.double(1.0, 200.0))\n                                        when (RandomUtil.int(1, 3)) {\n                                            1 -> invokestatic(\"java/lang/Double\", \"isInfinite\", \"(D)Z\", false)\n                                            2 -> invokestatic(\"java/lang/Double\", \"isNaN\", \"(D)Z\", false)\n                                        }\n                                    }\n                                }\n                            }\n                            3 -> {\n\n                            }\n                        }\n\n                        val labelNode = LabelNode()\n\n                        when (type) {\n                            1 -> {\n                                when {\n                                    bool -> {\n                                        ifeq(labelNode)\n                                    }\n                                    else -> {\n                                        ifne(labelNode)\n                                    }\n                                }\n                            }\n                            else -> ifeq(labelNode)\n                        }\n\n                        val labelNode1 = LabelNode()\n                        +labelNode1\n                        // start\n                        // todo make switch with shit code.\n                        when(RandomUtil.int(1, 3)) {\n                            1 -> {\n                                val size = RandomUtil.int(1, 30)\n                                val stringBuilder = StringBuilder()\n                                stringBuilder.append(\"(\")\n                                repeat((1..size).count()) { stringBuilder.append(\"Ljava/lang/String;\") }\n                                stringBuilder.append(\")V\")\n\n                                repeat((1..RandomUtil.int(3, 10)).count()) {\n                                    +LabelNode()\n                                    val className = '\\u0000' + StringUtil.getStringWithJavaKeywords(6)\n                                    new(className)\n                                    repeat((1..size).count()) { ldc(StringUtil.generateString(6)) }\n\n                                    invokespecial(\n                                        className,\n                                        \"<init>\",\n                                        stringBuilder.toString(),\n                                        false\n                                    )\n                                    +LabelNode()\n                                }\n                            }\n                            2 -> {\n                                val list = mutableListOf<Pair<LabelNode, Int>>()\n                                repeat((0..RandomUtil.int(10, 30)).count()) { list.add(Pair(LabelNode(), it))}\n                                val label3 = LabelNode()\n\n                                val labels = mutableListOf<LabelNode>()\n                                val ints = mutableListOf<Int>()\n                                list.forEach {\n                                    labels.add(it.first)\n                                    ints.add(it.second)\n                                }\n                                labels.add(label3)\n                                ints.add(100)\n\n                                +LabelNode()\n                                ldc(RandomUtil.int(10, 2000))\n                                ldc(RandomUtil.int(10, 2000))\n                                ixor()\n                                lookupswitch(label3, Pair(ints.toIntArray(), labels.toTypedArray()))\n                                +label3\n                                frame(F_SAME, 0, null, 0, null)\n                                goto(label3)\n\n                                labels.remove(label3)\n                                labels.forEach {\n                                    +it\n                                    frame(F_SAME, 0, null, 0, null)\n                                    when(RandomUtil.int(1, 6)) {\n                                        1 -> {\n                                            new(\"java/lang/NullPointerException\")\n                                            dup()\n                                            ldc(\"AlpheratzObfuscator\")\n                                            invokespecial(\n                                                \"java/lang/NullPointerException\",\n                                                \"<init>\",\n                                                \"(Ljava/lang/String;)V\",\n                                                false\n                                            )\n                                            athrow()\n                                        }\n                                        2 -> {\n                                            val size = RandomUtil.int(1, 30)\n                                            val stringBuilder = StringBuilder()\n                                            stringBuilder.append(\"(\")\n                                            repeat((1..size).count()) { stringBuilder.append(\"Ljava/lang/String;\") }\n                                            stringBuilder.append(\")V\")\n\n                                            repeat((1..RandomUtil.int(3, 10)).count()) {\n                                                +LabelNode()\n                                                val className = '\\u0000' + StringUtil.getStringWithJavaKeywords(6)\n                                                new(className)\n                                                repeat((1..size).count()) { ldc(StringUtil.generateString(6)) }\n\n                                                invokespecial(\n                                                    className,\n                                                    \"<init>\",\n                                                    stringBuilder.toString(),\n                                                    false\n                                                )\n                                                +LabelNode()\n                                            }\n                                        }\n                                        3 -> {\n                                            ldc(\"AlpheratzObfuscator - https://github.com/alpheratzteam/obfuscator\")\n                                            printlnAsm()\n                                        }\n                                        4 -> {\n                                            aconst_null()\n                                            athrow()\n                                        }\n                                        else -> goto(label3)\n                                    }\n                                }\n\n                                +LabelNode()\n                            }\n                        }\n                        // shit code\n                        // end\n                        +labelNode\n                        frame(F_SAME, 0, null, 0, null)\n//                        +LabelNode()\n                    })\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/TrashExceptionTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer\n\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport java.io.IOException\nimport java.lang.annotation.AnnotationTypeMismatchException\nimport java.nio.BufferUnderflowException\nimport kotlin.reflect.KClass\n\n/**\n * @author Unix\n * @since 04.04.2021\n */\n\nclass TrashExceptionTransformer : Transformer {\n\n    // TODO: 04.04.2021 get automatic all exceptions from package java/util\n\n    private val exceptions = listOf(get(Exception::class), get(IOException::class), get(BufferUnderflowException::class), get(ExceptionInInitializerError::class),\n        get(ArrayIndexOutOfBoundsException::class), get(ArrayStoreException::class), get(AnnotationTypeMismatchException::class))\n\n    override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.methods.forEach { it.exceptions.addAll(exceptions) } }\n\n    fun <T : Any> get(any: KClass<T>) = any.qualifiedName?.replace(\".\", \"/\")\n\n//    fun <T : Any> gets(classes: List<KClass<T>>) : List<String> {\n//        val list = mutableListOf<String>()\n//        classes.forEach { get(it)?.let { list.add(it) } }\n//\n//        return list\n//    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/FieldAccessTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer.optimizer\n\nimport org.objectweb.asm.Opcodes.ACC_FINAL\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.ASMUtil\n\n/**\n * @author Unix\n * @since 07.04.2021\n */\n\nclass FieldAccessTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.stream()\n            .flatMap { it.fields.stream() }\n            .filter { ASMUtil.isFinal(it.access) }\n            .forEach { it.access -= ACC_FINAL }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/GotoInlinerTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer.optimizer\n\nimport org.objectweb.asm.Opcodes.GOTO\nimport org.objectweb.asm.tree.JumpInsnNode\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\nimport pl.alpheratzteam.obfuscator.util.ConditionUtil\nimport java.util.*\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass GotoInlinerTransformer : Transformer {\n\n    override fun transform(obfuscator: Obfuscator) {\n        obfuscator.classes.values.forEach {\n            it.methods.forEach {\n                it.instructions.filter { it.opcode == GOTO }.forEach {\n                    val gotoJump = it as JumpInsnNode\n                    val insnAfterTarget = gotoJump.label.next\n                    ConditionUtil.checkCondition(Objects.nonNull(insnAfterTarget)) {\n                        when (insnAfterTarget.opcode) {\n                            GOTO -> gotoJump.label = (insnAfterTarget as JumpInsnNode).label\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/transformer/optimizer/NopRemoverTransformer.kt",
    "content": "package pl.alpheratzteam.obfuscator.transformer.optimizer\n\nimport org.objectweb.asm.Opcodes.NOP\nimport pl.alpheratzteam.obfuscator.Obfuscator\nimport pl.alpheratzteam.obfuscator.api.transformer.Transformer\n\n/**\n * @author Unix\n * @since 18.12.2020\n */\n\nclass NopRemoverTransformer : Transformer {\n    override fun transform(obfuscator: Obfuscator) = obfuscator.classes.values.forEach { it.methods.forEach { methodNode -> methodNode.instructions.filter { it.opcode == NOP }.forEach { methodNode.instructions.remove(it) } } }\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/AsmUtil.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.commons.CodeSizeEvaluator\nimport org.objectweb.asm.tree.*\nimport java.util.*\nimport kotlin.collections.HashMap\nimport kotlin.collections.any\nimport kotlin.collections.filterIndexed\nimport kotlin.collections.forEachIndexed\nimport kotlin.collections.set\n\n// https://github.com/ByteZ1337/Vetric/blob/master/src/main/kotlin/xyz/xenondevs/obfuscator/utils/asm/ASMUtils.kt\n\nobject ASMUtil {\n\n    /* ------------------ Constants ------------------ */\n\n    const val OBJECT_TYPE = \"java/lang/Object\"\n\n    /* ------------------ Access Checks ------------------ */\n\n    fun isPublic(access: Int) = access and ACC_PUBLIC != 0\n\n    fun isPrivate(access: Int) = access and ACC_PRIVATE != 0\n\n    fun isProtected(access: Int) = access and ACC_PROTECTED != 0\n\n    fun isStatic(access: Int) = access and ACC_STATIC != 0\n\n    fun isFinal(access: Int) = access and ACC_FINAL != 0\n\n    fun isAbstract(access: Int) = access and ACC_ABSTRACT != 0\n\n    fun isNative(access: Int) = access and ACC_NATIVE != 0\n\n    fun isEnum(access: Int) = access and ACC_ENUM != 0\n\n    fun isInterface(access: Int) = access and ACC_INTERFACE != 0\n\n    fun isAnnotation(access: Int) = access and ACC_ANNOTATION != 0\n\n    fun isBridge(access: Int) = access and ACC_BRIDGE != 0\n\n    fun isMandated(access: Int) = access and ACC_MANDATED != 0\n\n    fun isModule(access: Int) = access and ACC_MODULE != 0\n\n    fun isOpen(access: Int) = access and ACC_OPEN != 0\n\n    fun isStaticPhase(access: Int) = access and ACC_STATIC_PHASE != 0\n\n    fun isSuper(access: Int) = access and ACC_SUPER != 0\n\n    fun isSynchronized(access: Int) = access and ACC_SYNCHRONIZED != 0\n\n    fun isSynthetic(access: Int) = access and ACC_SYNTHETIC != 0\n\n    fun isTransient(access: Int) = access and ACC_TRANSIENT != 0\n\n    fun isTransitive(access: Int) = access and ACC_TRANSITIVE != 0\n\n    fun isVolatile(access: Int) = access and ACC_VOLATILE != 0\n\n    fun isVarargs(access: Int) = access and ACC_VARARGS != 0\n\n    fun isDeprecated(access: Int) = access and ACC_DEPRECATED != 0\n\n    fun isStrict(access: Int) = access and ACC_STRICT != 0\n\n    fun AnnotationNode.toHashMap(): HashMap<String, Any?> {\n        val map = HashMap<String, Any?>()\n        values.filterIndexed { index, _ -> index % 2 == 0 }.forEachIndexed { index, any ->\n            map[any.toString()] = values[index * 2 + 1]\n        }\n        return map\n    }\n\n    fun hasMethod(name: String, desc: String, clazz: ClassNode) =\n        clazz.methods != null && clazz.methods.any { it.desc == desc && it.name == name }\n\n    fun getIntInsn(value: Int) =\n        when (value) {\n            in -1..5 -> InsnNode(value + 3)\n            in Byte.MIN_VALUE..Byte.MAX_VALUE -> IntInsnNode(BIPUSH, value)\n            in Short.MIN_VALUE..Short.MAX_VALUE -> IntInsnNode(SIPUSH, value)\n            else -> LdcInsnNode(value)\n        }\n\n    fun getLongInsn(value: Long) =\n        when (value) {\n            in 0..1 -> InsnNode((value + 9).toInt())\n            else -> LdcInsnNode(value)\n        }\n\n    fun getFloatInsn(value: Float) =\n        when {\n            value % 1 == 0f && value in 0f..2f -> InsnNode((value + 11).toInt())\n            else -> LdcInsnNode(value)\n        }\n\n    fun getDoubleInsn(value: Double) =\n        when {\n            value % 1 == 0.0 && value in 0.0..1.0 -> InsnNode((value + 14).toInt())\n            else -> LdcInsnNode(value)\n        }\n\n    fun isIntInsn(insn: AbstractInsnNode): Boolean {\n        return when {\n            Objects.isNull(insn) -> false\n            else -> {\n                val opcode = insn.opcode\n                (opcode in ICONST_M1..ICONST_5 || opcode == BIPUSH || opcode == SIPUSH || (insn is LdcInsnNode && insn.cst is Int))\n            }\n        }\n    }\n\n    fun isLongInsn(insn: AbstractInsnNode): Boolean = insn.opcode == LCONST_0 || insn.opcode == LCONST_1 || (insn is LdcInsnNode && insn.cst is Long)\n\n    fun isFloatInsn(insn: AbstractInsnNode): Boolean = (insn.opcode in FCONST_0..FCONST_2 || insn is LdcInsnNode && insn.cst is Float)\n\n    fun isDoubleInsn(insn: AbstractInsnNode): Boolean = (insn.opcode in DCONST_0..DCONST_1 || insn is LdcInsnNode && insn.cst is Double)\n\n    // https://github.com/ItzSomebody/radon/blob/master/src/main/java/me/itzsomebody/radon/utils/ASMUtils.java\n\n    fun getIntFromInsn(insn: AbstractInsnNode): Int {\n        val opcode = insn.opcode\n        return when {\n            opcode in ICONST_M1..ICONST_5 -> opcode - 3\n            insn is IntInsnNode && insn.opcode !== NEWARRAY -> insn.operand\n            insn is LdcInsnNode && insn.cst is Int -> insn.cst as Int\n            else -> throw UnsupportedOperationException()\n        }\n    }\n\n    fun getLongFromInsn(insn: AbstractInsnNode): Long {\n        val opcode = insn.opcode\n        return when {\n            opcode in LCONST_0..LCONST_1 -> (opcode - 9).toLong()\n            insn is LdcInsnNode && insn.cst is Long -> insn.cst as Long\n            else -> 0L\n        }\n    }\n\n    fun getFloatFromInsn(insn: AbstractInsnNode): Float {\n        val opcode = insn.opcode\n        return when {\n            opcode in FCONST_0..FCONST_2 -> (opcode - 11).toFloat()\n            insn is LdcInsnNode && insn.cst is Float -> insn.cst as Float\n            else -> .0f\n        }\n    }\n\n    fun getDoubleFromInsn(insn: AbstractInsnNode): Double {\n        val opcode = insn.opcode\n        return when {\n            opcode in DCONST_0..DCONST_1 -> (opcode - 14).toDouble()\n            insn is LdcInsnNode && insn.cst is Double -> insn.cst as Double\n            else -> .0\n        }\n    }\n\n    fun isInstruction(insn: AbstractInsnNode?) = insn !is FrameNode && insn !is LineNumberNode && insn !is LabelNode\n\n    fun getMaxSize(methodNode: MethodNode): Int {\n        val codeSizeEvaluator = CodeSizeEvaluator(null)\n        methodNode.accept(codeSizeEvaluator)\n        return codeSizeEvaluator.getMaxSize()\n    }\n\n    fun hasInstructions(methodNode: MethodNode) = Objects.nonNull(methodNode.instructions) && methodNode.instructions.size() > 0\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/ConditionUtil.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\n/**\n * @author Unix\n * @since 30.03.2021\n */\n\nobject ConditionUtil {\n\n    /**\n     * Checks some conditions.\n     * if **true**, runs [Runnable].\n     * @param condition as conditions to check.\n     * @param runnable as runnable to run.\n     * @see [Runnable]\n     */\n    fun checkCondition(condition: Boolean, runnable: Runnable) {\n        if (!condition) {\n            return\n        }\n\n        runnable.run()\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/InsnBuilder.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport org.objectweb.asm.Handle\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.Type\nimport org.objectweb.asm.tree.*\n\n/**\n * @author cookiedragon234, ByteZ\n */\n\nclass InsnBuilder {\n\n    val list = InsnList()\n\n    operator fun InsnList.unaryPlus() = list.add(this)\n    operator fun AbstractInsnNode.unaryPlus() = list.add(this)\n    fun Int.insn() = InsnNode(this)\n\n    fun insn(opcode: Int) = +InsnNode(opcode)\n\n    fun nop() = insn(NOP)\n\n    /* Loading constant values */\n\n    fun aconst_null() = insn(ACONST_NULL)\n    fun ldc(int: Int) = +ASMUtil.getIntInsn(int)\n    fun ldc(long: Long) = +ASMUtil.getLongInsn(long)\n    fun ldc(float: Float) = +ASMUtil.getFloatInsn(float)\n    fun ldc(double: Double) = +ASMUtil.getDoubleInsn(double)\n    fun ldc(string: String) = +LdcInsnNode(string)\n    fun ldc(type: Type) = +LdcInsnNode(type)\n    fun ldc(handle: Handle) = +LdcInsnNode(handle)\n\n    /* Locals */\n\n    fun istore(`var`: Int) = +VarInsnNode(ISTORE, `var`)\n    fun iload(`var`: Int) = +VarInsnNode(ILOAD, `var`)\n    fun lstore(`var`: Int) = +VarInsnNode(LSTORE, `var`)\n    fun lload(`var`: Int) = +VarInsnNode(LLOAD, `var`)\n    fun fstore(`var`: Int) = +VarInsnNode(FSTORE, `var`)\n    fun fload(`var`: Int) = +VarInsnNode(FLOAD, `var`)\n    fun dstore(`var`: Int) = +VarInsnNode(DSTORE, `var`)\n    fun dload(`var`: Int) = +VarInsnNode(DLOAD, `var`)\n    fun astore(`var`: Int) = +VarInsnNode(ASTORE, `var`)\n    fun aload(`var`: Int) = +VarInsnNode(ALOAD, `var`)\n\n    /* Array storing & loading */\n\n    fun iastore() = insn(IASTORE)\n    fun iaload() = insn(IALOAD)\n    fun lastore() = insn(LASTORE)\n    fun laload() = insn(LALOAD)\n    fun fastore() = insn(FASTORE)\n    fun faload() = insn(FALOAD)\n    fun dastore() = insn(DASTORE)\n    fun daload() = insn(DALOAD)\n    fun aastore() = insn(AASTORE)\n    fun aaload() = insn(AALOAD)\n    fun bastore() = insn(BASTORE)\n    fun baload() = insn(BALOAD)\n    fun castore() = insn(CASTORE)\n    fun caload() = insn(CALOAD)\n    fun sastore() = insn(SASTORE)\n    fun saload() = insn(SALOAD)\n\n    /* Stack manipulation */\n\n    fun pop() = insn(POP)\n    fun pop2() = insn(POP2)\n    fun dup() = insn(DUP)\n    fun dup_x1() = insn(DUP_X1)\n    fun dup_x2() = insn(DUP_X2)\n    fun dup2() = insn(DUP2)\n    fun dup2_x1() = insn(DUP2_X1)\n    fun dup2_x2() = insn(DUP2_X2)\n    fun swap() = insn(SWAP)\n\n    /* Arithmetic & Bitwise */\n\n    fun iadd() = insn(IADD)\n    fun isub() = insn(ISUB)\n    fun imul() = insn(IMUL)\n    fun idiv() = insn(IDIV)\n    fun irem() = insn(IREM)\n    fun ineg() = insn(INEG)\n    fun ishl() = insn(ISHL)\n    fun ishr() = insn(ISHR)\n    fun iushr() = insn(IUSHR)\n    fun iand() = insn(IAND)\n    fun ior() = insn(IOR)\n    fun ixor() = insn(IXOR)\n    fun iinc(`var`: Int, incr: Int) = +IincInsnNode(`var`, incr)\n\n    fun ladd() = insn(LADD)\n    fun lsub() = insn(LSUB)\n    fun lmul() = insn(LMUL)\n    fun ldiv() = insn(LDIV)\n    fun lrem() = insn(LREM)\n    fun lneg() = insn(LNEG)\n    fun lshl() = insn(LSHL)\n    fun lshr() = insn(LSHR)\n    fun lushr() = insn(LUSHR)\n    fun lor() = insn(LOR)\n    fun land() = insn(LAND)\n    fun lxor() = insn(LXOR)\n\n    fun fadd() = insn(FADD)\n    fun fsub() = insn(FSUB)\n    fun fmul() = insn(FMUL)\n    fun fdiv() = insn(FDIV)\n    fun frem() = insn(FREM)\n    fun fneg() = insn(FNEG)\n\n    fun dadd() = insn(DADD)\n    fun dsub() = insn(DSUB)\n    fun dmul() = insn(DMUL)\n    fun ddiv() = insn(DDIV)\n    fun drem() = insn(DREM)\n    fun dneg() = insn(DNEG)\n\n    /* Primitive type conversion */\n\n    fun i2l() = insn(I2L)\n    fun i2f() = insn(I2F)\n    fun i2d() = insn(I2D)\n    fun i2b() = insn(I2B)\n    fun i2c() = insn(I2C)\n    fun i2s() = insn(I2S)\n    fun l2i() = insn(L2I)\n    fun l2f() = insn(L2F)\n    fun l2d() = insn(L2D)\n    fun f2i() = insn(F2I)\n    fun f2l() = insn(F2L)\n    fun f2d() = insn(F2D)\n    fun d2i() = insn(D2I)\n    fun d2l() = insn(D2L)\n    fun d2f() = insn(D2F)\n\n    /* Number comparisons */\n\n    fun lcmp() = insn(LCMP)\n    fun fcmpl() = insn(FCMPL)\n    fun fcmpg() = insn(FCMPG)\n    fun dcmpl() = insn(DCMPL)\n    fun dcmpg() = insn(DCMPG)\n\n    /* Jumping */\n\n    fun goto(label: LabelNode) = +JumpInsnNode(GOTO, label)\n    fun jsr(label: LabelNode) = +JumpInsnNode(JSR, label)\n\n    fun ifeq(label: LabelNode) = +JumpInsnNode(IFEQ, label)\n    fun ifne(label: LabelNode) = +JumpInsnNode(IFNE, label)\n    fun iflt(label: LabelNode) = +JumpInsnNode(IFLT, label)\n    fun ifle(label: LabelNode) = +JumpInsnNode(IFLE, label)\n    fun ifge(label: LabelNode) = +JumpInsnNode(IFGE, label)\n    fun ifgt(label: LabelNode) = +JumpInsnNode(IFGT, label)\n\n    fun if_icmplt(label: LabelNode) = +JumpInsnNode(IF_ICMPLT, label)\n    fun if_icmple(label: LabelNode) = +JumpInsnNode(IF_ICMPLE, label)\n    fun if_icmpge(label: LabelNode) = +JumpInsnNode(IF_ICMPGE, label)\n    fun if_icmpgt(label: LabelNode) = +JumpInsnNode(IF_ICMPGT, label)\n    fun if_icmpeq(label: LabelNode) = +JumpInsnNode(IF_ICMPEQ, label)\n    fun if_icmpne(label: LabelNode) = +JumpInsnNode(IF_ICMPNE, label)\n    fun if_acmpeq(label: LabelNode) = +JumpInsnNode(IF_ACMPEQ, label)\n\n    fun ifnull(label: LabelNode) = +JumpInsnNode(IFNULL, label)\n    fun ifnonnull(label: LabelNode) = +JumpInsnNode(IFNONNULL, label)\n\n//    fun tableswitch(baseNumber: Int, dflt: LabelNode, vararg targets: LabelNode) = +constructTableSwitch(baseNumber, dflt, *targets)\n    fun lookupswitch(defaultLabel: LabelNode, lookup: Pair<IntArray, Array<LabelNode>>) = +LookupSwitchInsnNode(defaultLabel, lookup.first, lookup.second)\n\n    /* Fields */\n\n    fun getstatic(owner: String, name: String, desc: String) = +FieldInsnNode(GETSTATIC, owner, name, desc)\n    fun putstatic(owner: String, name: String, desc: String) = +FieldInsnNode(PUTSTATIC, owner, name, desc)\n    fun getfield(owner: String, name: String, desc: String) = +FieldInsnNode(GETFIELD, owner, name, desc)\n    fun putfield(owner: String, name: String, desc: String) = +FieldInsnNode(PUTFIELD, owner, name, desc)\n\n    /* Method invocation */\n\n    fun invokevirtual(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKEVIRTUAL, owner, name, desc, `interface`)\n    fun invokespecial(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKESPECIAL, owner, name, desc, `interface`)\n    fun invokestatic(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKESTATIC, owner, name, desc, `interface`)\n    fun invokeinterface(owner: String, name: String, desc: String, `interface`: Boolean = false) = +MethodInsnNode(INVOKEINTERFACE, owner, name, desc, `interface`)\n\n    /* Creating new instances */\n\n    fun new(type: String) = +TypeInsnNode(NEW, type)\n    fun newarray(type: Int) = +IntInsnNode(NEWARRAY, type)\n    fun anewarray(desc: String) = +TypeInsnNode(ANEWARRAY, desc)\n    fun newboolarray() = newarray(T_BOOLEAN)\n    fun newchararray() = newarray(T_CHAR)\n    fun newbytearray() = newarray(T_BYTE)\n    fun newshortarray() = newarray(T_SHORT)\n    fun newintarray() = newarray(T_INT)\n    fun newlongarray() = newarray(T_LONG)\n    fun newfloatarray() = newarray(T_FLOAT)\n    fun newdoublearray() = newarray(T_DOUBLE)\n\n    /* Array information */\n\n    fun arraylength() = insn(ARRAYLENGTH)\n\n    /* Throwing exceptions */\n\n    fun athrow() = insn(ATHROW)\n\n    /* Type checks and casts */\n\n    fun checkcast(descriptor: String) = +TypeInsnNode(CHECKCAST, descriptor)\n    fun instanceof(descriptor: String) = +TypeInsnNode(INSTANCEOF, descriptor)\n\n    /* Returns */\n\n    fun ireturn() = insn(IRETURN)\n    fun lreturn() = insn(LRETURN)\n    fun freturn() = insn(FRETURN)\n    fun dreturn() = insn(DRETURN)\n    fun areturn() = insn(ARETURN)\n    fun _return() = insn(RETURN)\n\n\n    /* Frames */\n    fun frame(type: Int, numLocal: Int, local: Array<Any>?, numStack: Int, stack: Array<Any>?) = +FrameNode(type, numLocal, local, numStack, stack)\n}\n\nfun insnBuilder(builder: InsnBuilder.() -> Unit) = InsnBuilder().also(builder).list"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/JarUtil.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport org.objectweb.asm.ClassReader\nimport org.objectweb.asm.ClassWriter\nimport org.objectweb.asm.tree.ClassNode\nimport java.io.*\nimport java.lang.Exception\nimport java.util.jar.JarEntry\nimport java.util.jar.JarFile\nimport java.util.jar.JarOutputStream\nimport java.util.zip.CRC32\nimport java.util.zip.ZipOutputStream\n\n/**\n * @author Unix\n * @since 16.12.2020\n */\n\nobject JarUtil {\n\n    /**\n     * Loads jar file as [Pair].\n     * @param file input file.\n     * @return [Pair] as readed content from the file.\n     */\n    fun loadJar(file: File): Pair<MutableMap<String, ClassNode>, MutableMap<String, ByteArray>> {\n        val classes = mutableMapOf<String, ClassNode>()\n        val assets = mutableMapOf<String, ByteArray>()\n\n        JarFile(file).use {\n            val entries = it.entries()\n            while (entries.hasMoreElements()) {\n                val jarEntry = entries.nextElement()\n                try {\n                    val bytes = asByteArray(it.getInputStream(jarEntry))\n                    if (!jarEntry.name.endsWith(\".class\")) {\n                        assets[jarEntry.name] = bytes\n                        continue\n                    }\n\n                    val classNode = ClassNode()\n                    val classReader = ClassReader(bytes)\n                    classReader.accept(classNode, ClassReader.EXPAND_FRAMES)\n                    classes[classNode.name] = classNode\n                } catch (ex: Exception) {\n                    ex.printStackTrace()\n                }\n            }\n        }\n\n        return Pair(classes, assets)\n    }\n\n    /**\n     * Saves contents to jar file.\n     * @param file output file.\n     * @param pair content to save.\n     * @throws [IOException] thrown when error is occurred.\n     */\n    @Throws(IOException::class)\n    fun saveJar(file: File, pair: Pair<MutableMap<String, ClassNode>, MutableMap<String, ByteArray>>) {\n        JarOutputStream(FileOutputStream(file)).use {\n            corrupt(it) // TODO: 04.04.2021 add this to configuration\n\n            pair.first.values.forEach { classNode ->\n                val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)\n                it.putNextEntry(JarEntry(classNode.name + \".class\"))\n                classNode.accept(classWriter)\n                it.write(classWriter.toByteArray())\n                it.closeEntry()\n            }\n\n            pair.second.forEach { (key, value) ->\n                run {\n                    it.putNextEntry(JarEntry(key))\n                    it.write(value)\n                    it.closeEntry()\n                }\n            }\n        }\n    }\n\n    /**\n     * This methods reads content from [InputStream] to [ByteArray].\n     * @param inputStream stream to read.\n     * @return [ByteArray] readed data.\n     */\n    private fun asByteArray(inputStream: InputStream): ByteArray {\n        return try {\n            val out = ByteArrayOutputStream()\n\n            var readed: Int\n            while (inputStream.read().also { readed = it } != -1) {\n                out.write(readed)\n            }\n\n            inputStream.close()\n            out.toByteArray()\n        } catch (ex: Exception) {\n            ex.printStackTrace()\n            ByteArray(0)\n        }\n    }\n\n    /**\n     * Corrupts the contents of the zip file.\n     * @param outputStream stream to corrupt\n     * @see [ZipOutputStream]\n     */\n    private fun corrupt(outputStream: ZipOutputStream) {\n        val field = ZipOutputStream::class.java.getDeclaredField(\"crc\")\n        field.isAccessible = true\n        field[outputStream] = object : CRC32() {\n            override fun getValue() = RandomUtil.int(Int.MAX_VALUE).toLong()\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/RandomUtil.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport java.util.concurrent.ThreadLocalRandom\n\n/**\n * @author Unix\n * @since 17.12.2020\n */\n\nobject RandomUtil {\n\n    private val random = ThreadLocalRandom.current()\n\n    /**\n     * Randomizes a number.\n     * @param max as max int range.\n     * @return [Int] randomized int value.\n     */\n    fun int(max: Int) = random.nextInt(max)\n\n    /**\n     * Randomizes a number.\n     * @return [Int] randomized int value.\n     */\n    fun int() = random.nextInt()\n\n    /**\n     * Randomizes a number.\n     * @return [Double] randomized double value.\n     */\n    fun double() = random.nextDouble()\n\n    /**\n     * Randomizes a number.\n     * @return [Float] randomized float value.\n     */\n    fun float() = random.nextFloat()\n\n    /**\n     * Randomizes a number.\n     * @param min as min value to randomize.\n     * @param max as max value to randomize.\n     * @return [Int] randomized int value.\n     */\n    fun int(min: Int, max: Int) = random.nextInt(min, max)\n\n    /**\n     * Randomizes a number.\n     * @param [min] as min value to randomize.\n     * @param [max] as max value to randomize.\n     * @return [Double] randomized double value.\n     */\n    fun double(min: Double, max: Double) = random.nextDouble(min, max)\n\n    /**\n     * Randomizes a number.\n     * @param [min] as min value to randomize.\n     * @param [max] as max value to randomize.\n     * @return [Float] randomized float value.\n     */\n    fun float(min: Double, max: Double) = double(min, max).toFloat()\n\n    /**\n     * Randomizes the chance.\n     * @param chance as chance to check.\n     * @return [Boolean], if `true` chance is right.\n     */\n    fun chance(chance: Double) = Math.random() * 100.0 <= chance\n\n    /**\n     * Randomizes a boolean.\n     * @return [Boolean] randomized boolean value.\n     */\n    fun boolean() = random.nextBoolean()\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/StringUtil.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport java.lang.StringBuilder\nimport java.util.stream.Collectors\nimport java.util.stream.IntStream\nimport java.util.concurrent.ThreadLocalRandom\n\n/**\n * @author Unix\n * @since 17.12.2020\n */\n\nobject StringUtil {\n\n    private val chars = \"abcdefghijklmnopqrstuvwxyz1234567890\".toCharArray()\n    private val javaKeywords = mutableListOf(\n        \"abstract\", \"boolean\", \"break\", \"byte\", \"case\", \"catch\", \"char\", \"class\",\n        \"continue\", \"default\", \"do\", \"while\", \"for\", \"if\",\n        \"\\u0000\", \"\\u0001\", \"\\u0002\", \"\\u0004\",\n        \"double\", \"else\", \"new\", \"null\", \"return\", \"short\",\n        \"super\", \"static\", \"switch\", \"try\", \"void\",\n        \"while\", \"volatile\"\n    )\n\n    /**\n     * Generates custom string.\n     * @param length length of the generated string.\n     * @return [String] as generated string.\n     */\n    fun generateString(length: Int): String {\n        return IntStream.range(0, length)\n            .mapToObj {\n                Character.toString(\n                    chars[RandomUtil.int(chars.size)]\n                )\n            }.collect(Collectors.joining())\n    }\n\n    /**\n     * Generates unreadable string.\n     * @param string string to be encoded.\n     * @return [String] as unreadable generated string.\n     */\n    fun makeUnreadable(string: String): String { // generate unreadable string\n        val stringBuilder = StringBuilder()\n        string.toCharArray().forEach { stringBuilder.append((it + '\\u7159'.toInt())) }\n        return stringBuilder.toString()\n    }\n\n    /**\n     * Generates java keyword string.\n     * @param length length of the generated string.\n     * @return [String] as java keyword generated string.\n     */\n    fun getStringWithJavaKeywords(length: Int): String {\n        val stringBuilder = StringBuilder()\n        for (index in 0..length) {\n            val keyword = javaKeywords[ThreadLocalRandom.current().nextInt(0, javaKeywords.size)]\n\n            when {\n                index != 24 -> {\n                    stringBuilder.append(keyword).append(\" \")\n                } else -> {\n                    stringBuilder.append(keyword)\n                }\n            }\n        }\n\n        return stringBuilder.toString()\n    }\n\n}"
  },
  {
    "path": "src/main/kotlin/pl/alpheratzteam/obfuscator/util/Util.kt",
    "content": "package pl.alpheratzteam.obfuscator.util\n\nimport org.objectweb.asm.Type\nimport org.objectweb.asm.Opcodes.*\nimport org.objectweb.asm.tree.*\nimport java.io.PrintStream\nimport kotlin.reflect.KClass\nimport kotlin.reflect.KFunction\n\n/**\n * @author cookiedragon234 23/Apr/2020\n */\ninline fun <reified T: Any> Any?.cast(type: KClass<T>): T = this as T\ninline fun <reified T: Any> Any?.cast(type: Class<T>): T = this as T\n\nval <T: Any> KClass<T>.internalName: String\n    get() = Type.getInternalName(this.java)\n\ninline val KFunction<*>.descriptor: String\n    inline get() {\n        val params = parameters.map { Type.getType(it.type.classifier.cast(KClass::class).java) }\n        val returnType = Type.getType(returnType.classifier.cast(KClass::class).java)\n        return Type.getMethodDescriptor(returnType, *params.toTypedArray())\n    }\n\nfun InsnList.add(opcode: Int) = add(InsnNode(opcode))\n\nfun ldcInt(int: Int): AbstractInsnNode {\n    return if (int == -1) {\n        InsnNode(ICONST_M1)\n    } else if (int == 0) {\n        InsnNode(ICONST_0)\n    } else if (int == 1) {\n        InsnNode(ICONST_1)\n    } else if (int == 2) {\n        InsnNode(ICONST_2)\n    } else if (int == 3) {\n        InsnNode(ICONST_3)\n    } else if (int == 4) {\n        InsnNode(ICONST_4)\n    } else if (int == 5) {\n        InsnNode(ICONST_5)\n    } else if (int >= -128 && int <= 127) {\n        IntInsnNode(BIPUSH, int)\n    } else if (int >= -32768 && int <= 32767) {\n        IntInsnNode(SIPUSH, int)\n    } else {\n        LdcInsnNode(int)\n    }\n}\n\nfun ldcLong(long: Long): AbstractInsnNode {\n    return when (long) {\n        0L -> InsnNode(LCONST_0)\n        1L -> InsnNode(LCONST_1)\n        else -> LdcInsnNode(long)\n    }\n}\n\nfun ldcDouble(double: Double): AbstractInsnNode {\n    return when (double) {\n        0.0 -> InsnNode(DCONST_0)\n        1.0 -> InsnNode(DCONST_1)\n        else -> LdcInsnNode(double)\n    }\n}\n\nfun ldcFloat(float: Float): AbstractInsnNode {\n    return when (float) {\n        0f -> InsnNode(FCONST_0)\n        1f -> InsnNode(FCONST_1)\n        2f -> InsnNode(FCONST_2)\n        else -> LdcInsnNode(float)\n    }\n}\n\ninline fun constructTableSwitch(\n    baseNumber: Int,\n    defaultLabel: LabelNode,\n    vararg targetLabels: LabelNode\n): TableSwitchInsnNode {\n    return TableSwitchInsnNode(\n        baseNumber,\n        baseNumber + targetLabels.size - 1,\n        defaultLabel,\n        *targetLabels\n    )\n}\n\ninline fun constructLookupSwitch(\n    defaultLabel: LabelNode,\n    lookup: Array<Pair<Int, LabelNode>>\n): LookupSwitchInsnNode {\n    lookup.sortWith { a, b -> a.first.compareTo(b.first) }\n\n    val keys = lookup.map {\n        it.first\n    }.toIntArray()\n\n    val values = lookup.map {\n        it.second\n    }.toTypedArray()\n\n    return LookupSwitchInsnNode(\n        defaultLabel,\n        keys,\n        values\n    )\n}\n\nfun InsnList.printlnAsm() {\n    add(FieldInsnNode(GETSTATIC, \"java/lang/System\", \"out\", \"Ljava/io/PrintStream;\"))\n    add(SWAP)\n    add(MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, \"println\", \"(Ljava/lang/Object;)V\", false))\n}\n\nfun InsnBuilder.printlnAsm() {\n    +FieldInsnNode(GETSTATIC, \"java/lang/System\", \"out\", \"Ljava/io/PrintStream;\")\n    +SWAP.insn()\n    +MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, \"println\", \"(Ljava/lang/Object;)V\", false)\n}\n\nfun InsnList.printlnIntAsm() {\n    add(FieldInsnNode(GETSTATIC, System::class.internalName, \"out\", \"Ljava/io/PrintStream;\"))\n    add(InsnNode(SWAP))\n    add(MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, \"println\", \"(I)V\", false))\n}\nfun InsnBuilder.printlnIntAsm() {\n    +FieldInsnNode(GETSTATIC, System::class.internalName, \"out\", \"Ljava/io/PrintStream;\")\n    +SWAP.insn()\n    +MethodInsnNode(INVOKEVIRTUAL, PrintStream::class.internalName, \"println\", \"(I)V\", false)\n}\n\ninline fun InsnList.forEach(op: (insn: AbstractInsnNode) -> Unit) = this.iterator().forEach(op)"
  }
]