⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 decompiler.java

📁 java中比较著名的js引擎当属mozilla开源的rhino
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): *   Mike Ang *   Igor Bukanov *   Mike McCabe * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */package org.mozilla.javascript;/** * The following class save decompilation information about the source. * Source information is returned from the parser as a String * associated with function nodes and with the toplevel script.  When * saved in the constant pool of a class, this string will be UTF-8 * encoded, and token values will occupy a single byte. * Source is saved (mostly) as token numbers.  The tokens saved pretty * much correspond to the token stream of a 'canonical' representation * of the input program, as directed by the parser.  (There were a few * cases where tokens could have been left out where decompiler could * easily reconstruct them, but I left them in for clarity).  (I also * looked adding source collection to TokenStream instead, where I * could have limited the changes to a few lines in getToken... but * this wouldn't have saved any space in the resulting source * representation, and would have meant that I'd have to duplicate * parser logic in the decompiler to disambiguate situations where * newlines are important.)  The function decompile expands the * tokens back into their string representations, using simple * lookahead to correct spacing and indentation. * * Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens * are stored inline, as a NUMBER token, a character representing the type, and * either 1 or 4 characters representing the bit-encoding of the number.  String * types NAME, STRING and OBJECT are currently stored as a token type, * followed by a character giving the length of the string (assumed to * be less than 2^16), followed by the characters of the string * inlined into the source string.  Changing this to some reference to * to the string in the compiled class' constant pool would probably * save a lot of space... but would require some method of deriving * the final constant pool entry from information available at parse * time. */public class Decompiler{    /**     * Flag to indicate that the decompilation should omit the     * function header and trailing brace.     */    public static final int ONLY_BODY_FLAG = 1 << 0;    /**     * Flag to indicate that the decompilation generates toSource result.     */    public static final int TO_SOURCE_FLAG = 1 << 1;    /**     * Decompilation property to specify initial ident value.     */    public static final int INITIAL_INDENT_PROP = 1;    /**     * Decompilation property to specify default identation offset.     */    public static final int INDENT_GAP_PROP = 2;    /**     * Decompilation property to specify identation offset for case labels.     */    public static final int CASE_GAP_PROP = 3;    // Marker to denote the last RC of function so it can be distinguished from    // the last RC of object literals in case of function expressions    private static final int FUNCTION_END = Token.LAST_TOKEN + 1;    String getEncodedSource()    {        return sourceToString(0);    }    int getCurrentOffset()    {        return sourceTop;    }    int markFunctionStart(int functionType)    {        int savedOffset = getCurrentOffset();        addToken(Token.FUNCTION);        append((char)functionType);        return savedOffset;    }    int markFunctionEnd(int functionStart)    {        int offset = getCurrentOffset();        append((char)FUNCTION_END);        return offset;    }    void addToken(int token)    {        if (!(0 <= token && token <= Token.LAST_TOKEN))            throw new IllegalArgumentException();        append((char)token);    }    void addEOL(int token)    {        if (!(0 <= token && token <= Token.LAST_TOKEN))            throw new IllegalArgumentException();        append((char)token);        append((char)Token.EOL);    }    void addName(String str)    {        addToken(Token.NAME);        appendString(str);    }    void addString(String str)    {        addToken(Token.STRING);        appendString(str);    }    void addRegexp(String regexp, String flags)    {        addToken(Token.REGEXP);        appendString('/' + regexp + '/' + flags);    }    void addNumber(double n)    {        addToken(Token.NUMBER);        /* encode the number in the source stream.         * Save as NUMBER type (char | char char char char)         * where type is         * 'D' - double, 'S' - short, 'J' - long.         * We need to retain float vs. integer type info to keep the         * behavior of liveconnect type-guessing the same after         * decompilation.  (Liveconnect tries to present 1.0 to Java         * as a float/double)         * OPT: This is no longer true. We could compress the format.         * This may not be the most space-efficient encoding;         * the chars created below may take up to 3 bytes in         * constant pool UTF-8 encoding, so a Double could take         * up to 12 bytes.         */        long lbits = (long)n;        if (lbits != n) {            // if it's floating point, save as a Double bit pattern.            // (12/15/97 our scanner only returns Double for f.p.)            lbits = Double.doubleToLongBits(n);            append('D');            append((char)(lbits >> 48));            append((char)(lbits >> 32));            append((char)(lbits >> 16));            append((char)lbits);        }        else {            // we can ignore negative values, bc they're already prefixed            // by NEG               if (lbits < 0) Kit.codeBug();            // will it fit in a char?            // this gives a short encoding for integer values up to 2^16.            if (lbits <= Character.MAX_VALUE) {                append('S');                append((char)lbits);            }            else { // Integral, but won't fit in a char. Store as a long.                append('J');                append((char)(lbits >> 48));                append((char)(lbits >> 32));                append((char)(lbits >> 16));                append((char)lbits);            }        }    }    private void appendString(String str)    {        int L = str.length();        int lengthEncodingSize = 1;        if (L >= 0x8000) {            lengthEncodingSize = 2;        }        int nextTop = sourceTop + lengthEncodingSize + L;        if (nextTop > sourceBuffer.length) {            increaseSourceCapacity(nextTop);        }        if (L >= 0x8000) {            // Use 2 chars to encode strings exceeding 32K, were the highest            // bit in the first char indicates presence of the next byte            sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16));            ++sourceTop;        }        sourceBuffer[sourceTop] = (char)L;        ++sourceTop;        str.getChars(0, L, sourceBuffer, sourceTop);        sourceTop = nextTop;    }    private void append(char c)    {        if (sourceTop == sourceBuffer.length) {            increaseSourceCapacity(sourceTop + 1);        }        sourceBuffer[sourceTop] = c;        ++sourceTop;    }    private void increaseSourceCapacity(int minimalCapacity)    {        // Call this only when capacity increase is must        if (minimalCapacity <= sourceBuffer.length) Kit.codeBug();        int newCapacity = sourceBuffer.length * 2;        if (newCapacity < minimalCapacity) {            newCapacity = minimalCapacity;        }        char[] tmp = new char[newCapacity];        System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);        sourceBuffer = tmp;    }    private String sourceToString(int offset)    {        if (offset < 0 || sourceTop < offset) Kit.codeBug();        return new String(sourceBuffer, offset, sourceTop - offset);    }    /**     * Decompile the source information associated with this js     * function/script back into a string.  For the most part, this     * just means translating tokens back to their string     * representations; there's a little bit of lookahead logic to     * decide the proper spacing/indentation.  Most of the work in     * mapping the original source to the prettyprinted decompiled     * version is done by the parser.     *     * @param source encoded source tree presentation     *     * @param flags flags to select output format     *     * @param properties indentation properties     *     */    public static String decompile(String source, int flags,                                   UintMap properties)    {        int length = source.length();        if (length == 0) { return ""; }        int indent = properties.getInt(INITIAL_INDENT_PROP, 0);        if (indent < 0) throw new IllegalArgumentException();        int indentGap = properties.getInt(INDENT_GAP_PROP, 4);        if (indentGap < 0) throw new IllegalArgumentException();        int caseGap = properties.getInt(CASE_GAP_PROP, 2);        if (caseGap < 0) throw new IllegalArgumentException();        StringBuffer result = new StringBuffer();        boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));        boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));        // Spew tokens in source, for debugging.        // as TYPE number char        if (printSource) {            System.err.println("length:" + length);            for (int i = 0; i < length; ++i) {                // Note that tokenToName will fail unless Context.printTrees                // is true.                String tokenname = null;                if (Token.printNames) {                    tokenname = Token.name(source.charAt(i));                }                if (tokenname == null) {                    tokenname = "---";                }                String pad = tokenname.length() > 7                    ? "\t"                    : "\t\t";                System.err.println                    (tokenname                     + pad + (int)source.charAt(i)                     + "\t'" + ScriptRuntime.escapeString                     (source.substring(i, i+1))                     + "'");            }            System.err.println();        }        int braceNesting = 0;        boolean afterFirstEOL = false;        int i = 0;        int topFunctionType;        if (source.charAt(i) == Token.SCRIPT) {            ++i;            topFunctionType = -1;        } else {            topFunctionType = source.charAt(i + 1);        }        if (!toSource) {            // add an initial newline to exactly match js.            result.append('\n');            for (int j = 0; j < indent; j++)                result.append(' ');        } else {            if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {                result.append('(');            }        }        while (i < length) {            switch(source.charAt(i)) {            case Token.NAME:            case Token.REGEXP:  // re-wrapped in '/'s in parser...                i = printSourceString(source, i + 1, false, result);                continue;            case Token.STRING:                i = printSourceString(source, i + 1, true, result);                continue;            case Token.NUMBER:                i = printSourceNumber(source, i + 1, result);                continue;            case Token.TRUE:                result.append("true");                break;            case Token.FALSE:                result.append("false");                break;            case Token.NULL:                result.append("null");                break;            case Token.THIS:                result.append("this");                break;            case Token.FUNCTION:                ++i; // skip function type                result.append("function ");                break;            case FUNCTION_END:                // Do nothing                break;            case Token.COMMA:                result.append(", ");                break;            case Token.LC:                ++braceNesting;                if (Token.EOL == getNext(source, length, i))                    indent += indentGap;                result.append('{');                break;            case Token.RC: {                --braceNesting;                /* don't print the closing RC if it closes the                 * toplevel function and we're called from                 * decompileFunctionBody.                 */                if (justFunctionBody && braceNesting == 0)                    break;                result.append('}');                switch (getNext(source, length, i)) {                    case Token.EOL:                    case FUNCTION_END:                        indent -= indentGap;                        break;                    case Token.WHILE:                    case Token.ELSE:                        indent -= indentGap;                        result.append(' ');                        break;                }                break;            }            case Token.LP:                result.append('(');                break;            case Token.RP:                result.append(')');                if (Token.LC == getNext(source, length, i))                    result.append(' ');                break;            case Token.LB:                result.append('[');                break;            case Token.RB:                result.append(']');                break;            case Token.EOL: {                if (toSource) break;                boolean newLine = true;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -