/*******************************************************************************
* Copyright (c) 2007, 2012 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.internal.debug.launch;
import java.io.File;
import java.net.InetAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
import org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule;
import org.eclipse.tcf.internal.debug.model.TCFSourceRef;
import org.eclipse.tcf.services.ILineNumbers;
import org.eclipse.tcf.services.IPathMap;
/**
* The TCF source lookup participant knows how to translate
* a ILineNumbers.CodeArea into a source file name.
*/
public class TCFSourceLookupParticipant extends AbstractSourceLookupParticipant {
@SuppressWarnings("serial")
private final LinkedHashMap<String,Object[]> cache = new LinkedHashMap<String,Object[]>(511, 0.75f, true) {
@Override
@SuppressWarnings("rawtypes")
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 1023;
}
};
@Override
public void sourceContainersChanged(ISourceLookupDirector director) {
cache.clear();
}
public String getSourceName(Object object) throws CoreException {
if (object instanceof String) {
return (String)object;
}
if (object instanceof ILineNumbers.CodeArea) {
ILineNumbers.CodeArea area = (ILineNumbers.CodeArea)object;
return toFileName(area);
}
if (object instanceof TCFSourceRef) {
TCFSourceRef ref = (TCFSourceRef)object;
if (ref.area == null) return null;
return toFileName(ref.area);
}
return null;
}
public static String toFileName(ILineNumbers.CodeArea area) {
if (area.directory != null && area.file != null && !isAbsolutePath(area.file)) {
return area.directory + "/" + area.file;
}
return area.file;
}
public static String toFileName(IPathMap.PathMapRule r, String fnm) {
try {
String src = r.getSource();
if (src == null) return null;
if (!fnm.startsWith(src)) return null;
String host = r.getHost();
if (host != null && host.length() > 0) {
if (!InetAddress.getLocalHost().equals(InetAddress.getByName(host))) return null;
}
String dst = r.getDestination();
if (dst == null || dst.length() == 0) return null;
int l = src.length();
if (dst.endsWith("/") && l < fnm.length() && fnm.charAt(l) == '/') l++;
return dst + fnm.substring(l);
}
catch (Exception x) {
return null;
}
}
private static boolean isAbsolutePath(String fnm) {
if (fnm.length() == 0) return false;
char ch = fnm.charAt(0);
if (ch == '/' || ch == '\\') return true;
if (fnm.length() >= 3 && fnm.charAt(1) == ':') {
ch = fnm.charAt(2);
if (ch == '/' || ch == '\\') return true;
}
return false;
}
private String applyPathMap(String fnm) {
ILaunchConfiguration cfg = getDirector().getLaunchConfiguration();
if (cfg == null) return fnm;
try {
String path_map = cfg.getAttribute(TCFLaunchDelegate.ATTR_PATH_MAP, "");
if (path_map.length() == 0) return fnm;
ArrayList<PathMapRule> map = TCFLaunchDelegate.parsePathMapAttribute(path_map);
for (PathMapRule r : map) {
String query = r.getContextQuery();
if (query != null && query.length() > 0 && !query.equals("*")) continue;
String res = toFileName(r, fnm);
if (res != null) return res;
}
if (fnm.startsWith("/cygdrive/")) {
fnm = fnm.substring(10, 11) + ":" + fnm.substring(11);
}
return fnm;
}
catch (Exception x) {
return fnm;
}
}
private Object[] findSource(String name) throws CoreException {
Object[] res;
File file = new File(applyPathMap(name));
if (file.isAbsolute() && file.exists() && file.isFile()) {
res = new Object[]{ new LocalFileStorage(file) };
}
else {
res = super.findSourceElements(name);
}
ArrayList<Object> list = new ArrayList<Object>();
for (Object o : res) {
if (o instanceof IStorage && !(o instanceof IFile)) {
IPath path = ((IStorage)o).getFullPath();
if (path != null) {
URI uri = URIUtil.toURI(path);
IFile[] arr = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri);
if (arr != null && arr.length > 0) {
int cnt = list.size();
for (IFile resource : arr) {
if (resource.isAccessible()) {
list.add(resource);
}
}
if (list.size() > cnt) continue;
}
}
}
list.add(o);
}
return list.toArray(new Object[list.size()]);
}
@Override
public Object[] findSourceElements(Object object) throws CoreException {
String name = getSourceName(object);
if (name == null) return null;
Object[] res = cache.get(name);
if (res != null) return res;
res = findSource(name);
cache.put(name, res);
return res;
}
}