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

📄 bytecodedisplay.java

📁 Java Bytecode Editor 是一个 JAVA 的字节码反汇编和修改器。它可以很方便的修改已经编译成 Class 文件的 JAVA 文件。
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either
    version 2 of the license, or (at your option) any later version.
*/

package ee.ioc.cs.jbe.browser.detail.attributes.code;

import org.gjt.jclasslib.bytecode.*;
import org.gjt.jclasslib.io.ByteCodeReader;
import org.gjt.jclasslib.structures.ClassFile;
import org.gjt.jclasslib.structures.InvalidByteCodeException;
import org.gjt.jclasslib.structures.attributes.CodeAttribute;

import ee.ioc.cs.jbe.browser.*;


import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.font.*;
import java.io.IOException;
import java.text.AttributedString;
import java.util.*;

/**
    Bytecode renderer.

    @author <a href="mailto:jclasslib@ej-technologies.com">Ingo Kegel</a>
    @version $Revision: 1.2 $ $Date: 2006/09/04 15:43:18 $
*/
public class ByteCodeDisplay extends JPanel implements Scrollable {

    /** Horizontal margin. */
    public static final int MARGIN_X = 3;
    /** Vertical margin. */
    public static final int MARGIN_Y = 3;

    /** Border for the renderer. */
    public static final Border BORDER = new EmptyBorder(MARGIN_Y, MARGIN_X, MARGIN_Y, MARGIN_X);

    private static Map<TextAttribute, Object> STYLE_BASE;
    private static Map<TextAttribute, Object> STYLE_NORMAL;
    private static Map<TextAttribute, Object> STYLE_SMALL;
    private static Map<TextAttribute, Object> STYLE_LINK;
    private static Map<TextAttribute, Object> STYLE_OFFSET;
    private static Map<TextAttribute, Object> STYLE_INSTRUCTION;
    private static Map<TextAttribute, Object> STYLE_IMMEDIATE_VALUE;

    private static final String TAB_STRING = "        ";

    static {
        initStyles(null);
    }

    public static void initStyles(Font baseFont) {

        STYLE_BASE = new HashMap<TextAttribute, Object>(2);
        if (baseFont != null) {
            STYLE_BASE.put(TextAttribute.FAMILY, baseFont.getFamily());
        } else {
            baseFont = UIManager.getFont("TextArea.font");
            STYLE_BASE.put(TextAttribute.FAMILY, "MonoSpaced");
        }

        STYLE_BASE.put(TextAttribute.SIZE, new Float(baseFont.getSize()));

        STYLE_NORMAL = new HashMap<TextAttribute, Object>(0);

        STYLE_SMALL = new HashMap<TextAttribute, Object>(1);
        STYLE_SMALL.put(TextAttribute.SIZE, new Float(baseFont.getSize() - 1));

        STYLE_LINK = new HashMap<TextAttribute, Object>(3);
        STYLE_LINK.put(TextAttribute.FOREGROUND, new Color(0, 128, 0));
        STYLE_LINK.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
        STYLE_LINK.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);

        STYLE_OFFSET = new HashMap<TextAttribute, Object>(1);
        STYLE_OFFSET.put(TextAttribute.FOREGROUND, new Color(128, 0, 0));

