/*******************************************************************************
* Copyright (c) 2004, 2015 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.internal.core.sourcelookup;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.internal.core.model.ExternalTranslationUnit;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.sourcelookup.ISourceContainerType;
import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
import org.eclipse.debug.core.sourcelookup.containers.AbstractSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
import com.ibm.icu.text.MessageFormat;
/**
* The source container that maps a backend path to the local filesystem path.
*/
public class MapEntrySourceContainer extends AbstractSourceContainer {
/**
* Unique identifier for the map entry source container type
* (value <code>org.eclipse.cdt.debug.core.containerType.mapEntry</code>).
*/
public static final String TYPE_ID = CDebugCorePlugin.getUniqueIdentifier() + ".containerType.mapEntry"; //$NON-NLS-1$
private IPath fLocalPath;
private String fBackendPathStr;
/**
* Constructor for MapEntrySourceContainer.
*/
public MapEntrySourceContainer() {
fBackendPathStr = ""; //$NON-NLS-1$
fLocalPath = Path.EMPTY;
}
/**
* Constructor for MapEntrySourceContainer.
*/
public MapEntrySourceContainer(String backendPathStr, IPath local) {
fBackendPathStr = backendPathStr;
fLocalPath = local;
}
/**
* Creates an IPath from a string which may be a Win32 path.
* <p>
* <p>
* ("new Path(...)" won't work in Unix when using a Win32 path: the
* backslash separator and the device notation are completely munged.)
* Copied from org.eclipse.cdt.debug.edc.internal.PathUtils
*
* @param path
* @return converted string
*
* @deprecated createPath existed as a solution to try and store non-current
* platform paths in an IPath, however that was limited.
* createPath only exists for legacy case (see
* findSourceElements below). See <a href=
* "https://bugs.eclipse.org/bugs/show_bug.cgi?id=472765">Bug
* 472765</a> for more details.
* <p>
* Instead of using createPath, keep paths as Strings and use
* other methods to compare paths.
*/
@Deprecated
public static IPath createPath(String path) {
if (path == null)
return null;
// Check for windows full-path formatting.
if (path.matches("^([a-zA-Z])[:](.*)$")) { //$NON-NLS-1$
String device = null;
String missingfile = path.replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
int idx = missingfile.indexOf(":"); //$NON-NLS-1$
if ( idx > 0 ) {
device = missingfile.substring(0, idx + 1);
missingfile = missingfile.substring(idx + 1);
}
return new Path(device, missingfile);
}
int idx = 0;
// Cygwin or UNC path
if (path.startsWith("//")) { //$NON-NLS-1$
String network;
idx = path.indexOf("/", 2); //$NON-NLS-1$
if (idx > 0) {
network = path.substring(0, idx);
path = path.substring(idx);
} else {
network = path;
path = ""; //$NON-NLS-1$
}
return new Path(network, path).makeUNC(true);
}
// fallthrough
return new Path(path);
}
@Override
public Object[] findSourceElements(String name) throws CoreException {
IPath path = null;
if (name != null) {
// First try the non-canonical comparison
final String backend = getBackendPathStr();
if (name.toLowerCase().startsWith(backend.toLowerCase())) {
String suffix = name.substring(backend.length());
// checkStartsWith only verifies that the paths are the same up
// to getBackend(), however if name=/hello2/a.c and backend=/hello
// then checkStartsWith will be true, so we have to further check
// that we are on a separator
if (backend.endsWith("/") || backend.endsWith("\\") || //$NON-NLS-1$ //$NON-NLS-2$
suffix.startsWith("/") || suffix.startsWith("\\")) { //$NON-NLS-1$ //$NON-NLS-2$
path = getLocalPath().append(suffix);
}
}
// Then if we have not matched, try the legacy way of canonicalizing
// the paths and comparing them
if (path == null) {
IPath input = createPath(name);
IPath backendPath = createPath(backend);
if (backendPath.isPrefixOf(input)) {
IPath suffix = input.removeFirstSegments(backendPath.segmentCount());
path = getLocalPath().append(suffix);
}
}
}
if (path != null) {
IFile[] wsFiles = ResourceLookup.findFilesForLocation(path);
ArrayList<IFile> list = new ArrayList<IFile>();
for (int j = 0; j < wsFiles.length; ++j) {
if (wsFiles[j].exists()) {
list.add(wsFiles[j]);
if (!isFindDuplicates())
break;
}
}
if (list.size() > 0)
return list.toArray();
File file = path.toFile();
// The file is not already in the workspace so try to create an external translation unit for it.
ISourceLookupDirector director = getDirector();
if (director != null && file.exists() && file.isFile()) {
ILaunchConfiguration launchConfiguration = director.getLaunchConfiguration();
if (launchConfiguration != null) {
String projectName = launchConfiguration.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
if (projectName.length() > 0) {
ICProject project = CoreModel.getDefault().getCModel().getCProject(projectName);
if (project != null) {
String id;
try {
final IPath location= Path.fromOSString(file.getCanonicalPath());
id = CoreModel.getRegistedContentTypeId(project.getProject(), location.lastSegment());
return new ExternalTranslationUnit[] { new ExternalTranslationUnit(project, location, id) };
} catch (IOException e) {
CDebugCorePlugin.log(e);
}
}
}
}
}
if (file.exists() && file.isFile()) {
return new Object[] { new LocalFileStorage(file) };
}
}
return EMPTY;
}
@Override
public String getName() {
return MessageFormat.format("{0} - {1}", new Object[] { getBackendPathStr(), getLocalPath().toOSString() }); //$NON-NLS-1$
}
@Override
public ISourceContainerType getType() {
return getSourceContainerType(TYPE_ID);
}
public IPath getLocalPath() {
return fLocalPath;
}
public String getBackendPathStr() {
return fBackendPathStr;
}
public void setLocalPath(IPath local) {
fLocalPath = local;
}
public void setBackendPathStr(String backendPathStr) {
fBackendPathStr = backendPathStr;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof MapEntrySourceContainer))
return false;
MapEntrySourceContainer entry = (MapEntrySourceContainer)o;
return (entry.getBackendPathStr().equals(getBackendPathStr()) && entry.getLocalPath().equals(getLocalPath()));
}
public MapEntrySourceContainer copy() {
return new MapEntrySourceContainer(fBackendPathStr, fLocalPath);
}
}