1 /******************************************************************************* 2 * Copyright (c) 2005, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Mickael Istria (Red Hat Inc.) - [263316] regexp for file association 14 *******************************************************************************/ 15 package org.eclipse.core.internal.content; 16 17 import java.io.*; 18 import java.util.*; 19 import java.util.regex.Pattern; 20 import org.eclipse.core.runtime.QualifiedName; 21 import org.eclipse.core.runtime.content.*; 22 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 23 import org.eclipse.core.runtime.preferences.IScopeContext; 24 import org.osgi.service.prefs.BackingStoreException; 25 26 /** 27 * @since 3.1 28 */ 29 public class ContentTypeMatcher implements IContentTypeMatcher { 30 31 private IScopeContext context; 32 private IContentTypeManager.ISelectionPolicy policy; 33 ContentTypeMatcher(IContentTypeManager.ISelectionPolicy policy, IScopeContext context)34 public ContentTypeMatcher(IContentTypeManager.ISelectionPolicy policy, IScopeContext context) { 35 this.policy = policy; 36 this.context = context; 37 } 38 39 @Override findContentTypeFor(InputStream contents, String fileName)40 public IContentType findContentTypeFor(InputStream contents, String fileName) throws IOException { 41 ContentTypeCatalog currentCatalog = getCatalog(); 42 IContentType[] all = currentCatalog.findContentTypesFor(this, contents, fileName); 43 return all.length > 0 ? new ContentTypeHandler((ContentType) all[0], currentCatalog.getGeneration()) : null; 44 } 45 46 @Override findContentTypeFor(String fileName)47 public IContentType findContentTypeFor(String fileName) { 48 // basic implementation just gets all content types 49 ContentTypeCatalog currentCatalog = getCatalog(); 50 IContentType[] associated = currentCatalog.findContentTypesFor(this, fileName); 51 return associated.length == 0 ? null : new ContentTypeHandler((ContentType) associated[0], currentCatalog.getGeneration()); 52 } 53 54 @Override findContentTypesFor(InputStream contents, String fileName)55 public IContentType[] findContentTypesFor(InputStream contents, String fileName) throws IOException { 56 ContentTypeCatalog currentCatalog = getCatalog(); 57 IContentType[] types = currentCatalog.findContentTypesFor(this, contents, fileName); 58 IContentType[] result = new IContentType[types.length]; 59 int generation = currentCatalog.getGeneration(); 60 for (int i = 0; i < result.length; i++) 61 result[i] = new ContentTypeHandler((ContentType) types[i], generation); 62 return result; 63 } 64 65 @Override findContentTypesFor(String fileName)66 public IContentType[] findContentTypesFor(String fileName) { 67 ContentTypeCatalog currentCatalog = getCatalog(); 68 IContentType[] types = currentCatalog.findContentTypesFor(this, fileName); 69 IContentType[] result = new IContentType[types.length]; 70 int generation = currentCatalog.getGeneration(); 71 for (int i = 0; i < result.length; i++) 72 result[i] = new ContentTypeHandler((ContentType) types[i], generation); 73 return result; 74 } 75 getCatalog()76 private ContentTypeCatalog getCatalog() { 77 return ContentTypeManager.getInstance().getCatalog(); 78 } 79 80 @Override getDescriptionFor(InputStream contents, String fileName, QualifiedName[] options)81 public IContentDescription getDescriptionFor(InputStream contents, String fileName, QualifiedName[] options) throws IOException { 82 return getCatalog().getDescriptionFor(this, contents, fileName, options); 83 } 84 85 @Override getDescriptionFor(Reader contents, String fileName, QualifiedName[] options)86 public IContentDescription getDescriptionFor(Reader contents, String fileName, QualifiedName[] options) throws IOException { 87 return getCatalog().getDescriptionFor(this, contents, fileName, options); 88 } 89 getContext()90 public IScopeContext getContext() { 91 return context; 92 } 93 getPolicy()94 public IContentTypeManager.ISelectionPolicy getPolicy() { 95 return policy; 96 } 97 98 /** 99 * Enumerates all content types whose settings satisfy the given file spec type mask. 100 */ getDirectlyAssociated(final ContentTypeCatalog catalog, final String fileSpec, final int typeMask)101 public Collection<ContentType> getDirectlyAssociated(final ContentTypeCatalog catalog, final String fileSpec, final int typeMask) { 102 if ((typeMask & (IContentType.FILE_EXTENSION_SPEC | IContentType.FILE_NAME_SPEC)) == 0) { 103 throw new IllegalArgumentException("This method only apply to name or extension based associations"); //$NON-NLS-1$ 104 } 105 //TODO: make sure we include built-in associations as well 106 final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE); 107 final Set<ContentType> result = new HashSet<>(3); 108 try { 109 root.accept(node -> { 110 if (node == root) 111 return true; 112 String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask); 113 for (String fileSpecification : fileSpecs) 114 if (fileSpecification.equalsIgnoreCase(fileSpec)) { 115 ContentType associated = catalog.getContentType(node.name()); 116 if (associated != null) 117 result.add(associated); 118 break; 119 } 120 return false; 121 }); 122 } catch (BackingStoreException bse) { 123 ContentType.log(ContentMessages.content_errorLoadingSettings, bse); 124 } 125 return result == null ? Collections.EMPTY_SET : result; 126 } 127 getMatchingRegexpAssociated(ContentTypeCatalog catalog, String fileName, final int typeMask)128 public Collection<? extends ContentType> getMatchingRegexpAssociated(ContentTypeCatalog catalog, 129 String fileName, final int typeMask) { 130 if ((typeMask & IContentType.FILE_PATTERN_SPEC) == 0) { 131 throw new IllegalArgumentException("This method only applies for FILE_REGEXP_SPEC."); //$NON-NLS-1$ 132 } 133 final IEclipsePreferences root = context.getNode(ContentTypeManager.CONTENT_TYPE_PREF_NODE); 134 final Set<ContentType> result = new HashSet<>(3); 135 try { 136 root.accept(node -> { 137 if (node == root) 138 return true; 139 String[] fileSpecs = ContentTypeSettings.getFileSpecs(node, typeMask); 140 for (String fileSpecification : fileSpecs) 141 if (Pattern.matches(catalog.toRegexp(fileSpecification), fileName)) { 142 ContentType associated = catalog.getContentType(node.name()); 143 if (associated != null) 144 result.add(associated); 145 break; 146 } 147 return false; 148 }); 149 } catch (BackingStoreException bse) { 150 ContentType.log(ContentMessages.content_errorLoadingSettings, bse); 151 } 152 return result == null ? Collections.EMPTY_SET : result; 153 } 154 getSpecificDescription(BasicDescription description)155 public IContentDescription getSpecificDescription(BasicDescription description) { 156 if (description == null || ContentTypeManager.getInstance().getContext().equals(getContext())) 157 // no need for specific content descriptions 158 return description; 159 // default description 160 if (description instanceof DefaultDescription) 161 // return an context specific description instead 162 return new DefaultDescription(new ContentTypeSettings((ContentType) description.getContentTypeInfo(), context)); 163 // non-default description 164 // replace info object with context specific settings 165 ((ContentDescription) description).setContentTypeInfo(new ContentTypeSettings((ContentType) description.getContentTypeInfo(), context)); 166 return description; 167 } 168 169 } 170