/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2017 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.sarl.eclipse.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.content.IContentDescription;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.util.GenericXMLWriter;
import org.eclipse.jdt.internal.core.ClasspathAccessRule;
import org.eclipse.jdt.internal.core.ClasspathAttribute;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.ClasspathEntry.AssertionFailedException;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Class mostly inspired from jdt See {@link JavaProject#decodeClasspath} and {@code ClasspathEntry}.
*
* @author $Author: ngaud$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("checkstyle:classdataabstractioncoupling")
public final class JavaClasspathParser {
/**
* UnknownXmlElements.
*
* @author $Author: ngaud$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
static class UnknownXmlElements {
/**
* Unknown attributes.
*/
String[] attributes;
/**
* Unknown children.
*/
List<String> children;
}
/**
* Private constructor.
*/
private JavaClasspathParser() {
//
}
/**
* Reads entry of a .classpath file.
*
* @param projectName
* - the name of project containing the .classpath file
* @param projectRootAbsoluteFullPath
* - the path to project containing the .classpath file
* @return the set of CLasspath ENtries extracted from the .classpath
* @throws CoreException
* - exception during parsing of .classpath
* @throws IOException
* - exception during parsing of .classpath
* @throws ClasspathEntry.AssertionFailedException
* - exception during parsing of .classpath
* @throws URISyntaxException
* - exception during parsing of .classpath
*/
public static IClasspathEntry[][] readFileEntriesWithException(String projectName, URL projectRootAbsoluteFullPath)
throws CoreException, IOException, ClasspathEntry.AssertionFailedException, URISyntaxException {
return readFileEntriesWithException(projectName, projectRootAbsoluteFullPath, null);
}
/**
* Reads entry of a .classpath file.
*
* @param projectName
* - the name of project containing the .classpath file
* @param projectRootAbsoluteFullPath
* - the path to project containing the .classpath file
* @param unknownElements
* - map of unknow elements
* @return the set of CLasspath Entries extracted from the .classpath
* @throws CoreException
* - exception during parsing of .classpath
* @throws IOException
* - exception during parsing of .classpath
* @throws ClasspathEntry.AssertionFailedException
* - exception during parsing of .classpath
* @throws URISyntaxException
* - exception during parsing of .classpath
*/
@SuppressWarnings("checkstyle:innerassignment")
public static IClasspathEntry[][] readFileEntriesWithException(String projectName, URL projectRootAbsoluteFullPath,
Map<IPath, UnknownXmlElements> unknownElements)
throws CoreException, IOException, ClasspathEntry.AssertionFailedException, URISyntaxException {
final URL rscFile = new URL(projectRootAbsoluteFullPath.toExternalForm().concat(JavaProject.CLASSPATH_FILENAME));
byte[] bytes;
// when a project is imported, we get a first delta for the addition of the .project, but the .classpath is not accessible
// so default to using java.io.File
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=96258
final URI location;
try {
location = rscFile.toURI();
} catch (URISyntaxException e) {
throw e;
}
if (location == null) {
throw new IOException("Cannot obtain a location URI for " + rscFile); //$NON-NLS-1$
}
final File file = Util.toLocalFile(location, null/* no progress monitor available */);
if (file == null) {
throw new IOException("Unable to fetch file from " + location); //$NON-NLS-1$
}
try {
bytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file);
} catch (IOException e) {
throw e;
}
if (hasUTF8BOM(bytes)) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=240034
final int length = bytes.length - IContentDescription.BOM_UTF_8.length;
System.arraycopy(bytes, IContentDescription.BOM_UTF_8.length, bytes = new byte[length], 0, length);
}
String xmlClasspath;
try {
// .classpath always encoded with UTF-8
xmlClasspath = new String(bytes, org.eclipse.jdt.internal.compiler.util.Util.UTF_8);
} catch (UnsupportedEncodingException e) {
Util.log(e, "Could not read .classpath with UTF-8 encoding"); //$NON-NLS-1$
// fallback to default
xmlClasspath = new String(bytes);
}
return decodeClasspath(projectName, Path.fromPortableString(projectRootAbsoluteFullPath.getPath()), xmlClasspath, unknownElements);
}
private static boolean hasUTF8BOM(byte[] bytes) {
if (bytes.length > IContentDescription.BOM_UTF_8.length) {
for (int i = 0, length = IContentDescription.BOM_UTF_8.length; i < length; i++) {
if (IContentDescription.BOM_UTF_8[i] != bytes[i]) {
return false;
}
}
return true;
}
return false;
}
/**
* Reads and decode an XML classpath string. Returns a two-dimensional array, where the number of elements in the row is fixed to 2. The first
* element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored by the client
* earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
*
* @param projectName
* - the name of project containing the .classpath file
* @param projectRootAbsoluteFullPath
* - the path to project containing the .classpath file
* @param xmlClasspath
* - path to the XML
* @param unknownElements
* - map of unknow elements
* @return the set of CLasspath ENtries extracted from the .classpath
* @throws IOException
* - exception during parsing of .classpath
* @throws ClasspathEntry.AssertionFailedException
* - exception during parsing of .classpath
*/
@SuppressWarnings("checkstyle:npathcomplexity")
public static IClasspathEntry[][] decodeClasspath(String projectName, IPath projectRootAbsoluteFullPath, String xmlClasspath,
Map<IPath, UnknownXmlElements> unknownElements) throws IOException, ClasspathEntry.AssertionFailedException {
final List<IClasspathEntry> paths = new ArrayList<>();
IClasspathEntry defaultOutput = null;
final Element cpElement;
try (StringReader reader = new StringReader(xmlClasspath);) {
final DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
} catch (SAXException e) {
throw new IOException(Messages.file_badFormat);
} catch (ParserConfigurationException e) {
throw new IOException(Messages.file_badFormat);
}
if (!cpElement.getNodeName().equalsIgnoreCase("classpath")) { //$NON-NLS-1$
throw new IOException(Messages.file_badFormat);
}
NodeList list = cpElement.getElementsByTagName(ClasspathEntry.TAG_CLASSPATHENTRY);
int length = list.getLength();
for (int i = 0; i < length; ++i) {
final Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
final IClasspathEntry entry = elementDecode((Element) node, projectName, projectRootAbsoluteFullPath, unknownElements);
if (entry != null) {
if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
// separate output
defaultOutput = entry;
} else {
paths.add(entry);
}
}
}
}
final int pathSize = paths.size();
final IClasspathEntry[][] entries = new IClasspathEntry[2][];
entries[0] = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
paths.toArray(entries[0]);
if (defaultOutput != null) {
// ensure output is last item
entries[0][pathSize] = defaultOutput;
}
paths.clear();
list = cpElement.getElementsByTagName(ClasspathEntry.TAG_REFERENCED_ENTRY);
length = list.getLength();
for (int i = 0; i < length; ++i) {
final Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
final IClasspathEntry entry = elementDecode((Element) node, projectName, projectRootAbsoluteFullPath, unknownElements);
if (entry != null) {
paths.add(entry);
}
}
}
entries[1] = new IClasspathEntry[paths.size()];
paths.toArray(entries[1]);
return entries;
}
// public IClasspathEntry decodeClasspathEntry(String projectName, IPath projectRootAbsoluteFullPath,String encodedEntry) {
//
// try {
// if (encodedEntry == null) return null;
// StringReader reader = new StringReader(encodedEntry);
// Element node;
//
// try {
// DocumentBuilder parser =
// DocumentBuilderFactory.newInstance().newDocumentBuilder();
// node = parser.parse(new InputSource(reader)).getDocumentElement();
// } catch (SAXException e) {
// return null;
// } catch (ParserConfigurationException e) {
// return null;
// } finally {
// reader.close();
// }
//
// if (!node.getNodeName().equalsIgnoreCase(ClasspathEntry.TAG_CLASSPATHENTRY)
// || node.getNodeType() != Node.ELEMENT_NODE) {
// return null;
// }
// return elementDecode(node, projectName,projectRootAbsoluteFullPath, null/*not interested in unknown elements*/);
// } catch (IOException e) {
// // bad format
// return null;
// }
// }
/**
* Decodes one XML element with the XML stream.
*
* @param element
* - the considered element
* @param projectName
* - the name of project containing the .classpath file
* @param projectRootAbsoluteFullPath
* - he path to project containing the .classpath file
* @param unknownElements
* - map of unknown elements
* @return the set of CLasspath ENtries extracted from the considered element
*/
@SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity" })
public static IClasspathEntry elementDecode(Element element, String projectName, IPath projectRootAbsoluteFullPath,
Map<IPath, UnknownXmlElements> unknownElements) {
final IPath projectPath = projectRootAbsoluteFullPath;
final NamedNodeMap attributes = element.getAttributes();
final NodeList children = element.getChildNodes();
final boolean[] foundChildren = new boolean[children.getLength()];
final String kindAttr = removeAttribute(ClasspathEntry.TAG_KIND, attributes);
final String pathAttr = removeAttribute(ClasspathEntry.TAG_PATH, attributes);
// ensure path is absolute
IPath path = new Path(pathAttr);
final int kind = kindFromString(kindAttr);
if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
if (!(path.segmentCount() > 0 && path.segment(0).equals(ClasspathEntry.DOT_DOT))) {
path = projectPath.append(path);
}
}
// source attachment info (optional)
IPath sourceAttachmentPath = element.hasAttribute(ClasspathEntry.TAG_SOURCEPATH)
? new Path(removeAttribute(ClasspathEntry.TAG_SOURCEPATH, attributes)) : null;
if (kind != IClasspathEntry.CPE_VARIABLE && sourceAttachmentPath != null && !sourceAttachmentPath.isAbsolute()) {
sourceAttachmentPath = projectPath.append(sourceAttachmentPath);
}
final IPath sourceAttachmentRootPath = element.hasAttribute(ClasspathEntry.TAG_ROOTPATH)
? new Path(removeAttribute(ClasspathEntry.TAG_ROOTPATH, attributes)) : null;
// exported flag (optional)
final boolean isExported = removeAttribute(ClasspathEntry.TAG_EXPORTED, attributes).equals("true"); //$NON-NLS-1$
// inclusion patterns (optional)
IPath[] inclusionPatterns = decodePatterns(attributes, ClasspathEntry.TAG_INCLUDING);
if (inclusionPatterns == null) {
inclusionPatterns = ClasspathEntry.INCLUDE_ALL;
}
// exclusion patterns (optional)
IPath[] exclusionPatterns = decodePatterns(attributes, ClasspathEntry.TAG_EXCLUDING);
if (exclusionPatterns == null) {
exclusionPatterns = ClasspathEntry.EXCLUDE_NONE;
}
// access rules (optional)
NodeList attributeList = getChildAttributes(ClasspathEntry.TAG_ACCESS_RULES, children, foundChildren);
IAccessRule[] accessRules = decodeAccessRules(attributeList);
// backward compatibility
if (accessRules == null) {
accessRules = getAccessRules(inclusionPatterns, exclusionPatterns);
}
// combine access rules (optional)
final boolean combineAccessRestrictions = !removeAttribute(ClasspathEntry.TAG_COMBINE_ACCESS_RULES, attributes).equals("false"); //$NON-NLS-1$
// extra attributes (optional)
attributeList = getChildAttributes(ClasspathEntry.TAG_ATTRIBUTES, children, foundChildren);
final IClasspathAttribute[] extraAttributes = decodeExtraAttributes(attributeList);
// custom output location
final IPath outputLocation = element.hasAttribute(ClasspathEntry.TAG_OUTPUT)
? projectPath.append(removeAttribute(ClasspathEntry.TAG_OUTPUT, attributes)) : null;
String[] unknownAttributes = null;
ArrayList<String> unknownChildren = null;
if (unknownElements != null) {
// unknown attributes
final int unknownAttributeLength = attributes.getLength();
if (unknownAttributeLength != 0) {
unknownAttributes = new String[unknownAttributeLength * 2];
for (int i = 0; i < unknownAttributeLength; i++) {
final Node attribute = attributes.item(i);
unknownAttributes[i * 2] = attribute.getNodeName();
unknownAttributes[i * 2 + 1] = attribute.getNodeValue();
}
}
// unknown children
for (int i = 0, length = foundChildren.length; i < length; i++) {
if (!foundChildren[i]) {
final Node node = children.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (unknownChildren == null) {
unknownChildren = new ArrayList<>();
}
final StringBuffer buffer = new StringBuffer();
decodeUnknownNode(node, buffer);
unknownChildren.add(buffer.toString());
}
}
}
// recreate the CP entry
IClasspathEntry entry = null;
switch (kind) {
case IClasspathEntry.CPE_PROJECT:
/*
* IPackageFragmentRoot.K_SOURCE, IClasspathEntry.CPE_PROJECT, path, ClasspathEntry.INCLUDE_ALL, // inclusion patterns
* ClasspathEntry.EXCLUDE_NONE, // exclusion patterns null, // source attachment null, // source attachment root null, // specific output
* folder
*/
entry = new ClasspathEntry(IPackageFragmentRoot.K_SOURCE, IClasspathEntry.CPE_PROJECT, path, ClasspathEntry.INCLUDE_ALL,
ClasspathEntry.EXCLUDE_NONE, null, null, null, isExported, accessRules, combineAccessRestrictions, extraAttributes);
break;
case IClasspathEntry.CPE_LIBRARY:
entry = JavaCore.newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, accessRules, extraAttributes, isExported);
break;
case IClasspathEntry.CPE_SOURCE:
// must be an entry in this project or specify another project
final String projSegment = path.segment(0);
if (projSegment != null && projSegment.equals(projectName)) {
// this project
entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
} else {
if (path.segmentCount() == 1) {
// another project
entry = JavaCore.newProjectEntry(path, accessRules, combineAccessRestrictions, extraAttributes, isExported);
} else {
// an invalid source folder
entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
}
}
break;
case IClasspathEntry.CPE_VARIABLE:
entry = JavaCore.newVariableEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, accessRules, extraAttributes, isExported);
break;
case IClasspathEntry.CPE_CONTAINER:
entry = JavaCore.newContainerEntry(path, accessRules, extraAttributes, isExported);
break;
case ClasspathEntry.K_OUTPUT:
if (!path.isAbsolute()) {
return null;
}
/*
* ClasspathEntry.EXCLUDE_NONE, null, // source attachment null, // source attachment root null, // custom output location false, null, //
* no access rules false, // no accessible files to combine
*/
entry = new ClasspathEntry(ClasspathEntry.K_OUTPUT, IClasspathEntry.CPE_LIBRARY, path, ClasspathEntry.INCLUDE_ALL,
ClasspathEntry.EXCLUDE_NONE, null, null, null, false, null, false, ClasspathEntry.NO_EXTRA_ATTRIBUTES);
break;
default:
throw new AssertionFailedException(Messages.bind(Messages.classpath_unknownKind, kindAttr));
}
if (unknownAttributes != null || unknownChildren != null) {
final UnknownXmlElements unknownXmlElements = new UnknownXmlElements();
unknownXmlElements.attributes = unknownAttributes;
unknownXmlElements.children = unknownChildren;
if (unknownElements != null) {
unknownElements.put(path, unknownXmlElements);
}
}
return entry;
}
private static NodeList getChildAttributes(String childName, NodeList children, boolean[] foundChildren) {
for (int i = 0, length = foundChildren.length; i < length; i++) {
final Node node = children.item(i);
if (childName.equals(node.getNodeName())) {
foundChildren[i] = true;
return node.getChildNodes();
}
}
return null;
}
private static String removeAttribute(String nodeName, NamedNodeMap nodeMap) {
final Node node = removeNode(nodeName, nodeMap);
if (node == null) {
return ""; // //$NON-NLS-1$
}
return node.getNodeValue();
}
private static Node removeNode(String nodeName, NamedNodeMap nodeMap) {
try {
return nodeMap.removeNamedItem(nodeName);
} catch (DOMException e) {
if (e.code != DOMException.NOT_FOUND_ERR) {
throw e;
}
return null;
}
}
/**
* Decode some element tag containing a sequence of patterns into IPath[].
*
* @param nodeMap
* - map
* @param tag
* - tag
* @return aarray of IPATH
*/
@SuppressWarnings("checkstyle:innerassignment")
private static IPath[] decodePatterns(NamedNodeMap nodeMap, String tag) {
final String sequence = removeAttribute(tag, nodeMap);
if (!"".equals(sequence)) { //$NON-NLS-1$
final char[][] patterns = CharOperation.splitOn('|', sequence.toCharArray());
final int patternCount;
if ((patternCount = patterns.length) > 0) {
IPath[] paths = new IPath[patternCount];
int index = 0;
for (int j = 0; j < patternCount; j++) {
final char[] pattern = patterns[j];
if (pattern.length == 0) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=105581
continue;
}
paths[index++] = new Path(new String(pattern));
}
if (index < patternCount) {
System.arraycopy(paths, 0, paths = new IPath[index], 0, index);
}
return paths;
}
}
return null;
}
@SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:innerassignment" })
private static IAccessRule[] decodeAccessRules(NodeList list) {
if (list == null) {
return null;
}
final int length = list.getLength();
if (length == 0) {
return null;
}
IAccessRule[] result = new IAccessRule[length];
int index = 0;
for (int i = 0; i < length; i++) {
final Node accessRule = list.item(i);
if (accessRule.getNodeType() == Node.ELEMENT_NODE) {
final Element elementAccessRule = (Element) accessRule;
final String pattern = elementAccessRule.getAttribute(ClasspathEntry.TAG_PATTERN);
if (pattern == null) {
continue;
}
final String tagKind = elementAccessRule.getAttribute(ClasspathEntry.TAG_KIND);
final int kind;
if (ClasspathEntry.TAG_ACCESSIBLE.equals(tagKind)) {
kind = IAccessRule.K_ACCESSIBLE;
} else if (ClasspathEntry.TAG_NON_ACCESSIBLE.equals(tagKind)) {
kind = IAccessRule.K_NON_ACCESSIBLE;
} else if (ClasspathEntry.TAG_DISCOURAGED.equals(tagKind)) {
kind = IAccessRule.K_DISCOURAGED;
} else {
continue;
}
final boolean ignoreIfBetter = "true".equals(elementAccessRule.getAttribute(ClasspathEntry.TAG_IGNORE_IF_BETTER)); //$NON-NLS-1$
result[index++] = new ClasspathAccessRule(new Path(pattern), ignoreIfBetter ? kind | IAccessRule.IGNORE_IF_BETTER : kind);
}
}
if (index != length) {
System.arraycopy(result, 0, result = new IAccessRule[index], 0, index);
}
return result;
}
@SuppressWarnings("checkstyle:innerassignment")
private static IClasspathAttribute[] decodeExtraAttributes(NodeList attributes) {
if (attributes == null) {
return ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
final int length = attributes.getLength();
if (length == 0) {
return ClasspathEntry.NO_EXTRA_ATTRIBUTES;
}
IClasspathAttribute[] result = new IClasspathAttribute[length];
int index = 0;
for (int i = 0; i < length; ++i) {
final Node node = attributes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
final Element attribute = (Element) node;
final String name = attribute.getAttribute(ClasspathEntry.TAG_ATTRIBUTE_NAME);
if (name == null) {
continue;
}
final String value = attribute.getAttribute(ClasspathEntry.TAG_ATTRIBUTE_VALUE);
if (value == null) {
continue;
}
result[index++] = new ClasspathAttribute(name, value);
}
}
if (index != length) {
System.arraycopy(result, 0, result = new IClasspathAttribute[index], 0, index);
}
return result;
}
private static void decodeUnknownNode(Node node, StringBuffer buffer) {
final ByteArrayOutputStream s = new ByteArrayOutputStream();
final OutputStreamWriter writer;
try {
writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
try (GenericXMLWriter xmlWriter = new GenericXMLWriter(writer, System.getProperty("line.separator"), //$NON-NLS-1$
false/* don't print XML version */)) {
decodeUnknownNode(node, xmlWriter, true/* insert new line */);
xmlWriter.flush();
}
buffer.append(s.toString("UTF8")); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
// ignore (UTF8 is always supported)
}
}
@SuppressWarnings({"checkstyle:innerassignment", "checkstyle:illegaltype"})
private static void decodeUnknownNode(Node node, GenericXMLWriter xmlWriter, boolean insertNewLine) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE:
final NamedNodeMap attributes;
HashMap<String, String> parameters = null;
if ((attributes = node.getAttributes()) != null) {
final int length = attributes.getLength();
if (length > 0) {
parameters = new HashMap<>();
for (int i = 0; i < length; i++) {
final Node attribute = attributes.item(i);
parameters.put(attribute.getNodeName(), attribute.getNodeValue());
}
}
}
final NodeList children = node.getChildNodes();
final int childrenLength = children.getLength();
final String nodeName = node.getNodeName();
xmlWriter.printTag(nodeName, parameters, false/* don't insert tab */, false/* don't insert new line */,
childrenLength == 0/* close tag if no children */);
if (childrenLength > 0) {
for (int i = 0; i < childrenLength; i++) {
decodeUnknownNode(children.item(i), xmlWriter, false/* don't insert new line */);
}
xmlWriter.endTag(nodeName, false/* don't insert tab */, insertNewLine);
}
break;
case Node.TEXT_NODE:
final String data = ((Text) node).getData();
xmlWriter.printString(data, false/* don't insert tab */, false/* don't insert new line */);
break;
default:
break;
}
}
/**
* Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
*
* @param kindStr
* - string to test
* @return the integer identifier of the type of the specified string: CPE_PROJECT, CPE_VARIABLE, CPE_CONTAINER, etc.
*/
@SuppressWarnings("checkstyle:equalsavoidnull")
private static int kindFromString(String kindStr) {
if (kindStr.equalsIgnoreCase("prj")) { //$NON-NLS-1$
return IClasspathEntry.CPE_PROJECT;
}
if (kindStr.equalsIgnoreCase("var")) { //$NON-NLS-1$
return IClasspathEntry.CPE_VARIABLE;
}
if (kindStr.equalsIgnoreCase("con")) { //$NON-NLS-1$
return IClasspathEntry.CPE_CONTAINER;
}
if (kindStr.equalsIgnoreCase("src")) { //$NON-NLS-1$
return IClasspathEntry.CPE_SOURCE;
}
if (kindStr.equalsIgnoreCase("lib")) { //$NON-NLS-1$
return IClasspathEntry.CPE_LIBRARY;
}
if (kindStr.equalsIgnoreCase("output")) { //$NON-NLS-1$
return ClasspathEntry.K_OUTPUT;
}
return -1;
}
/*
* Backward compatibility: only accessible and non-accessible files are suported.
*/
private static IAccessRule[] getAccessRules(IPath[] accessibleFiles, IPath[] nonAccessibleFiles) {
final int accessibleFilesLength = accessibleFiles == null ? 0 : accessibleFiles.length;
final int nonAccessibleFilesLength = nonAccessibleFiles == null ? 0 : nonAccessibleFiles.length;
final int length = accessibleFilesLength + nonAccessibleFilesLength;
if (length == 0) {
return null;
}
final IAccessRule[] accessRules = new IAccessRule[length];
if (accessibleFiles != null) {
for (int i = 0; i < accessibleFilesLength; i++) {
accessRules[i] = JavaCore.newAccessRule(accessibleFiles[i], IAccessRule.K_ACCESSIBLE);
}
}
if (nonAccessibleFiles != null) {
for (int i = 0; i < nonAccessibleFilesLength; i++) {
accessRules[accessibleFilesLength + i] = JavaCore.newAccessRule(nonAccessibleFiles[i], IAccessRule.K_NON_ACCESSIBLE);
}
}
return accessRules;
}
}