001: package tide.sources;
002:
003: import tide.utils.BytecodeUtils;
004: import tide.classsyntax.ClassUtils;
005: import tide.editor.MainEditorFrame;
006: import tide.exttools.jad_decompiler.*;
007: import snow.utils.StringUtils;
008: import snow.utils.storage.*;
009: import tide.syntaxtree.*;
010: import javax.swing.tree.*;
011: import javax.swing.undo.*;
012: import java.io.*;
013: import java.util.*;
014: import java.util.zip.*;
015:
016: /** Directories, files from all elements in class path. libraries and dirs.
017: * (TODO: dirs support if wanted).
018: * maybe source or classes, from dirs or jars.
019: *
020: * display may be decompiled (jad) or bytecode (javap)
021: */
022: public class LibFileItem extends DefaultMutableTreeNode implements
023: FileItem {
024: final String name;
025: private final String fullJavaName;
026: final private String packageName;
027:
028: // either file of directory
029: boolean isFile = false;
030: //private File file = null;
031: private ZipEntry ze;
032: private ZipFile archive;
033:
034: // todo: remove to liberate resources...
035: public String decompiledContentOrSource = null;
036: public boolean enforceDecompileInsteadOfViewingSource = false;
037:
038: /** Used for directories and roots (where only name is set)
039: */
040: public LibFileItem(final String name, final String fullJavaName,
041: final String packageName) {
042: this (name, fullJavaName, packageName, null);
043: }
044:
045: /** Used for directories and roots (where only name is set)
046: */
047: public LibFileItem(final String name, final String fullJavaName,
048: final String packageName, final ZipFile archive) {
049: super (name);
050:
051: this .name = name;
052: this .fullJavaName = fullJavaName;
053: this .packageName = packageName;
054: this .archive = archive;
055: }
056:
057: public LibFileItem(final ZipEntry zfile, final String onlyName,
058: final ZipFile archive) {
059: super (onlyName);
060: this .name = onlyName; // getName is com/sun/...
061:
062: this .isFile = !zfile.isDirectory();
063: this .ze = zfile;
064: this .archive = archive;
065:
066: String jn = ze.getName();
067: if (jn.endsWith(".java")) {
068: jn = jn.substring(0, jn.length() - 5);
069: this .fullJavaName = jn.replace('/', '.');
070: } else if (jn.endsWith(".class")) {
071: jn = jn.substring(0, jn.length() - 6);
072: this .fullJavaName = jn.replace('/', '.');
073: } else {
074: this .fullJavaName = "";
075: }
076:
077: // TODO. verify ! (for internal classes Point2D.Double ???)
078: this .packageName = StringUtils.removeAfterLastIncluded(
079: fullJavaName, ".");
080:
081: } // Constructor
082:
083: /** close files (Overridden below)
084: */
085: public void liberateResourcesForGC() {
086: decompiledContentOrSource = null;
087: }
088:
089: /** This is the node name only.
090: */
091: public String getName() {
092: return name;
093: }
094:
095: private int caretLinePosition = 0, caretColPosition = 0;
096:
097: public int getCaretLinePosition() {
098: return caretLinePosition;
099: }
100:
101: public int getCaretColumnPosition() {
102: return caretColPosition;
103: }
104:
105: public void setCaretPositionToRemember(int line, int col) {
106: caretLinePosition = line;
107: caretColPosition = col;
108: }
109:
110: /** for directories and files
111: */
112: public String getJavaName() {
113: return fullJavaName;
114: }
115:
116: public String getPackageName() {
117: return packageName;
118: }
119:
120: public boolean getHasBeenRemoved() {
121: return false;
122: }
123:
124: /** The node name or file name without ".java"
125: */
126: public String getJavaPartName() {
127: String nname = getName();
128: if (!this .isFile)
129: return nname;
130:
131: if (nname.endsWith(".java")) {
132: nname = nname.substring(0, nname.length() - 5);
133: } else if (nname.endsWith(".class")) {
134: nname = nname.substring(0, nname.length() - 6);
135: }
136: return nname;
137: }
138:
139: public boolean isEditable() {
140: return false;
141: }
142:
143: /** Either source or class file.
144: */
145: public boolean isJavaFile() {
146: if (!isFile)
147: return false;
148: if (this .getName().endsWith(".java"))
149: return true;
150: if (this .getName().endsWith(".class"))
151: return true;
152: return false;
153: }
154:
155: public boolean isDirectory() {
156: return !isFile;
157: }
158:
159: public boolean isSourceFile() {
160: if (!isFile)
161: return false;
162: if (this .getName().endsWith(".java"))
163: return true;
164: return false;
165: }
166:
167: public boolean hasTextRepresentation() {
168: return isJavaFile() || isClassFile();
169: }
170:
171: // overidden by roots
172: public boolean isIgnored() {
173: return false;
174: }
175:
176: public boolean isClassFile() {
177: if (!isFile)
178: return false;
179: if (this .getName().endsWith(".class"))
180: return true;
181: return false;
182: }
183:
184: /** data may be lost if not saved previously !
185: * used to enforce reload from file !
186: */
187: public void deleteCachedContent() {
188: this .decompiledContentOrSource = null;
189: }
190:
191: public long getLastModified() {
192: /*if(this.file!=null)
193: return file.lastModified();*/
194:
195: if (this .ze != null)
196: return ze.getTime();
197:
198: return -1;
199: }
200:
201: public long getFileSize() {
202: /*if(this.file!=null)
203: return file.length();*/
204:
205: if (this .ze != null)
206: return ze.getSize();
207:
208: return -1;
209: }
210:
211: /** if has been previously decompiled, the decompiled content is returned.
212: (Set it to null to enforce normal display.)
213: If jad is set to default decompile classes, and correctly installed (path ok), classes content will be decompiled.
214:
215: TODO: better ! choice between (jad, associated source, javap, bytecode, ??)
216: */
217: public String getContent() throws Exception {
218: if (decompiledContentOrSource != null)
219: return decompiledContentOrSource;
220:
221: // [Oct2007]: added as first alternative
222: //
223: if (this .isClassFile()
224: && !enforceDecompileInsteadOfViewingSource) {
225: try {
226: String cont = MainEditorFrame.instance
227: .getActualProject().librariesTreeModel
228: .getSourceFor(getJavaName());
229: if (cont != null) {
230: decompiledContentOrSource = cont;
231: return cont;
232: } else
233: MainEditorFrame
234: .debugOut("No associated source for "
235: + getJavaName());
236:
237: } catch (Exception ex) {
238: ex.printStackTrace();
239: }
240: }
241:
242: if (MainEditorFrame.instance
243: .getActualProject()
244: .getBooleanProperty("JAD_applyJadToClassFilesCB", false)
245: && JADDecompilerSettingsDialog.isConfigured()
246: && this .isClassFile()) {
247: try {
248: JADLauncher.decompile(this );
249: if (decompiledContentOrSource != null)
250: return decompiledContentOrSource;
251: } catch (Exception e) {
252: e.printStackTrace(); // lazy: just display and let the normal case below...
253: }
254: }
255: /*
256: if(file!=null && file.isFile())
257: {
258: try
259: {
260: if(this.isJavaFile())
261: {
262: return FileUtils.getFileStringContent(file);
263: }
264: else if(this.isClassFile())
265: {
266: //System.out.println("getting class content for "+getJavaName());
267: // looks if source available (coming from src.zip !)
268: if(!enforceDecompileInsteadOfViewingSource)
269: {
270: try
271: {
272: String cont = MainEditorFrame.instance.getActualProject().librariesTreeModel.getSourceFor(getJavaName());
273: if(cont!=null)
274: {
275: decompiledContentOrSource = cont;
276: return cont;
277: }
278: else System.out.println("No source for "+ getJavaName());
279:
280: } catch(Exception ex) {ex.printStackTrace(); }
281: }
282:
283: return ClassUtils.getClassSourceOutlineFromByteCode(file.getName(), new FileInputStream(file), MainEditorFrame.instance.getActualProject().getJavap_TOOL());
284: }
285: else
286: {
287: // other type... (currently not accepted by the editor...) TODO ?
288: return FileUtils.getFileStringContent(file);
289: }
290: }
291: catch(Exception e)
292: {
293: throw e;
294: }
295: }*/
296:
297: if (archive != null && ze != null && !ze.isDirectory()) {
298: InputStream is = null;
299: try {
300: if (ze.getName().endsWith(".class")) {
301: is = archive.getInputStream(ze);
302: String nname = ze.getName();
303: int pos = nname.lastIndexOf('/');
304: if (pos >= 0) {
305: nname = nname
306: .substring(pos + 1, nname.length());
307: }
308: /*
309: if(!enforceDecompileInsteadOfViewingSource)
310: {
311:
312: try
313: {
314: String cont = MainEditorFrame.instance.getActualProject().librariesTreeModel.getSourceFor(getJavaName());
315: if(cont!=null)
316: {
317: decompiledContentOrSource = cont;
318: return cont;
319: }
320: else MainEditorFrame.debugOut("No associated source for "+ getJavaName());
321:
322: } catch(Exception ex) {ex.printStackTrace(); }
323: }*/
324:
325: decompiledContentOrSource = BytecodeUtils
326: .getClassSourceOutlineFromByteCode(nname,
327: is, MainEditorFrame.instance
328: .getActualProject()
329: .getJavap_TOOL());
330: return decompiledContentOrSource;
331: } else {
332: StringBuilder sb = new StringBuilder();
333: is = archive.getInputStream(ze);
334: InputStreamReader r = new InputStreamReader(is);
335: char[] buf = new char[256];
336: int read = -1;
337: while ((read = r.read(buf)) != -1) {
338: sb.append(new String(buf, 0, read));
339: }
340: return sb.toString();
341: }
342: } catch (Exception e) {
343: throw e;
344: } finally {
345: if (is != null)
346: try {
347: is.close();
348: } catch (Exception ignored) {
349: }
350: }
351: }
352: return "";
353: }
354:
355: /** @return the content inputStream, maybe from a jar entry or file.
356: null for directories.
357: Used by the jad launcher.
358: */
359: public InputStream getRAWContentInputStream() throws Exception {
360: /*if(file!=null && file.isFile())
361: {
362: return new FileInputStream( file );
363: }*/
364: if (archive != null && ze != null && !ze.isDirectory()) {
365: return archive.getInputStream(ze);
366: } else {
367: return null;
368: }
369: }
370:
371: /** zip archive name (in the class path)
372: */
373: public String getRootArchiveName() {
374: if (archive != null) {
375: return archive.getName();
376: }
377:
378: return "???";
379: }
380:
381: public LibFileItem getChildItemAt(int i) {
382: return (LibFileItem) this .getChildAt(i);
383: }
384:
385: public boolean hasPackageDirectJavaChilds() {
386: if (this .isJavaFile())
387: return false;
388: for (int i = 0; i < this .getChildCount(); i++) {
389: if (this .getChildItemAt(i).isJavaFile())
390: return true;
391: }
392: return false;
393: }
394:
395: /** often called 0.3% CPU! */
396: public LibFileItem getChildNamed(final String _name) {
397: for (int i = 0; i < this .getChildCount(); i++) {
398: if (this .getChildItemAt(i).getName().equals(_name))
399: return this .getChildItemAt(i);
400: }
401: // not found
402: return null;
403: }
404:
405: private SimplifiedSyntaxTree2 simplifiedSyntaxTree = null;
406:
407: public void setSimplifiedSyntaxTree(final SimplifiedSyntaxTree2 st) {
408: if (simplifiedSyntaxTree != null) {
409: simplifiedSyntaxTree.terminateSST();
410: }
411: simplifiedSyntaxTree = st;
412: SyntaxTreeCache.getInstance().addToCache(this );
413: }
414:
415: public SimplifiedSyntaxTree2 getSimplifiedSyntaxTreeIfAlreadyMade() {
416: return simplifiedSyntaxTree;
417: }
418:
419: private ParserResult cu = null;
420:
421: public ParserResult getParserResultIfAlreadyMade() {
422: return cu;
423: }
424:
425: public void setParserResult(final ParserResult st) {
426: cu = st;
427: }
428:
429: /** Important: Must call close at the end !
430: * [April2007]: may be ignored (property set from the tree, stored in the project.
431: * based on the name). If ignored, is not passed to the tools as Proguard => boost
432: */
433: static public class LibFileRoot extends LibFileItem {
434: public final ZipFile file;
435: private boolean ignored = false;
436:
437: public LibFileRoot(ZipFile file, String simpleName) {
438: super (MainEditorFrame.compactUI ? simpleName : file
439: .getName(), "", "");
440:
441: this .file = file;
442: this .isFile = false;
443:
444: this .ignored = MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
445: .contains(file.getName());
446: }
447:
448: @Override
449: public boolean isIgnored() {
450: return ignored;
451: }
452:
453: public boolean getHasBeenRemoved() {
454: return false;
455: }
456:
457: public void setIgnored(boolean is) {
458: ignored = is;
459: if (is) {
460: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
461: .add(file.getName());
462: } else {
463: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
464: .remove(file.getName());
465: }
466: }
467:
468: public void close() {
469: FileUtils.closeIgnoringExceptions(file);
470: }
471:
472: @Override
473: // CALLED during project clear... ok... closes
474: public void liberateResourcesForGC() {
475: close();
476: }
477: }
478:
479: /** DUMMY Zip, for low mem mode
480: */
481: static public class LibFileRootLOWMEM extends LibFileItem {
482: private boolean ignored = false;
483:
484: public LibFileRootLOWMEM(String name) {
485: super (name, "", "");
486:
487: this .ignored = MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
488: .contains(name);
489: }
490:
491: @Override
492: public boolean isIgnored() {
493: return ignored;
494: }
495:
496: public void setIgnored(boolean is) {
497: ignored = is;
498: if (is) {
499: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
500: .add(name);
501: } else {
502: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
503: .remove(name);
504: }
505: }
506:
507: public void close() {
508:
509: }
510:
511: @Override
512: public void liberateResourcesForGC() {
513:
514: }
515: }
516:
517: static class LibDirRoot extends LibFileItem {
518: public final File file;
519: private boolean ignored = false;
520:
521: public LibDirRoot(File file) {
522: super (file.getName(), "", "");
523: this .file = file;
524: this .isFile = !(file.isDirectory());
525:
526: this .ignored = MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
527: .contains(file.getName());
528: }
529:
530: @Override
531: public boolean isIgnored() {
532: return ignored;
533: }
534:
535: public void setIgnored(boolean is) {
536: ignored = is;
537: if (is) {
538: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
539: .add(file.getName());
540: } else {
541: MainEditorFrame.instance.getActualProject().ignoredLibrariesNames
542: .remove(file.getName());
543: }
544: }
545: }
546:
547: }
|