/*******************************************************************************
* Copyright (c) 2007, 2016 Intel 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:
* Intel Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.settings.model.util;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.ILanguageDescriptor;
import org.eclipse.cdt.core.model.LanguageManager;
import org.eclipse.cdt.core.settings.model.CIncludeFileEntry;
import org.eclipse.cdt.core.settings.model.CIncludePathEntry;
import org.eclipse.cdt.core.settings.model.CLibraryFileEntry;
import org.eclipse.cdt.core.settings.model.CLibraryPathEntry;
import org.eclipse.cdt.core.settings.model.CMacroEntry;
import org.eclipse.cdt.core.settings.model.CMacroFileEntry;
import org.eclipse.cdt.core.settings.model.COutputEntry;
import org.eclipse.cdt.core.settings.model.CSourceEntry;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICExclusionPatternPathEntry;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICLibraryFileEntry;
import org.eclipse.cdt.core.settings.model.ICOutputEntry;
import org.eclipse.cdt.core.settings.model.ICSettingBase;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.ICSourceEntry;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.cdt.core.settings.model.extension.CBuildData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationData;
import org.eclipse.cdt.core.settings.model.extension.CFolderData;
import org.eclipse.cdt.core.settings.model.extension.CLanguageData;
import org.eclipse.cdt.core.settings.model.extension.CResourceData;
import org.eclipse.cdt.core.settings.model.extension.CTargetPlatformData;
import org.eclipse.cdt.core.settings.model.extension.impl.CDataFactory;
import org.eclipse.cdt.core.settings.model.extension.impl.CDefaultLanguageData;
import org.eclipse.cdt.internal.core.WeakHashSet;
import org.eclipse.cdt.internal.core.WeakHashSetSynchronized;
import org.eclipse.cdt.internal.core.settings.model.ExceptionFactory;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.content.IContentTypeManager;
import org.eclipse.core.runtime.content.IContentTypeSettings;
import org.eclipse.core.runtime.preferences.IScopeContext;
public class CDataUtil {
private static final String EMPTY = ""; //$NON-NLS-1$
private static final String DELIM = " "; //$NON-NLS-1$
private static Random randomNumber;
public static final String[] EMPTY_STRING_ARRAY = {};
/**
* Pool of setting entries implemented as WeakHashSet. That allows to gain memory savings
* at the expense of CPU time. WeakHashSet handles garbage collection when a list is not
* referenced anywhere else. See JavaDoc {@link java.lang.ref.WeakReference} about weak reference objects.
*/
private static WeakHashSet<ICSettingEntry> settingEntriesPool = new WeakHashSetSynchronized<>();
public static int genRandomNumber() {
if (randomNumber == null) {
// Set the random number seed
randomNumber = new Random();
randomNumber.setSeed(System.currentTimeMillis());
}
int i = randomNumber.nextInt();
if (i < 0) {
i *= -1;
}
return i;
}
public static String genId(String baseId) {
String suffix = Integer.toString(genRandomNumber());
return baseId != null ?
new StringBuilder(baseId).append(".").append(suffix).toString() : //$NON-NLS-1$
suffix;
}
public static boolean objectsEqual(Object o1, Object o2) {
if (o1 == null)
return o2 == null;
return o1.equals(o2);
}
public static String arrayToString(String[] array, String separator) {
return arrayToString((Object[])array, separator);
}
public static String arrayToString(Object[] array, String separator) {
if (array == null)
return null;
if (array.length == 0)
return ""; //$NON-NLS-1$
if (array.length == 1)
return array[0].toString();
StringBuilder buf = new StringBuilder();
buf.append(array[0]);
for (int i = 1; i < array.length; i++) {
buf.append(separator).append(array[i]);
}
return buf.toString();
}
public static String[] stringToArray(String string, String separator) {
if (string == null)
return null;
if (string.length() == 0)
return EMPTY_STRING_ARRAY;
StringTokenizer t = new StringTokenizer(string, separator);
List<String> list = new ArrayList<>(t.countTokens());
while (t.hasMoreElements()) {
list.add(t.nextToken());
}
return list.toArray(new String[list.size()]);
}
public static ICSettingEntry[] resolveEntries(ICSettingEntry entries[], ICConfigurationDescription cfgDes) {
if (entries.length == 0)
return entries;
ArrayList<ICSettingEntry> out = new ArrayList<>(entries.length);
ICdtVariableManager mngr = CCorePlugin.getDefault().getCdtVariableManager();
for (int i = 0; i < entries.length; i++) {
ICSettingEntry entry = entries[i];
out.addAll(Arrays.asList(createResolvedEntry(entry, cfgDes, mngr)));
}
return out.toArray(new ICSettingEntry[out.size()]);
}
public static ICLanguageSettingEntry[] resolveEntries(ICLanguageSettingEntry entries[], ICConfigurationDescription cfgDes) {
if (entries.length == 0)
return entries;
ICSettingEntry[] resolved = resolveEntries((ICSettingEntry[])entries, cfgDes);
ICLanguageSettingEntry[] resolvedLangEntries = new ICLanguageSettingEntry[resolved.length];
System.arraycopy(resolved, 0, resolvedLangEntries, 0, resolved.length);
return resolvedLangEntries;
}
public static ICSourceEntry[] resolveEntries(ICSourceEntry entries[], ICConfigurationDescription cfgDes) {
if (entries.length == 0)
return entries;
ICSettingEntry[] resolved = resolveEntries((ICSettingEntry[])entries, cfgDes);
ICSourceEntry[] resolvedLangEntries = new ICSourceEntry[resolved.length];
System.arraycopy(resolved, 0, resolvedLangEntries, 0, resolved.length);
return resolvedLangEntries;
}
public static ICOutputEntry[] resolveEntries(ICOutputEntry entries[], ICConfigurationDescription cfgDes) {
if (entries.length == 0)
return entries;
ICSettingEntry[] resolved = resolveEntries((ICSettingEntry[])entries, cfgDes);
ICOutputEntry[] resolvedLangEntries = new ICOutputEntry[resolved.length];
System.arraycopy(resolved, 0, resolvedLangEntries, 0, resolved.length);
return resolvedLangEntries;
}
private static ICSettingEntry[] createResolvedEntry(ICSettingEntry entry, ICConfigurationDescription cfg, ICdtVariableManager mngr) {
if (entry.isResolved())
return new ICSettingEntry[] { entry };
String name = entry.getName();
String[] names = new String[] { name }; // default value
try {
if ((entry.getKind() != ICSettingEntry.MACRO) &&
mngr.isStringListValue(name, cfg)) {
names = mngr.resolveStringListValue(name, EMPTY, DELIM, cfg);
} else {
names[0] = mngr.resolveValue(name, EMPTY, DELIM, cfg);
}
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
ICSettingEntry[] result = new ICSettingEntry[names.length];
for (int k=0; k<names.length; k++) {
String value = null;
IPath[] exclusionFilters = null;
IPath srcPath = null, srcRootPath = null, srcPrefixMapping = null;
switch (entry.getKind()) {
case ICSettingEntry.MACRO:
value = entry.getValue();
try {
value = mngr.resolveValue(value, EMPTY, DELIM, cfg);
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
break;
case ICSettingEntry.LIBRARY_FILE:
ICLibraryFileEntry libFile = (ICLibraryFileEntry)entry;
srcPath = libFile.getSourceAttachmentPath();
srcRootPath = libFile.getSourceAttachmentRootPath();
srcPrefixMapping = libFile.getSourceAttachmentPrefixMapping();
if (srcPath != null)
srcPath = resolvePath(mngr, cfg, srcPath);
if (srcRootPath != null)
srcRootPath = resolvePath(mngr, cfg, srcRootPath);
if (srcPrefixMapping != null)
srcPrefixMapping = resolvePath(mngr, cfg, srcPrefixMapping);
break;
case ICSettingEntry.SOURCE_PATH:
case ICSettingEntry.OUTPUT_PATH:
exclusionFilters = ((ICExclusionPatternPathEntry)entry).getExclusionPatterns();
for (int i = 0; i < exclusionFilters.length; i++) {
String exclString = exclusionFilters[i].toString();
try {
exclString = mngr.resolveValue(exclString, EMPTY, DELIM, cfg);
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
exclusionFilters[i] = new Path(exclString);
}
break;
default:
break;
}
result[k] = createEntry(entry.getKind(), names[k], value, exclusionFilters, entry.getFlags() | ICSettingEntry.RESOLVED, srcPath, srcRootPath, srcPrefixMapping);
}
return result;
}
private static IPath resolvePath(ICdtVariableManager mngr, ICConfigurationDescription cfg, IPath path) {
if (path == null)
return null;
try {
String unresolved = path.toString();
String resolved = mngr.resolveValue(unresolved, EMPTY, DELIM, cfg);
if (resolved != null && !resolved.equals(unresolved))
path = new Path(resolved);
} catch (CdtVariableException e) {
CCorePlugin.log(e);
}
return path;
}
/**
* Return entry cached in setting entries pool to optimize for memory usage.
* Note that the pool will handle garbage collection for unreferenced entries.
*
* @since 5.4
*/
@SuppressWarnings("unchecked")
public static <T extends ICSettingEntry> T getPooledEntry(T entry) {
return (T) settingEntriesPool.add(entry);
}
/**
* Convenience method to clone {@link ICLanguageSettingEntry} with modified flags.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @param entry - source entry.
* @param flagsToAdd - binary combination of bits to add to the flags.
* @param flafsToClear - binary combination of bits to clear in the flags.
* @return new entry with the modified flags.
*/
public static ICLanguageSettingEntry createEntry(ICLanguageSettingEntry entry, int flagsToAdd, int flafsToClear) {
return createEntry(entry, (entry.getFlags() | flagsToAdd) & (~flafsToClear));
}
/**
* Convenience method to clone {@link ICLanguageSettingEntry} with different flags.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @param entry - source entry.
* @param flags - new flags.
* @return new entry with the specified flags.
*/
public static ICLanguageSettingEntry createEntry(ICLanguageSettingEntry entry, int flags) {
switch (entry.getKind()) {
case ICSettingEntry.INCLUDE_PATH:
entry = new CIncludePathEntry(entry.getName(), flags);
break;
case ICSettingEntry.MACRO:
entry = new CMacroEntry(entry.getName(), entry.getValue(), flags);
break;
case ICSettingEntry.INCLUDE_FILE:
entry = new CIncludeFileEntry(entry.getName(), flags);
break;
case ICSettingEntry.MACRO_FILE:
entry = new CMacroFileEntry(entry.getName(), flags);
break;
case ICSettingEntry.LIBRARY_PATH:
entry = new CLibraryPathEntry(entry.getName(), flags);
break;
case ICSettingEntry.LIBRARY_FILE:
ICLibraryFileEntry libFile = (ICLibraryFileEntry)entry;
entry = new CLibraryFileEntry(entry.getName(),
flags,
libFile.getSourceAttachmentPath(),
libFile.getSourceAttachmentRootPath(),
libFile.getSourceAttachmentPrefixMapping()
);
break;
}
return getPooledEntry(entry);
}
/**
* Convenience method to create {@link ICSettingEntry} depending on kind.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*/
public static ICSettingEntry createEntry(int kind, String name, String value, IPath[] exclusionPatterns, int flags) {
return createEntry(kind, name, value, exclusionPatterns, flags, null, null, null);
}
/**
* Convenience method to create {@link ICSettingEntry} depending on kind.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*/
public static ICSettingEntry createEntry(int kind, String name, String value, IPath[] exclusionPatterns, int flags, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath, IPath sourceAttachmentPrefixMapping) {
ICSettingEntry entry = null;
switch (kind) {
case ICLanguageSettingEntry.INCLUDE_PATH:
entry = new CIncludePathEntry(name, flags);
break;
case ICLanguageSettingEntry.MACRO:
entry = new CMacroEntry(name, value, flags);
break;
case ICLanguageSettingEntry.INCLUDE_FILE:
entry = new CIncludeFileEntry(name, flags);
break;
case ICLanguageSettingEntry.MACRO_FILE:
entry = new CMacroFileEntry(name, flags);
break;
case ICLanguageSettingEntry.LIBRARY_PATH:
entry = new CLibraryPathEntry(name, flags);
break;
case ICLanguageSettingEntry.LIBRARY_FILE:
entry = new CLibraryFileEntry(name, flags, sourceAttachmentPath, sourceAttachmentRootPath, sourceAttachmentPrefixMapping);
break;
case ICLanguageSettingEntry.OUTPUT_PATH:
entry = new COutputEntry(name, exclusionPatterns, flags);
break;
case ICLanguageSettingEntry.SOURCE_PATH:
entry = new CSourceEntry(name, exclusionPatterns, flags);
break;
default:
throw new IllegalArgumentException();
}
return getPooledEntry(entry);
}
/**
* Utility method to create {@link CIncludePathEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CIncludePathEntry createCIncludePathEntry(String name, int flags) {
return getPooledEntry(new CIncludePathEntry(name, flags));
}
/**
* Utility method to create {@link CIncludeFileEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CIncludeFileEntry createCIncludeFileEntry(String name, int flags) {
return getPooledEntry(new CIncludeFileEntry(name, flags));
}
/**
* Utility method to create {@link CMacroEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CMacroEntry createCMacroEntry(String name, String value, int flags) {
return getPooledEntry(new CMacroEntry(name, value, flags));
}
/**
* Utility method to create {@link CMacroFileEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CMacroFileEntry createCMacroFileEntry(String name, int flags) {
return getPooledEntry(new CMacroFileEntry(name, flags));
}
/**
* Utility method to create {@link CLibraryPathEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CLibraryPathEntry createCLibraryPathEntry(String name, int flags) {
return getPooledEntry(new CLibraryPathEntry(name, flags));
}
/**
* Utility method to create {@link CLibraryFileEntry}.
* Note that this method keeps the entries in the pool to avoid proliferation of duplicates.
*
* @since 5.4
*/
public static CLibraryFileEntry createCLibraryFileEntry(String name, int flags) {
return getPooledEntry(new CLibraryFileEntry(name, flags));
}
public static String[] getSourceExtensions(IProject project, CLanguageData data) {
String[] exts = null;
String[] typeIds = data.getSourceContentTypeIds();
if (typeIds != null && typeIds.length != 0) {
exts = getExtensionsFromContentTypes(project, typeIds);
} else {
exts = data.getSourceExtensions();
if (exts != null && exts.length != 0)
exts = exts.clone();
else
exts = CDefaultLanguageData.EMPTY_STRING_ARRAY;
}
if (exts == null)
exts = CDefaultLanguageData.EMPTY_STRING_ARRAY;
return exts;
}
public static String[] getExtensionsFromContentTypes(IProject project, String[] typeIds) {
String[] exts = null;
if (typeIds != null && typeIds.length != 0) {
IContentTypeManager manager = Platform.getContentTypeManager();
IContentType type;
if (typeIds.length == 1) {
type = manager.getContentType(typeIds[0]);
if (type != null)
exts = getContentTypeFileSpecs(project, type);
} else {
List<String> list = new ArrayList<>();
for (int i = 0; i < typeIds.length; i++) {
type = manager.getContentType(typeIds[i]);
if (type != null) {
list.addAll(Arrays.asList(getContentTypeFileSpecs(project, type)));
}
}
exts = list.toArray(new String[list.size()]);
}
}
if (exts == null)
exts = CDefaultLanguageData.EMPTY_STRING_ARRAY;
return exts;
}
public static String[] getContentTypeFileSpecs (IProject project, IContentType type) {
String[] globalSpecs = type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
IContentTypeSettings settings = null;
if (project != null) {
IScopeContext projectScope = new ProjectScope(project);
try {
settings = type.getSettings(projectScope);
} catch (Exception e) {}
if (settings != null) {
String[] specs = settings.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
if (specs.length > 0) {
int total = globalSpecs.length + specs.length;
String[] projSpecs = new String[total];
int i=0;
for (int j=0; j<specs.length; j++) {
projSpecs[i] = specs[j];
i++;
}
for (int j=0; j<globalSpecs.length; j++) {
projSpecs[i] = globalSpecs[j];
i++;
}
return projSpecs;
}
}
}
return globalSpecs;
}
public static CLanguageData findLanguagDataForFile(String fileName, IProject project, CFolderData fData) {
return findLanguagDataForFile(fileName, project, fData.getLanguageDatas());
}
public static CLanguageData findLanguagDataForFile(String fileName, IProject project, CLanguageData datas[]) {
// if (cType != null) {
// setting = findLanguageSettingForContentTypeId(cType.getId(), settings, true);
// if (setting == null)
// setting = findLanguageSettingForContentTypeId(cType.getId(), settings, false);
// }
CLanguageData data = null;
int index = fileName.lastIndexOf('.');
if (index > 0) {
String ext = fileName.substring(index + 1).trim();
if (ext.length() > 0) {
data = findLanguageDataForExtension(ext, datas);
}
}
return data;
}
public static CLanguageData findLanguageDataForExtension(String ext, CLanguageData datas[]/*, boolean src*/) {
CLanguageData data;
for (int i = 0; i < datas.length; i++) {
data = datas[i];
String exts[] = data.getSourceExtensions();
/* if (src) {
if (setting.getSourceContentType() == null) {
exts = setting.getSourceExtensions();
}
} else {
if (setting.getHeaderContentType() == null) {
exts = setting.getHeaderExtensions();
}
}
*/
if (exts != null && exts.length != 0) {
for (int j = 0; j < exts.length; j++) {
if (ext.equals(exts[j]))
return data;
}
}
}
return null;
}
public static Map<IPath, CResourceData> createPathRcDataMap(CConfigurationData data) {
Map<IPath, CResourceData> map = new HashMap<>();
CResourceData[] rcDatas = data.getResourceDatas();
CResourceData rcData;
for (int i = 0; i < rcDatas.length; i++) {
rcData = rcDatas[i];
map.put(rcData.getPath(), rcData);
}
return map;
}
public static PathSettingsContainer createRcDataHolder(CConfigurationData data) {
PathSettingsContainer h = PathSettingsContainer.createRootContainer();
h.setValue(data.getRootFolderData());
CResourceData[] rcDatas = data.getResourceDatas();
CResourceData rcData;
PathSettingsContainer child;
for (int i = 0; i < rcDatas.length; i++) {
rcData = rcDatas[i];
child = h.getChildContainer(rcData.getPath(), true, true);
child.setValue(rcData);
}
return h;
}
public static CConfigurationData createEmptyData(String id, String name, CDataFactory factory, boolean performLangAdjustment) {
if (id == null)
id = genId(null);
CConfigurationData data = factory.createConfigurationdata(id, name, null, false);
if (data.getRootFolderData() == null) {
CFolderData foData = factory.createFolderData(data, null, genId(data.getId()), false, Path.EMPTY);
factory.link(data, foData);
}
if (data.getBuildData() == null) {
CBuildData bData = factory.createBuildData(data, null, genId(data.getId()), null, false);
factory.link(data, bData);
}
if (data.getTargetPlatformData() == null) {
CTargetPlatformData tpData = factory.createTargetPlatformData(data, null, genId(data.getId()), null, false);
factory.link(data, tpData);
}
if (performLangAdjustment)
adjustConfig(data, factory);
return data;
}
public static CConfigurationData adjustConfig(CConfigurationData cfg, CDataFactory factory) {
LanguageManager mngr = LanguageManager.getInstance();
ILanguageDescriptor dess[] = mngr.getLanguageDescriptors();
Map<String, ILanguageDescriptor[]> map = mngr.getContentTypeIdToLanguageDescriptionsMap();
CResourceData[] rcDatas = cfg.getResourceDatas();
for (int i = 0; i < rcDatas.length; i++) {
if (rcDatas[i].getType() == ICSettingBase.SETTING_FOLDER) {
adjustFolderData(cfg, (CFolderData)rcDatas[i], factory, dess, new HashMap<>(map));
}
}
return cfg;
}
private static void adjustFolderData(CConfigurationData cfgData, CFolderData data, CDataFactory factory, ILanguageDescriptor dess[], HashMap<String, ILanguageDescriptor[]> map) {
Map<String, ILanguageDescriptor> langMap = new HashMap<>();
for (int i = 0; i < dess.length; i++) {
langMap.put(dess[i].getId(), dess[i]);
}
CLanguageData lDatas[] = data.getLanguageDatas();
for (int i = 0; i < lDatas.length; i++) {
CLanguageData lData = lDatas[i];
String langId = lData.getLanguageId();
if (langId != null) {
ILanguageDescriptor des = langMap.remove(langId);
adjustLanguageData(data, lData, des);
continue;
} else {
String[] cTypeIds = lData.getSourceContentTypeIds();
for (int c = 0; c < cTypeIds.length; c++) {
String cTypeId = cTypeIds[c];
ILanguageDescriptor[] langs = map.remove(cTypeId);
if (langs != null && langs.length != 0) {
for (int q = 0; q < langs.length; q++) {
langMap.remove(langs[q].getId());
}
adjustLanguageData(data, lData, langs[0]);
}
}
}
}
if (!langMap.isEmpty()) {
addLangs(cfgData, data, factory, langMap, map);
}
}
private static CLanguageData adjustLanguageData(CFolderData data, CLanguageData lData, ILanguageDescriptor des) {
String [] cTypeIds = des.getContentTypeIds();
String srcIds[] = lData.getSourceContentTypeIds();
Set<String> landTypes = new HashSet<>(Arrays.asList(cTypeIds));
landTypes.removeAll(Arrays.asList(srcIds));
if (landTypes.size() != 0) {
List<String> srcList = new ArrayList<>();
srcList.addAll(landTypes);
lData.setSourceContentTypeIds(srcList.toArray(new String[srcList.size()]));
}
if (!des.getId().equals(lData.getLanguageId())) {
lData.setLanguageId(des.getId());
}
return lData;
}
private static void addLangs(CConfigurationData cfgData, CFolderData data, CDataFactory factory, Map<String, ILanguageDescriptor> langMap, Map<String, ILanguageDescriptor[]> cTypeToLangMap) {
List<ILanguageDescriptor> list = new ArrayList<>(langMap.values());
ILanguageDescriptor des;
while(list.size() != 0) {
des = list.remove(list.size() - 1);
String[] ctypeIds = des.getContentTypeIds();
boolean addLang = false;
for (int i = 0; i < ctypeIds.length; i++) {
ILanguageDescriptor[] langs = cTypeToLangMap.remove(ctypeIds[i]);
if (langs != null && langs.length != 0) {
addLang = true;
for (int q = 0; q < langs.length; q++) {
list.remove(langs[q]);
}
}
}
if (addLang) {
CLanguageData lData = factory.createLanguageData(cfgData, data, genId(data.getId()), des.getName(), des.getId(),
ICSettingEntry.INCLUDE_FILE
| ICSettingEntry.INCLUDE_PATH
| ICSettingEntry.MACRO
| ICSettingEntry.MACRO_FILE,
ctypeIds, true);
factory.link(data, lData);
}
}
}
public static boolean isExcluded(IPath path, ICSourceEntry[] entries) {
for (int i = 0; i < entries.length; i++) {
if (!isExcluded(path, entries[i]))
return false;
}
return true;
}
public static boolean isExcluded(IPath path, ICSourceEntry entry) {
IPath entryPath = new Path(entry.getName());
if (path.isPrefixOf(entryPath))
return false;
if (!entryPath.isPrefixOf(path))
return true;
if (path.segmentCount() == 0)
return false;
char[][] exclusions = entry.fullExclusionPatternChars();
return CoreModelUtil.isExcluded(path, exclusions);
}
public static boolean isOnSourceEntry(IPath path, ICSourceEntry entry) {
IPath entryPath = new Path(entry.getName());
if (path.equals(entryPath))
return true;
if (!entryPath.isPrefixOf(path))
return false;
if (path.segmentCount() == 0)
return true;
char[][] exclusions = entry.fullExclusionPatternChars();
return !CoreModelUtil.isExcluded(path, exclusions);
}
public static boolean canExclude(IPath path, boolean isFolder, boolean excluded, ICSourceEntry[] entries) {
try {
ICSourceEntry[] out = setExcluded(path, isFolder, excluded, entries, false);
return !isEqual(entries, out);
} catch (CoreException e) { }
return false;
}
/**
*
* @param ein - initial source entries
* @param aus - resulting source entries
* @return - true if they are equal
*/
public static boolean isEqual(ICSourceEntry[] ein, ICSourceEntry[] aus) {
if (ein == null || aus == null)
return (ein == null && aus == null);
if (ein.length != aus.length)
return false;
for (int i= 0; i < ein.length; i++) {
boolean found = false;
for (int j=0; j<aus.length; j++) {
if (!ein[i].equalsByName(aus[j]))
continue;
if (ein[i].equalsByContents(aus[j])) {
found = true;
break;
}
return false; // contents is changed !
}
if (!found)
return false; // name is not found !
}
return true; // all entries are equal by name and contents
}
public static ICSourceEntry[] setExcluded(IPath path, boolean isFolder, boolean excluded, ICSourceEntry[] entries) throws CoreException {
return setExcluded(path, isFolder, excluded, entries, true);
}
public static ICSourceEntry[] setExcludedIfPossible(IPath path, boolean isFolder, boolean excluded, ICSourceEntry[] entries) {
try {
ICSourceEntry[] newEntries = setExcluded(path, isFolder, excluded, entries, false);
if (newEntries == null)
newEntries = entries;
return newEntries;
} catch (CoreException e) {
}
return entries;
}
public static ICSourceEntry[] setExcluded(IPath path, boolean isFolder, boolean excluded, ICSourceEntry[] entries, boolean throwExceptionOnErr) throws CoreException {
if (isExcluded(path, entries) == excluded)
return entries;
ICSourceEntry[] newEntries;
if (excluded) {
List<ICSourceEntry> includeList = new ArrayList<>(entries.length);
List<ICSourceEntry> excludeList = new ArrayList<>(entries.length);
sortEntries(path, false, entries, includeList, excludeList);
for (int i = 0; i < includeList.size(); i++) {
ICSourceEntry oldEntry = includeList.get(i);
List<IPath> tmp = new ArrayList<IPath>(1);
tmp.add(path);
ICSourceEntry newEntry = addExcludePaths(oldEntry, tmp, true);
if (newEntry != null)
excludeList.add(newEntry);
}
newEntries = excludeList.toArray(new ICSourceEntry[excludeList.size()]);
} else {
List<ICSourceEntry> includeList = new ArrayList<>(entries.length + 1);
List<ICSourceEntry> excludeList = new ArrayList<>(entries.length);
sortIncludingExcludingEntries(path, entries, includeList, excludeList);
boolean included = false;
if (includeList.size() != 0) {
if (includeExclusion(path, includeList) >= 0)
included = true;
}
if (!included) {
if (isFolder) {
includeList.add(new CSourceEntry(path, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED));
} else {
if (throwExceptionOnErr)
throw ExceptionFactory.createCoreException("can not create a source entry for individual file"); //$NON-NLS-1$
return null;
}
}
includeList.addAll(excludeList);
newEntries = includeList.toArray(new ICSourceEntry[includeList.size()]);
}
return newEntries;
}
private static int includeExclusion(IPath path, List<ICSourceEntry> entries) {
for (int i = 0; i < entries.size(); i++) {
ICSourceEntry entry = entries.get(i);
entry = include(path, entry);
if (entry != null) {
entries.set(i, entry);
return i;
}
}
return -1;
}
private static ICSourceEntry include(IPath path, ICSourceEntry entry) {
IPath[] exclusions = entry.getExclusionPatterns();
IPath entryPath = new Path(entry.getName());
IPath relPath = path.removeFirstSegments(entryPath.segmentCount()).makeRelative();
for (int k = 0; k < exclusions.length; k++) {
if (exclusions[k].equals(relPath)) {
IPath updatedExclusions[] = new IPath[exclusions.length - 1];
System.arraycopy(exclusions, 0, updatedExclusions, 0, k);
System.arraycopy(exclusions, k + 1, updatedExclusions, k, updatedExclusions.length - k);
ICSourceEntry updatedEntry = new CSourceEntry(entry.getName(), updatedExclusions, entry.getFlags());
if (isOnSourceEntry(path, updatedEntry))
return updatedEntry;
exclusions = updatedExclusions;
entry = updatedEntry;
}
}
return null;
}
private static void sortIncludingExcludingEntries(IPath path, ICSourceEntry[] entries, List<ICSourceEntry> including, List<ICSourceEntry> excluding) {
for (int i = 0; i < entries.length; i++) {
IPath entryPath = new Path(entries[i].getName());
if (entryPath.isPrefixOf(path)) {
including.add(entries[i]);
} else {
excluding.add(entries[i]);
}
}
}
public static ICSourceEntry[] adjustEntries(ICSourceEntry entries[]) {
return adjustEntries(entries, false, null);
}
private static ICSourceEntry[] getDefaultSourceEntries(boolean absolute, IProject project) {
ICSourceEntry entry;
if (absolute) {
if (project != null) {
entry = new CSourceEntry(project.getFullPath(), null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
} else {
entry = new CSourceEntry(Path.EMPTY, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
}
} else {
entry = new CSourceEntry(Path.EMPTY, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
}
return new ICSourceEntry[] { entry };
}
private static ICOutputEntry[] getDefaultOutputEntries(boolean absolute, IProject project) {
ICOutputEntry entry;
if (absolute) {
if (project != null) {
entry = new COutputEntry(project.getFullPath(), null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
} else {
entry = new COutputEntry(Path.EMPTY, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
}
} else {
entry = new COutputEntry(Path.EMPTY, null, ICSettingEntry.VALUE_WORKSPACE_PATH | ICSettingEntry.RESOLVED);
}
return new ICOutputEntry[] { entry };
}
public static ICOutputEntry[] adjustEntries(ICOutputEntry entries[], boolean makeAbsolute, IProject project) {
if (entries == null || entries.length == 0)
return getDefaultOutputEntries(makeAbsolute, project);
return makeAbsolute ? makeAbsolute(project, entries) : makeRelative(project, entries);
}
public static ICSourceEntry[] adjustEntries(ICSourceEntry entries[], boolean makeAbsolute, IProject project) {
if (entries == null || entries.length == 0)
return getDefaultSourceEntries(makeAbsolute, project);
ICSourceEntry ei, ej;
LinkedHashMap<ICSourceEntry, List<IPath>> map = new LinkedHashMap<>();
for (int i = 0; i < entries.length; i++) {
ei = entries[i];
List<IPath> list = null;
for (int j = 0; j < entries.length; j++) {
ej = entries[j];
if (ei == ej)
continue;
IPath ejPath = new Path(ej.getName());
if (!isExcluded(ejPath, ei)) {
if (list == null)
list = new ArrayList<>();
list.add(ejPath);
}
}
map.put(ei, list);
}
List<ICSourceEntry> resultList = new ArrayList<>(entries.length);
for (Iterator<Map.Entry<ICSourceEntry, List<IPath>>> iter = map.entrySet().iterator(); iter.hasNext();) {
Map.Entry<ICSourceEntry, List<IPath>> entry = iter.next();
List<IPath> list = entry.getValue();
if (list == null) {
resultList.add(entry.getKey());
} else {
ICSourceEntry se = entry.getKey();
se = addExcludePaths(se, list, true);
if (se != null)
resultList.add(se);
}
}
if (makeAbsolute) {
if (project != null)
resultList = makeAbsolute(project, resultList);
} else {
resultList = makeRelative(project, resultList);
}
ICSourceEntry[] resultArray = resultList.toArray(new ICSourceEntry[resultList.size()]);
Arrays.sort(resultArray, new Comparator<ICSourceEntry>() {
@Override
public int compare(ICSourceEntry o1, ICSourceEntry o2) {
return o1.getFullPath().toString().compareTo(o2.getFullPath().toString());
}
});
return resultArray;
}
private static List<ICSourceEntry> makeRelative(IProject project, List<ICSourceEntry> list) {
int size = list.size();
for (int i = 0; i < size; i++) {
list.set(i, makeRelative(project, list.get(i)));
}
return list;
}
private static List<ICSourceEntry> makeAbsolute(IProject project, List<ICSourceEntry> list) {
int size = list.size();
for (int i = 0; i < size; i++) {
list.set(i, makeAbsolute(project, list.get(i)));
}
return list;
}
public static ICSourceEntry makeAbsolute(IProject project, ICSourceEntry entry) {
return (ICSourceEntry)makeAbsolute(project, entry, true);
}
public static ICSourceEntry makeRelative(IProject project, ICSourceEntry entry) {
return (ICSourceEntry)makeRelative(project, entry, true);
}
public static ICSourceEntry[] makeRelative(IProject project, ICSourceEntry[] entries) {
return (ICSourceEntry[])makeRelative(project, entries, true);
}
public static ICSourceEntry[] makeAbsolute(IProject project, ICSourceEntry[] entries) {
return (ICSourceEntry[])makeAbsolute(project, entries, true);
}
public static ICOutputEntry makeAbsolute(IProject project, ICOutputEntry entry) {
return (ICOutputEntry)makeAbsolute(project, entry, true);
}
public static ICOutputEntry makeRelative(IProject project, ICOutputEntry entry) {
return (ICOutputEntry)makeRelative(project, entry, true);
}
public static ICOutputEntry[] makeAbsolute(IProject project, ICOutputEntry[] entries) {
return (ICOutputEntry[])makeAbsolute(project, entries, true);
}
public static ICOutputEntry[] makeRelative(IProject project, ICOutputEntry[] entries) {
return (ICOutputEntry[])makeRelative(project, entries, true);
}
private static Collection<IPath> removePrefix(IPath prefix, Collection<IPath> paths, Collection<IPath> result) {
if (result == null)
result = new ArrayList<>(paths.size());
for (Iterator<IPath> iter = paths.iterator(); iter.hasNext(); ) {
IPath path = iter.next();
if (prefix.isPrefixOf(path))
result.add(path.removeFirstSegments(prefix.segmentCount()));
// else
// result.add(path);
}
return result;
}
public static ICSourceEntry addExcludePaths(ICSourceEntry entry, Collection<IPath> paths, boolean removePrefix) {
IPath entryPath = new Path(entry.getName());
IPath[] oldExclusions = entry.getExclusionPatterns();
// List newExList = new ArrayList(oldExclusions.length + paths.size());
LinkedHashSet<IPath> newSet = new LinkedHashSet<>();
if (removePrefix) {
removePrefix(entryPath, paths, newSet);
} else {
newSet.addAll(paths);
}
for (Iterator<IPath> iter = newSet.iterator(); iter.hasNext();) {
IPath path = iter.next();
if (path.segmentCount() == 0)
return null;
}
newSet.addAll(Arrays.asList(oldExclusions));
IPath[] newExclusions = newSet.toArray(new IPath[newSet.size()]);
return new CSourceEntry(entry.getName(), newExclusions, entry.getFlags());
}
private static void sortEntries(IPath path, boolean byExclude, ICSourceEntry[] entries, List<ICSourceEntry> included, List<ICSourceEntry> excluded) {
for (int i = 0; i < entries.length; i++) {
if (byExclude ? isExcluded(path, entries[i]) : !isOnSourceEntry(path, entries[i])) {
if (excluded != null)
excluded.add(entries[i]);
} else {
if (included != null)
included.add(entries[i]);
}
}
}
public static Map<EntryNameKey, ICSettingEntry> fillEntriesMapByNameKey(Map<EntryNameKey, ICSettingEntry> map, ICSettingEntry[] entries) {
if (map == null)
map = new LinkedHashMap<>();
for (int i = 0; i < entries.length; i++) {
ICSettingEntry entry = entries[i];
map.put(new EntryNameKey(entry), entry);
}
return map;
}
public static Map<EntryContentsKey, ICSettingEntry> fillEntriesMapByContentsKey(Map<EntryContentsKey, ICSettingEntry> map, ICSettingEntry[] entries) {
if (map == null)
map = new LinkedHashMap<>();
for (int i = 0; i < entries.length; i++) {
ICSettingEntry entry = entries[i];
map.put(new EntryContentsKey(entry), entry);
}
return map;
}
public static boolean getBoolean(ICStorageElement el, String attr, boolean defaultValue) {
if (el != null) {
String tmp = el.getAttribute(attr);
if (tmp != null) {
return Boolean.valueOf(tmp).booleanValue();
}
}
return defaultValue;
}
public static void setBoolean(ICStorageElement el, String attr, boolean value) {
el.setAttribute(attr, String.valueOf(value));
}
public static int getInteger(ICStorageElement el, String attr, int defaultValue) {
if (el != null) {
String tmp = el.getAttribute(attr);
if (tmp != null) {
try {
return Integer.parseInt(tmp);
} catch (NumberFormatException e) {
}
}
}
return defaultValue;
}
public static void setInteger(ICStorageElement el, String attr, int value) {
el.setAttribute(attr, Integer.toString(value));
}
public static ICExclusionPatternPathEntry addRemoveExclusionsToEntry(ICExclusionPatternPathEntry entry, IPath[] paths, boolean add) throws IllegalArgumentException{
if (paths == null || paths.length == 0)
return entry;
Set<IPath> set = mergeRemovingDups(entry.getExclusionPatterns(), paths, add);
IPath exclusions[] = set.toArray(new IPath[set.size()]);
return (ICExclusionPatternPathEntry)createEntry(entry.getKind(), entry.getName(), null, exclusions, entry.getFlags());
}
private static Set<IPath> mergeRemovingDups(IPath[] o1, IPath[] o2, boolean add) {
LinkedHashSet<IPath> set = new LinkedHashSet<>();
set.addAll(Arrays.asList(o1));
if (add) {
set.addAll(Arrays.asList(o2));
} else {
set.removeAll(Arrays.asList(o2));
}
return set;
}
public static ICExclusionPatternPathEntry makeAbsolute(IProject project, ICExclusionPatternPathEntry entry, boolean force) {
if (!entry.isValueWorkspacePath() && !force)
return entry;
IPath path = new Path(entry.getName());
IPath projPath = project.getFullPath();
if (!path.isAbsolute() || (force && !projPath.isPrefixOf(path))) {
path = projPath.append(path).makeAbsolute();
return (ICExclusionPatternPathEntry) createEntry(entry.getKind(), path.toString(), null, entry.getExclusionPatterns(), entry.getFlags());
}
return entry;
}
public static ICExclusionPatternPathEntry makeRelative(IProject project, ICExclusionPatternPathEntry entry, boolean force) {
if (!entry.isValueWorkspacePath() && !force)
return entry;
IPath path = new Path(entry.getName());
IPath projPath = project.getFullPath();
if (path.isAbsolute()) {
if (projPath.isPrefixOf(path)) {
path = path.removeFirstSegments(projPath.segmentCount()).makeRelative();
} else if (force) {
path = path.makeRelative();
}
return (ICExclusionPatternPathEntry) createEntry(entry.getKind(), path.toString(), null, entry.getExclusionPatterns(), entry.getFlags());
}
return entry;
}
public static ICExclusionPatternPathEntry[] makeRelative(IProject project, ICExclusionPatternPathEntry[] entries, boolean force) {
if (entries == null)
return null;
ICExclusionPatternPathEntry[] relEntries = (ICExclusionPatternPathEntry[])Array.newInstance(entries.getClass().getComponentType(), entries.length);
for (int i = 0; i < entries.length; i++) {
relEntries[i] = makeRelative(project, entries[i], force);
}
return relEntries;
}
public static ICExclusionPatternPathEntry[] makeAbsolute(IProject project, ICExclusionPatternPathEntry[] entries, boolean force) {
if (entries == null)
return null;
ICExclusionPatternPathEntry[] relEntries = (ICExclusionPatternPathEntry[])Array.newInstance(entries.getClass().getComponentType(), entries.length);
for (int i = 0; i < entries.length; i++) {
relEntries[i] = makeAbsolute(project, entries[i], force);
}
return relEntries;
}
}