        STYLE_INSTRUCTION = new HashMap<TextAttribute, Object>(1);
        STYLE_INSTRUCTION.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);

        STYLE_IMMEDIATE_VALUE = new HashMap<TextAttribute, Object>(2);
        STYLE_IMMEDIATE_VALUE.put(TextAttribute.FOREGROUND, Color.magenta);
        STYLE_IMMEDIATE_VALUE.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
    }

    private ByteCodeDetailPane detailPane;

    private CodeAttribute codeAttribute;
    private ClassFile classFile;

    private int offsetWidth;
    private String offsetBlank;
    private HashMap<Integer, Integer> offsetToLine = new HashMap<Integer, Integer>();
    private ArrayList<AttributedString> lines = new ArrayList<AttributedString>();
    private ArrayList<String> textLines = new ArrayList<String>();
    private TextLayout[] textLayouts;
    private Map<Integer, BytecodeLink> lineToLink = new HashMap<Integer, BytecodeLink>();

    private LinkedList<LineCacheEntry> currentLineCache = new LinkedList<LineCacheEntry>();
    private FontRenderContext frc;
    private float currentHeight;
    private float currentWidth;
    private int lineHeight;
    private int ascent;
    private int characterWidth;

    /**
     * Get the left-padded value for a number.
     * @param number the number
     * @param width the total width.
     * @return the padded string.
     */
    public static String getPaddedValue(int number, int width) {

        StringBuffer buffer = new StringBuffer();
        String value = String.valueOf(number);
        int valueLength = value.length();
        for (int i = valueLength; i < width; i++) {
            buffer.append(' ');
        }
        buffer.append(value);
        return buffer.toString();
    }

    /**
     * Constructor.
     * @param detailPane the parent detail pane.
     */
    public ByteCodeDisplay(ByteCodeDetailPane detailPane) {
        this.detailPane = detailPane;

        setupComponent();
        setupEventHandlers();
    }

    // Scrollable

    public Dimension getPreferredScrollableViewportSize() {
        return null;
    }

    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {

        if (orientation == SwingConstants.HORIZONTAL) {
            return 10;
        } else {
            if (lineHeight == 0) {
                return 1;
            }
            int currentY = ((JViewport)getParent()).getViewPosition().y;
            float line = 1f * (currentY - MARGIN_Y) / lineHeight;
            int targetLine = (int)(direction < 0 ? Math.floor(line) - 1: Math.ceil(line) + 1);
            int targetY = MARGIN_Y + targetLine * lineHeight + 1;
            return Math.abs(currentY - targetY);
        }
    }

    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {

        JViewport viewport = (JViewport)getParent();
        if (orientation == SwingConstants.HORIZONTAL) {
            return viewport.getWidth();
        } else {
            if (lineHeight == 0) {
                return 1;
            }
            int currentY = viewport.getViewPosition().y;
            int rawTargetY = currentY + (direction < 0 ? -1 : 1) * viewport.getHeight();
            float line = 1f * (rawTargetY - MARGIN_Y) / lineHeight;
            int targetLine = (int)(direction < 0 ? Math.ceil(line): Math.floor(line));
            int targetY = MARGIN_Y + targetLine * lineHeight + 1;

            return Math.abs(currentY - targetY);
        }
    }

    public boolean getScrollableTracksViewportWidth() {
        return false;
    }

    public boolean getScrollableTracksViewportHeight() {
        return false;
    }

    // end Scrollable


    /**
     * Get the currently displayed code attribute.
     * @return the code attribute.
     */
    public CodeAttribute getCodeAttribute() {
        return codeAttribute;
    }

    /**
     * Get the current line count.
     * @return the line count.
     */
    public int getLineCount() {
        return lines.size();
    }

    /**
     * Get the current line height.
     * @return the line height.
     */
    public int getLineHeight() {
        return lineHeight;
    }

    /**
     * Get the curent line ascent.
     * @return the line ascent.
     */
    public int getAscent() {
        return ascent;
    }

    /**
     * Set the code attribute that is to be displayed.
     * @param codeAttribute the code attribute.
     * @param classFile the class file of the code attribute.
     */
    public void setCodeAttribute(CodeAttribute codeAttribute, ClassFile classFile) {
        this.codeAttribute = codeAttribute;
        this.classFile = classFile;
        frc = ((Graphics2D)getGraphics()).getFontRenderContext();
        setupTextLayouts();
        invalidate();
    }

    /**
     * Perform a link operation at a given point. Does nothing if there is no
     * link at this point.
     * @param point the point.
     */
    public void link(Point point) {

        BytecodeLink link = getLink(point);
        if (link == null) {
            return;
        }
        updateHistory(link.sourceOffset);

        if (link instanceof ConstantPoolLink) {
            ConstantPoolHyperlinkListener.link(detailPane.getBrowserServices(), ((ConstantPoolLink)link).cpIndex);
        } else if (link instanceof OffsetLink) {
            int targetOffset = ((OffsetLink)link).targetOffset;
            scrollToOffset(targetOffset);
            updateHistory(targetOffset);
        }
    }

    /**
     * Returns whether there is a link below the given point.
     * @param point the point.
     * @return the value.
     */
    public boolean isLink(Point point) {
        return getLink(point) != null;
    }

    /**
     * Scroll the view to a given bytecode offset.
     * @param offset the bytecode offset.
     */
    public void scrollToOffset(int offset) {

        Integer line = (Integer)offsetToLine.get(new Integer(offset));
        if (line == null) {
            return;
        }
        Rectangle target = new Rectangle(0, line.intValue() * lineHeight + MARGIN_Y + 1, 10, getParent().getHeight());
        scrollRectToVisible(target);
    }

    /**
     * Copy the view text to the clipboard.
     */
    public void copyToClipboard() {

        StringBuffer buffer = new StringBuffer();
        Iterator it = textLines.iterator();
        while (it.hasNext()) {
            String line = (String)it.next();
            buffer.append(line);
            buffer.append('\n');
        }
        StringSelection stringSelection = new StringSelection(buffer.toString());
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, stringSelection);
    }

    protected void paintComponent(Graphics graphics) {

        if (lineHeight == 0) {
            return;
        }

        Graphics2D g = (Graphics2D)graphics;
        g.translate(MARGIN_X, MARGIN_Y);
        Rectangle clipBounds = graphics.getClipBounds();
        Paint oldPaint = g.getPaint();
        g.setPaint(Color.WHITE);
        g.fill(clipBounds);
        g.setPaint(oldPaint);
        int startLine = Math.max(0, clipBounds.y / lineHeight - 1);
        int endLine = Math.min(lines.size(), (clipBounds.y + clipBounds.height) / lineHeight + 1);
        for (int i = startLine; i < endLine; i++) {
            TextLayout textLayout = getOrCreateTextLayout(i);
            textLayout.draw(g, 0, i * lineHeight + textLayout.getAscent());
        }

        g.translate(-MARGIN_X, -MARGIN_Y);
    }

    private TextLayout getOrCreateTextLayout(int i) {

        TextLayout textLayout = textLayouts[i];
        if (textLayout == null) {
            textLayout = textLayouts[i] = new TextLayout(((AttributedString)lines.get(i)).getIterator(), frc);
        }
        return textLayout;
    }

    private void setupComponent() {

        setBorder(BORDER);
        setDoubleBuffered(false);
        setOpaque(false);
    }

    private void setupEventHandlers() {
    }

    private BytecodeLink getLink(Point point) {

        if (lineHeight == 0) {
            return null;
        }
        int x = point.x - MARGIN_X;
        int y = point.y - MARGIN_Y;
        int line = y / lineHeight;
        BytecodeLink link = (BytecodeLink)lineToLink.get(new Integer(line));
        if (link == null) {
            return null;
        }

        TextLayout textLayout = getOrCreateTextLayout(line);
        TextHitInfo textHitInfo = textLayout.hitTestChar(x, y - line * lineHeight);
        int charIndex = textHitInfo.getCharIndex();
        if (charIndex >= link.startCharIndex && charIndex < link.endCharIndex) {
            return link;
        } else {
            return null;
        }

⌨️ 快捷键说明

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