blob: 6d26b35da1d2ae691b8b38edc1a0cf3646dcdd36 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 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
* Mickael Istria (Red Hat Inc.) - [263316] regexp for file association
*******************************************************************************/
package org.eclipse.core.internal.content;
import java.io.*;
import java.util.*;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.content.*;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.osgi.service.prefs.BackingStoreException;
/**
* @since 3.1
*/
public class ContentTypeMatcher implements IContentTypeMatcher {
private IScopeContext context;
private IContentTypeManager.ISelectionPolicy policy;
public ContentTypeMatcher(IContentTypeManager.ISelectionPolicy policy, IScopeContext context) {
this.policy = policy;
this.context = context;
}
@Override
public IContentType findContentTypeFor(InputStream contents, String fileName) throws IOException {
ContentTypeCatalog currentCatalog = getCatalog();
IContentType[] all = currentCatalog.findContentTypesFor(this, contents, fileName);
return all.length > 0 ? new ContentTypeHandler((ContentType) all[0], currentCatalog.getGeneration()) : null;
}
@Override
public IContentType findContentTypeFor(String fileName) {
// basic implementation just gets all content types
ContentTypeCatalog currentCatalog = getCatalog();
IContentType[] associated = currentCatalog.findContentTypesFor(this, fileName);
return associated.length == 0 ? null : new ContentTypeHandler((ContentType) associated[0], currentCatalog.getGeneration());
}
@Override
public IContentType[] findContentTypesFor(InputStream contents, String fileName) throws IOException {
ContentTypeCatalog currentCatalog = getCatalog();
IContentType[] types = currentCatalog.findContentTypesFor(this, contents, fileName);
IContentType[] result = new IContentType[types.length];
int generation = currentCatalog.getGeneration();
for (int i = 0; i < result.length; i++)
result[i] = new ContentTypeHandler((ContentType) types[i], generation);
return result;
}
@Override
public IContentType[] findContentTypesFor(String fileName) {
ContentTypeCatalog currentCatalog = getCatalog();
IContentType[] types = currentCatalog.findContentTypesFor(this, fileName);
IContentType[] result = new IContentType[types.length];
int generation = currentCatalog.getGeneration();
for (int i = 0; i < result.length; i++)
result[i] = new ContentTypeHandler((ContentType) types[i], generation);
return result;
}
private ContentTypeCatalog getCatalog() {
return ContentTypeManager.getInstance().getCatalog();
}
@Override
public IContentDescription getDescriptionFor(InputStream contents, String fileName, QualifiedName[] options) throws IOException {
return getCatalog().getDescriptionFor(this, contents, fileName, options);
}
@Override
public IContentDescription getDescriptionFor(Reader contents, String fileName, QualifiedName[] options) throws IOException {
return getCatalog().getDescriptionFor(this, contents, fileName, options);
}
public IScopeContext getContext() {
return context;
}
public IContentTypeManager.ISelectionPolicy getPolicy() {
return policy;
}
/**
* Enumerates all content types whose settings satisfy the given file spec type mask.
*/
public Collection<ContentType> getDirectlyAssociated(final ContentTypeCatalog catalog, final String fileSpec, final int typeMask) {
if ((typeMask & (IContentType.FILE_EXTENSION_SPEC | IContentType.FILE_NAME_SPEC)) == 0) {
throw new IllegalArgumentException("This method only apply to name or extension based associations"); //$NON-NLS-1$
}
//TODO: make sure we include built-in associations as well
final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE);
final Set<ContentType> result = new HashSet<>(3);
try {
root.accept(node -> {
if (node == root)
return true;
String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask);
for (String fileSpecification : fileSpecs)
if (fileSpecification.equalsIgnoreCase(fileSpec)) {
ContentType associated = catalog.getContentType(node.name());
if (associated != null)
result.add(associated);
break;
}
return false;
});
} catch (BackingStoreException bse) {
ContentType.log(ContentMessages.content_errorLoadingSettings, bse);
}
return result == null ? Collections.EMPTY_SET : result;
}
public Collection<? extends ContentType> getMatchingRegexpAssociated(ContentTypeCatalog catalog,
String fileName, final int typeMask) {
if ((typeMask & IContentType.FILE_PATTERN_SPEC) == 0) {
throw new IllegalArgumentException("This method only applies for FILE_REGEXP_SPEC."); //$NON-NLS-1$
}
final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE);
final Set<ContentType> result = new HashSet<>(3);
try {
root.accept(node -> {
if (node == root)
return true;
String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask);
for (String fileSpecification : fileSpecs)
if (Pattern.matches(catalog.toRegexp(fileSpecification), fileName)) {
ContentType associated = catalog.getContentType(node.name());
if (associated != null)
result.add(associated);
break;
}
return false;
});
} catch (BackingStoreException bse) {
ContentType.log(ContentMessages.content_errorLoadingSettings, bse);
}
return result == null ? Collections.EMPTY_SET : result;
}
public IContentDescription getSpecificDescription(BasicDescription description) {
if (description == null || ContentTypeManager.getInstance().getContext().equals(getContext()))
// no need for specific content descriptions
return description;
// default description
if (description instanceof DefaultDescription)
// return an context specific description instead
return new DefaultDescription(new ContentTypeSettings((ContentType) description.getContentTypeInfo(), context));
// non-default description
// replace info object with context specific settings
((ContentDescription) description).setContentTypeInfo(new ContentTypeSettings((ContentType) description.getContentTypeInfo(), context));
return description;
}
}