PageRenderTime 66ms CodeModel.GetById 55ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/bundles/plugins-trunk/JavaInsight/javainsight/JodeVFS.java

#
Java | 234 lines | 157 code | 41 blank | 36 comment | 29 complexity | a6c5a93bae69f00b1dbcf6ecd32cc915 MD5 | raw file
  1/*
  2 * JodeVFS.java
  3 * Copyright (c) 2001, 2002 Andre Kaplan
  4 *
  5 * jEdit edit mode settings:
  6 * :mode=java:tabSize=4:indentSize=4:noTabs=true:maxLineLen=0:
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23
 24package javainsight;
 25
 26import java.awt.Component;
 27import java.io.*;
 28import java.util.ArrayList;
 29
 30import javainsight.buildtools.ChainedIOException;
 31import javainsight.buildtools.JavaUtils;
 32import net.sf.jode.GlobalOptions;
 33import net.sf.jode.bytecode.ClassInfo;
 34import net.sf.jode.bytecode.ClassPath;
 35import net.sf.jode.decompiler.ClassAnalyzer;
 36import net.sf.jode.decompiler.ImportHandler;
 37import net.sf.jode.decompiler.Options;
 38import net.sf.jode.decompiler.TabbedPrintWriter;
 39
 40import org.apache.bcel.classfile.ClassParser;
 41import org.apache.bcel.classfile.JavaClass;
 42import org.gjt.sp.jedit.Mode;
 43import org.gjt.sp.jedit.jEdit;
 44import org.gjt.sp.jedit.io.VFS;
 45import org.gjt.sp.jedit.io.VFSManager;
 46import org.gjt.sp.util.Log;
 47
 48
 49public class JodeVFS extends ByteCodeVFS
 50{
 51    public static final String PROTOCOL = "jode";
 52
 53    private static final Object mutex = new Object();
 54
 55
 56    public JodeVFS() {
 57        super(PROTOCOL);
 58    }
 59
 60
 61    /**
 62     * Creates an input stream. This method is called from the I/O
 63     * thread.
 64     * @param session the VFS session
 65     * @param path The path
 66     * @param ignoreErrors If true, file not found errors should be
 67     * ignored
 68     * @param comp The component that will parent error dialog boxes
 69     * @exception IOException If an I/O error occurs
 70     */
 71    @Override
 72    public InputStream _createInputStream(Object session,
 73        String path, boolean ignoreErrors, Component comp)
 74        throws IOException
 75    {
 76        String pathToClass = path;
 77        if (path.startsWith(PROTOCOL + ':')) {
 78            pathToClass = pathToClass.substring(PROTOCOL.length() + 1);
 79        }
 80
 81        VFS vfs = VFSManager.getVFSForPath(pathToClass);
 82
 83        if (pathToClass.endsWith(".marks")) {
 84            return null;
 85        }
 86
 87        String className = null;
 88
 89        try {
 90            // Get the class name from BCEL!
 91            DataInputStream in = new DataInputStream(new BufferedInputStream(
 92                vfs._createInputStream(session, pathToClass, ignoreErrors, comp)
 93            ));
 94            JavaClass java_class = new ClassParser(in, pathToClass).parse();
 95            className = java_class.getClassName();
 96            in.close();
 97
 98            // Get the VFS path
 99            String vfsPath = vfs.getParentOfPath(pathToClass);
100            if (vfs != VFSManager.getVFSForPath(vfsPath)) {
101                vfsPath = null;
102            } else {
103                int dotIdx = className.lastIndexOf('.');
104                while (dotIdx != -1) {
105                    vfsPath = vfs.getParentOfPath(vfsPath);
106                    if (vfs != VFSManager.getVFSForPath(vfsPath)) {
107                        vfsPath = null;
108                        break;
109                    }
110                    dotIdx = className.lastIndexOf('.', dotIdx - 1);
111                }
112            }
113
114            ClassPath classPath = createJodeClasspath(vfsPath);
115
116            Log.log(Log.DEBUG, this, 
117                "className=" + className
118                + " vfsPath=" + vfsPath
119                + " pathToClass=" + pathToClass
120                + " classPath=" + classPath);
121
122            in = new DataInputStream(new BufferedInputStream(
123                vfs._createInputStream(session, pathToClass, ignoreErrors, comp)
124            ));
125
126            ClassInfo clazz = classPath.getClassInfo(className);
127            clazz.read(in, ClassInfo.ALL);
128            
129            ByteArrayOutputStream baOut = new ByteArrayOutputStream();
130            OutputStreamWriter output = new OutputStreamWriter(baOut);
131            decompile(className, classPath, output);
132            output.close();
133            
134            return new BufferedInputStream(new ByteArrayInputStream(baOut.toByteArray()));
135        } catch (IOException ioex) {
136            throw ioex;
137        } catch (Throwable t) {
138            // Jode sometimes throws java.lang.InternalError or other
139            // messy things:
140            throw new ChainedIOException("An error occured while decompiling " + className, t);
141        }
142    }
143
144
145    private ClassPath createJodeClasspath(String vfsPath) throws SecurityException, IOException {
146        ArrayList<ClassPath.Location> locations = new ArrayList<ClassPath.Location>();
147        for(String cp : JavaUtils.getClasspath()) {
148            locations.add(ClassPath.createLocation(cp));
149        }
150        if(vfsPath != null) {
151            locations.add(new VFSLocation(vfsPath));
152        }
153        return new ClassPath(locations.toArray(new ClassPath.Location[locations.size()]));
154    }
155
156
157    private void decompile(String className, ClassPath classPath, Writer decompilerOutput) throws IOException {
158        String style = jEdit.getProperty("javainsight.jode.style", "sun");
159        boolean pretty = jEdit.getBooleanProperty("javainsight.jode.pretty", true);
160        boolean onetime = jEdit.getBooleanProperty("javainsight.jode.onetime", false);
161        boolean decrypt = jEdit.getBooleanProperty("javainsight.jode.decrypt", true);
162        
163        int importPkgLimit = 0;
164        try { 
165            importPkgLimit = Integer.parseInt(jEdit.getProperty("javainsight.jode.pkglimit", "0"));
166        } catch(NumberFormatException ex) {}
167        if(importPkgLimit == 0)
168            importPkgLimit = Integer.MAX_VALUE;
169        
170        int importClassLimit = 1;
171        try {
172            importClassLimit = Integer.parseInt(jEdit.getProperty("javainsight.jode.clslimit", "1"));
173        } catch(NumberFormatException ex) {}
174        if(importClassLimit == 0)
175            importClassLimit = Integer.MAX_VALUE;
176        
177        Mode mode = jEdit.getMode("java");
178        String wrapMode = mode.getProperty("wrap").toString(); // "node", "soft", "hard"
179        int maxLineLen = (Integer) mode.getProperty("maxLineLen"); // 0 means no max. line len
180        int tabSize = (Integer) mode.getProperty("tabSize");
181        int indentSize = (Integer) mode.getProperty("indentSize");
182        boolean noTabs = mode.getBooleanProperty("noTabs");
183
184        if(!wrapMode.equals("hard") || maxLineLen == 0)
185            maxLineLen = 1000;
186        
187        if(noTabs)
188            tabSize = 0;
189        
190        int outputStyle = 0; // default for style "pascal"
191        if(style.equals("gnu"))
192            outputStyle = TabbedPrintWriter.GNU_SPACING | TabbedPrintWriter.INDENT_BRACES;
193        else if(style.equals("sun"))
194            outputStyle = TabbedPrintWriter.BRACE_AT_EOL;
195
196        if(pretty)
197            Options.options &= ~Options.OPTION_PRETTY;
198        else
199            Options.options |= Options.OPTION_PRETTY;
200        
201        if(onetime)
202            Options.options &= ~Options.OPTION_ONETIME;
203        else
204            Options.options |= Options.OPTION_ONETIME;
205        
206        if(decrypt)
207            Options.options &= ~Options.OPTION_DECRYPT;
208        else
209            Options.options |= Options.OPTION_DECRYPT;
210        
211        StringWriter errorOutput = new StringWriter();
212        GlobalOptions.err = new PrintWriter(errorOutput);
213
214        // JODE is not thread-safe
215        synchronized (mutex) {
216            ImportHandler importHandler = new ImportHandler(classPath, importPkgLimit, importClassLimit);
217            TabbedPrintWriter tabbedPrintWriter = new TabbedPrintWriter(decompilerOutput,
218                    importHandler, true, outputStyle, indentSize, tabSize, maxLineLen);
219            ClassInfo clazz = classPath.getClassInfo(className);
220            ClassAnalyzer clazzAnalyzer = new ClassAnalyzer(clazz, importHandler);
221            clazzAnalyzer.dumpJavaFile(tabbedPrintWriter);
222            tabbedPrintWriter.close();
223            errorOutput.close();
224        }
225        
226        GlobalOptions.err = null;
227        
228        String errorMessages = errorOutput.toString();
229        if(errorMessages != null && errorMessages.trim().length() > 0) {
230            Log.log(Log.ERROR, this, "Error decompiling class " + className + ":\n" + errorMessages);
231        }
232    }
233
234}