/******************************************************************************* * Copyright © 2010, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.internal.model; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.edt.ide.core.model.EGLModelException; import org.eclipse.edt.ide.core.model.IPackageFragmentRoot; import org.eclipse.edt.ide.core.model.IPart; public class SourceMapper { /** * Specifies the location of the package fragment roots within * the zip (empty specifies the default root). <code>null</code> is * not a valid root path. */ protected ArrayList rootPaths; // /** // * The binary type source is being mapped for // */ // protected BinaryType binaryType; /** * The location of the zip file containing source, or the location of the source folder (not including package folder) */ protected IPath sourcePath; /** * Specifies the location of the package fragment root within * the zip (empty specifies the default root). <code>null</code> is * not a valid root path. */ protected String rootPath = ""; //$NON-NLS-1$ /** * Table that maps a binary method to its parameter names. * Keys are the method handles, entries are <code>char[][]</code>. */ protected HashMap parameterNames; /** * Table that maps a binary element to its <code>SourceRange</code>s. * Keys are the element handles, entries are <code>SourceRange[]</code> which * is a two element array; the first being source range, the second * being name range. */ protected HashMap sourceRanges; /* * A map from IJavaElement to String[] */ protected HashMap categories; /** * The unknown source range {-1, 0} */ public static final SourceRange UNKNOWN_RANGE = new SourceRange(-1, 0); /** * The position within the source of the start of the * current member element, or -1 if we are outside a member. */ protected int[] memberDeclarationStart; /** * The <code>SourceRange</code> of the name of the current member element. */ protected SourceRange[] memberNameRange; /** * The name of the current member element. */ protected String[] memberName; /** * The parameter names for the current member method element. */ protected char[][][] methodParameterNames; /** * The parameter types for the current member method element. */ protected char[][][] methodParameterTypes; // /** // * The element searched for // */ // protected IJavaElement searchedElement; /** * imports references */ private HashMap importsTable; private HashMap importsCounterTable; /** * Enclosing type information */ // IType[] types; int[] typeDeclarationStarts; SourceRange[] typeNameRanges; int[] typeModifiers; int typeDepth; /** * Anonymous counter in case we want to map the source of an anonymous class. */ int anonymousCounter; int anonymousClassName; /** *Options to be used */ String encoding; Map options; /** * Use to handle root paths inference */ private boolean areRootPathsComputed; public static final int FROM_ZIP = 1; public static final int FROM_SOURCE = 2; private int sourceFrom = FROM_ZIP; //default: get source from zip file public SourceMapper() { this.areRootPathsComputed = false; } public SourceMapper(IPath sourcePath, String rootPath, Map options, int sourceFrom){ this(sourcePath, rootPath, options); this.sourceFrom = sourceFrom; } /** * Creates a <code>SourceMapper</code> that locates source in the zip file * at the given location in the specified package fragment root. */ public SourceMapper(IPath sourcePath, String rootPath, Map options) { this.areRootPathsComputed = false; this.options = options; try { this.encoding = ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset(); } catch (CoreException e) { // use no encoding } if (rootPath != null) { this.rootPaths = new ArrayList(); this.rootPaths.add(rootPath); } this.sourcePath = sourcePath; this.sourceRanges = new HashMap(); this.parameterNames = new HashMap(); this.importsTable = new HashMap(); this.importsCounterTable = new HashMap(); } // /** // * Locates and returns source code for the given (binary) type, in this // * SourceMapper's ZIP file, or returns <code>null</code> if source // * code cannot be found. // */ // public char[] findSource(IPart part, IBinaryType info) { // if (!part.isBinary()) { // return null; // } // String simpleSourceFileName = ((BinaryPart) part).getSourceFileName(info); // if (simpleSourceFileName == null) { // return null; // } // return findSource(type, simpleSourceFileName); // } // abstract public char[] findSource(IPart part, String simpleSourceFileName); public int getSourceFrom() { return sourceFrom; } public char[] findSource(String fullName) { char[] source = null; Object target = EGLModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true); //for non-archive source if (target instanceof IContainer) { //source is in workspace folder (non-archive) IResource res = ((IContainer)target).findMember(fullName); if (res instanceof IFile) { try { source = org.eclipse.edt.ide.core.internal.model.Util.getResourceContentsAsCharArray((IFile)res); } catch (EGLModelException e) { e.printStackTrace(); } } } else if (target instanceof IFile && !isZipFile(target)){ //source is in non-external file (non-archive) try { source = org.eclipse.edt.ide.core.internal.model.Util.getResourceContentsAsCharArray((IFile)target); } catch (EGLModelException e) { e.printStackTrace(); } } else if (target instanceof java.io.File && !isZipFile(target)){ //source is in extrernal file (non-archive) InputStream stream = null; try { stream = new BufferedInputStream(new FileInputStream((File)target)); source = org.eclipse.edt.ide.core.internal.model.util.Util.getInputStreamAsCharArray(stream, -1, null); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { //for archive source file // try to get the entry ZipEntry entry = null; ZipFile zip = null; EGLModelManager manager = EGLModelManager.getEGLModelManager(); try { zip = manager.getZipFile(this.sourcePath); entry = zip.getEntry(fullName); if (entry != null) { // now read the source code source = readSource(entry, zip); } } catch (CoreException e) { return null; } catch (Exception e) { return null; } finally { manager.closeZipFile(zip); // handle null case } } if(source == null){ //generate the frame from ir } return source; } /** * Locates and returns source code for the given (binary) type, in this * SourceMapper's ZIP file, or returns <code>null</code> if source * code cannot be found. * The given simpleSourceFileName is the .java file name (without the enclosing * folder) used to create the given type (e.g. "A.java" for x/y/A$Inner.class) */ public char[] findSource(IPart part, String simpleSourceFileName, String[] caseSensitivePackageName) { // long time = 0; // if (VERBOSE) { // time = System.currentTimeMillis(); // } String name; if (caseSensitivePackageName == null) { PackageFragment pkgFrag = (PackageFragment) part.getPackageFragment(); name = org.eclipse.edt.compiler.internal.core.utils.CharOperation.concatWith(pkgFrag.names, simpleSourceFileName, '/'); } else { name = org.eclipse.edt.compiler.internal.core.utils.CharOperation.concatWith(caseSensitivePackageName, simpleSourceFileName, '/'); } char[] source = null; if(this.sourcePath == null){ //no source return source; } EGLModelManager eglModelManager = EGLModelManager.getEGLModelManager(); try { eglModelManager.cacheZipFiles(this); // Cache any zip files we open during this operation if (this.rootPath != null) { source = getSourceForRootPath(this.rootPath, name); } if (source == null) { // computeAllRootPaths(part); if (this.rootPaths != null) { loop: for (Iterator iterator = this.rootPaths.iterator(); iterator.hasNext(); ) { String currentRootPath = (String) iterator.next(); if (!currentRootPath.equals(this.rootPath)) { source = getSourceForRootPath(currentRootPath, name); if (source != null) { // remember right root path this.rootPath = currentRootPath; break loop; } } } } } } finally { eglModelManager.flushZipFiles(this); // clean up cached zip files. } // if (VERBOSE) { // System.out.println("spent " + (System.currentTimeMillis() - time) + "ms for " + type.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ // } return source; } private char[] getSourceForRootPath(String currentRootPath, String name) { String newFullName; if (!currentRootPath.equals(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH)) { if (currentRootPath.endsWith("/")) { //$NON-NLS-1$ newFullName = currentRootPath + name; } else { newFullName = currentRootPath + '/' + name; } } else { newFullName = name; } return this.findSource(newFullName); } private char[] readSource(ZipEntry entry, ZipFile zip) { try { byte[] bytes = Util.getZipEntryByteContent(entry, zip); if (bytes != null) { return org.eclipse.edt.ide.core.internal.model.util.Util.bytesToChar(bytes, this.encoding); } } catch (IOException e) { // ignore } return null; } private boolean isZipFile(Object target){ String fileName = null; if(target instanceof java.io.File){ File file = (File)target; if(file.isFile()){ fileName = file.getName(); } } else if(target instanceof IFile){ IFile file = (IFile)target; fileName = file.getName(); } int index = fileName.lastIndexOf("."); if(index == -1){ return false; } else{ String ext = fileName.substring(index); //TODO if(ext.equalsIgnoreCase(".zip")){ // if(ext.equalsIgnoreCase(".zip") || ext.equalsIgnoreCase(".eglar")){ return true; } } return false; } public IPath getSourcePath() { return sourcePath; } }