All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.infoflow.methodSummary.xml.SummaryReader Maven / Gradle / Ivy

package soot.jimple.infoflow.methodSummary.xml;

import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_BASETYPE;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_FLOWTYPE;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_MATCH_STRICT;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_PARAMETER_INDEX;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_PREVENT_PROPAGATION;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.ATTRIBUTE_TAINT_SUB_FIELDS;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.TREE_CLEAR;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.TREE_FLOW;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.TREE_METHOD;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.TREE_SINK;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.TREE_SOURCE;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.VALUE_FALSE;
import static soot.jimple.infoflow.methodSummary.xml.XMLConstants.VALUE_TRUE;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import soot.jimple.infoflow.collections.data.IndexConstraint;
import soot.jimple.infoflow.collections.data.KeyConstraint;
import soot.jimple.infoflow.methodSummary.data.sourceSink.ConstraintType;
import soot.jimple.infoflow.methodSummary.data.sourceSink.FlowClear;
import soot.jimple.infoflow.methodSummary.data.sourceSink.FlowConstraint;
import soot.jimple.infoflow.methodSummary.data.sourceSink.FlowSink;
import soot.jimple.infoflow.methodSummary.data.sourceSink.FlowSource;
import soot.jimple.infoflow.methodSummary.data.summary.ClassMethodSummaries;
import soot.jimple.infoflow.methodSummary.data.summary.GapDefinition;
import soot.jimple.infoflow.methodSummary.data.summary.ImplicitLocation;
import soot.jimple.infoflow.methodSummary.data.summary.IsAliasType;
import soot.jimple.infoflow.methodSummary.data.summary.MethodClear;
import soot.jimple.infoflow.methodSummary.data.summary.MethodFlow;
import soot.jimple.infoflow.methodSummary.data.summary.MethodSummaries;
import soot.jimple.infoflow.methodSummary.data.summary.SourceSinkType;
import soot.jimple.infoflow.methodSummary.taintWrappers.AccessPathFragment;

public class SummaryReader extends AbstractXMLReader {

	// XML stuff incl. Verification against XSD
	private static final String XSD_FILE_PATH = "schema/ClassSummaryC.xsd";

	private boolean validateSummariesOnRead = false;

	private enum State {
		summary, hierarchy, intf, methods, method, flow, clear, gaps, gap, constraints, key, index
	}

	/**
	 * Reads a summary xml and places the new summaries into the given data object.
	 * This method closes the reader.
	 *
	 * @param reader    The reader from which to read the method summaries
	 * @param summaries The data object in which to place the summaries
	 * @throws XMLStreamException Thrown in case of a syntax error in the input file
	 * @throws IOException        Thrown if the reader could not be read
	 */
	public void read(Reader reader, ClassMethodSummaries summaries)
			throws XMLStreamException, SummaryXMLException, IOException {
		XMLStreamReader xmlreader = null;
		try {
			XMLInputFactory factory = XMLInputFactory.newInstance();
			factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
			factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
			xmlreader = factory.createXMLStreamReader(reader);
			final MethodSummaries summary = summaries.getMethodSummaries();

			Map sourceAttributes = new HashMap();
			Map sinkAttributes = new HashMap();
			Map clearAttributes = new HashMap();
			Map constraintAttributes = new HashMap<>();
			List constraints = new ArrayList<>();

			String currentMethod = "";
			int currentID = -1;
			IsAliasType isAlias = IsAliasType.FALSE;
			Boolean typeChecking = null;
			Boolean ignoreTypes = null;
			Boolean cutSubfields = null;
			boolean isFinal = false;
			boolean excludedOnClear = false;

			State state = State.summary;
			while (xmlreader.hasNext()) {
				// Read the next tag
				xmlreader.next();
				if (!xmlreader.hasName())
					continue;

				final String localName = xmlreader.getLocalName();
				if (localName.equals(XMLConstants.TREE_SUMMARY) && xmlreader.isStartElement()) {
					String isInterface = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_IS_INTERFACE);

					// If the string is empty, it's unknown, and neither true nor false, so we must
					// not call setInterface()!
					if (isInterface != null && !isInterface.isEmpty())
						summaries.setInterface(isInterface.equals(XMLConstants.VALUE_TRUE));

					String isExclusive = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_IS_EXCLUSIVE);
					if (isExclusive != null && !isExclusive.isEmpty())
						summaries.setExclusiveForClass(isExclusive.equals(XMLConstants.VALUE_TRUE));
				} else if (localName.equals(XMLConstants.TREE_METHODS) && xmlreader.isStartElement()) {
					if (state == State.summary)
						state = State.methods;
					else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_METHOD) && xmlreader.isStartElement()) {
					if (state == State.methods) {
						currentMethod = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_METHOD_SIG);

						// Some summaries are full signatures instead of subsignatures. We fix this on
						// the fly.
						if (currentMethod.contains(":"))
							currentMethod = currentMethod.substring(currentMethod.indexOf(":") + 1).trim();

						String sIsExcluded = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_IS_EXCLUDED);
						if (sIsExcluded != null && sIsExcluded.equals(XMLConstants.VALUE_TRUE))
							summary.addExcludedMethod(currentMethod);
						state = State.method;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_METHOD) && xmlreader.isEndElement()) {
					if (state == State.method) {
						state = State.methods;
						constraints.clear();
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_FLOW) && xmlreader.isStartElement()) {
					if (state == State.method) {
						sourceAttributes.clear();
						sinkAttributes.clear();
						state = State.flow;
						String sAlias = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_IS_ALIAS);
						isAlias = parseIsAlias(sAlias);

						String sTypeChecking = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_TYPE_CHECKING);
						if (sTypeChecking != null && !sTypeChecking.isEmpty())
							typeChecking = sTypeChecking.equals(XMLConstants.VALUE_TRUE);

						String sCutSubfields = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_CUT_SUBFIELDS);
						if (sCutSubfields != null && !sCutSubfields.isEmpty())
							cutSubfields = sCutSubfields.equals(XMLConstants.VALUE_TRUE);

						String sIgnoreTypes = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_IGNORE_TYPES);
						if (sIgnoreTypes != null && !sIgnoreTypes.isEmpty())
							ignoreTypes = sIgnoreTypes.equals(XMLConstants.VALUE_TRUE);

						String sIsFinal = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_FINAL);
						if (sIsFinal != null && !sIsFinal.isEmpty())
							isFinal = sIsFinal.equals(VALUE_TRUE);

						String sExcludedOnClear = getAttributeByName(xmlreader, XMLConstants.EXCLUDED_ON_CLEAR);
						if (sExcludedOnClear != null && !sExcludedOnClear.isEmpty())
							excludedOnClear = sExcludedOnClear.equals(VALUE_TRUE);
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_CLEAR) && xmlreader.isStartElement()) {
					if (state == State.method) {
						clearAttributes.clear();
						for (int i = 0; i < xmlreader.getAttributeCount(); i++)
							clearAttributes.put(xmlreader.getAttributeLocalName(i), xmlreader.getAttributeValue(i));
						state = State.clear;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_SOURCE) && xmlreader.isStartElement()) {
					if (state == State.flow) {
						for (int i = 0; i < xmlreader.getAttributeCount(); i++)
							sourceAttributes.put(xmlreader.getAttributeLocalName(i), xmlreader.getAttributeValue(i));
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_SINK) && xmlreader.isStartElement()) {
					if (state == State.flow) {
						if (xmlreader.getAttributeCount() == 0)
							throw new RuntimeException();
						for (int i = 0; i < xmlreader.getAttributeCount(); i++)
							sinkAttributes.put(xmlreader.getAttributeLocalName(i), xmlreader.getAttributeValue(i));
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_FLOW) && xmlreader.isEndElement()) {
					if (state == State.flow) {
						state = State.method;
						MethodFlow flow = new MethodFlow(currentMethod, createSource(summary, sourceAttributes),
								createSink(summary, sinkAttributes), isAlias, typeChecking, ignoreTypes, cutSubfields,
								constraints.toArray(new FlowConstraint[0]), isFinal, excludedOnClear);
						summary.addFlow(flow);

						isAlias = IsAliasType.FALSE;
						isFinal = false;
						excludedOnClear = false;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(TREE_CLEAR) && xmlreader.isEndElement()) {
					if (state == State.clear) {
						state = State.method;

						String sAlias = clearAttributes.get(XMLConstants.ATTRIBUTE_IS_ALIAS);
						IsAliasType alias = parseIsAlias(sAlias);

						String ppString = clearAttributes.get(ATTRIBUTE_PREVENT_PROPAGATION);
						boolean preventProp = ppString == null || ppString.isEmpty() || ppString.equals(VALUE_TRUE);
						MethodClear clear = new MethodClear(currentMethod, createClear(summary, clearAttributes),
								constraints.toArray(new FlowConstraint[0]), alias, preventProp);
						summary.addClear(clear);
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_METHODS) && xmlreader.isEndElement()) {
					if (state == State.methods)
						state = State.summary;
					else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_GAPS) && xmlreader.isStartElement()) {
					if (state == State.summary)
						state = State.gaps;
					else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_GAPS) && xmlreader.isEndElement()) {
					if (state == State.gaps)
						state = State.summary;
					else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_GAP) && xmlreader.isStartElement()) {
					if (state == State.gaps) {
						currentMethod = getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_METHOD_SIG);
						currentID = Integer.valueOf(getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_ID));
						summary.getOrCreateGap(currentID, currentMethod);
						state = State.gap;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_GAP) && xmlreader.isEndElement()) {
					if (state == State.gap) {
						state = State.gaps;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_HIERARCHY) && xmlreader.isStartElement()) {
					if (state == State.summary) {
						summaries.setSuperClass(getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_SUPERCLASS));
						state = State.hierarchy;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_HIERARCHY) && xmlreader.isEndElement()) {
					if (state == State.hierarchy) {
						state = State.summary;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_INTERFACE) && xmlreader.isStartElement()) {
					if (state == State.hierarchy) {
						summaries.addInterface(getAttributeByName(xmlreader, XMLConstants.ATTRIBUTE_NAME));
						state = State.intf;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_INTERFACE) && xmlreader.isEndElement()) {
					if (state == State.intf) {
						state = State.hierarchy;
					} else
						throw new SummaryXMLException();
				} else if (localName.equals(XMLConstants.TREE_CONSTRAINTS) && xmlreader.isStartElement()) {
					if (state != State.method)
						throw new SummaryXMLException();
					state = State.constraints;
				} else if (localName.equals(XMLConstants.TREE_CONSTRAINTS) && xmlreader.isEndElement()) {
					if (state != State.constraints)
						throw new SummaryXMLException();
					state = State.method;
				} else if (localName.equals(XMLConstants.TREE_KEY) && xmlreader.isStartElement()) {
					if (state != State.constraints)
						throw new SummaryXMLException();
					state = State.key;
					for (int i = 0; i < xmlreader.getAttributeCount(); i++)
						constraintAttributes.put(xmlreader.getAttributeLocalName(i), xmlreader.getAttributeValue(i));
				} else if (localName.equals(XMLConstants.TREE_KEY) && xmlreader.isEndElement()) {
					if (state != State.key)
						throw new SummaryXMLException();
					state = State.constraints;
					constraints.add(createKeyConstraint(constraintAttributes));
					constraintAttributes.clear();
				} else if (localName.equals(XMLConstants.TREE_INDEX) && xmlreader.isStartElement()) {
					if (state != State.constraints)
						throw new SummaryXMLException();
					state = State.index;
					for (int i = 0; i < xmlreader.getAttributeCount(); i++)
						constraintAttributes.put(xmlreader.getAttributeLocalName(i), xmlreader.getAttributeValue(i));
				} else if (localName.equals(XMLConstants.TREE_INDEX) && xmlreader.isEndElement()) {
					if (state != State.index)
						throw new SummaryXMLException();
					state = State.constraints;
					constraints.add(createIndexConstraint(constraintAttributes));
					constraintAttributes.clear();
				}
			}

			// Validate the summary to make sure that we didn't read in any
			// bogus stuff
			if (validateSummariesOnRead)
				summary.validate();
		} finally {
			if (xmlreader != null)
				xmlreader.close();
		}
	}

	private IsAliasType parseIsAlias(String sAlias) throws SummaryXMLException {
		if (sAlias == null)
			return IsAliasType.FALSE;

		switch (sAlias) {
		case XMLConstants.VALUE_TRUE:
			return IsAliasType.TRUE;
		case "":
		case XMLConstants.VALUE_FALSE:
			return IsAliasType.FALSE;
		case "withContext":
			return IsAliasType.WITH_CONTEXT;
		default:
			throw new SummaryXMLException("Unknown isAlias value: " + sAlias);
		}
	}

	/**
	 * Reads a summary xml file and merges the summaries that are saved in that file
	 * into the given data object
	 *
	 * @param fileName  The file from which to read the method summaries
	 * @param summaries The data object in which to place the summaries
	 * @throws XMLStreamException Thrown in case of a syntax error in the input file
	 * @throws IOException        Thrown if the file could not be read
	 */
	public void read(File fileName, ClassMethodSummaries summaries)
			throws XMLStreamException, SummaryXMLException, IOException {
		if (validateSummariesOnRead) {
			try (FileReader rdr = new FileReader(fileName)) {
				if (!verifyXML(rdr, XSD_FILE_PATH)) {
					throw new RuntimeException("The XML-File isn't valid");
				}
			}
		}

		read(new FileReader(fileName), summaries);
	}

	/**
	 * Creates a new source data object from the given XML attributes
	 *
	 * @param summary    The method summary for which to create the new flow source
	 * @param attributes The XML attributes for the source
	 * @return The newly created source data object
	 * @throws SummaryXMLException
	 */
	private FlowSource createSource(MethodSummaries summary, Map attributes)
			throws SummaryXMLException {
		if (isField(attributes)) {
			return new FlowSource(SourceSinkType.Field, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getGapDefinition(attributes, summary), isMatchStrict(attributes), isConstrained(attributes));
		} else if (isParameter(attributes)) {
			return new FlowSource(SourceSinkType.Parameter, parameterIdx(attributes), getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getGapDefinition(attributes, summary), isMatchStrict(attributes), isConstrained(attributes));
		} else if (isGapBaseObject(attributes)) {
			return new FlowSource(SourceSinkType.GapBaseObject, getBaseType(attributes),
					getGapDefinition(attributes, summary), isMatchStrict(attributes), isConstrained(attributes));
		} else if (isReturn(attributes)) {
			GapDefinition gap = getGapDefinition(attributes, summary);
			if (gap == null)
				throw new SummaryXMLException(
						"Return values can only be " + "sources if they have a gap specification");

			return new FlowSource(SourceSinkType.Return, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getGapDefinition(attributes, summary), isMatchStrict(attributes), isConstrained(attributes));
		}
		throw new SummaryXMLException("Invalid flow source definition");
	}

	/**
	 * Creates a new sink data object from the given XML attributes
	 *
	 * @param summary    The method summary for which to create the new flow source
	 * @param attributes The XML attributes for the sink
	 * @return The newly created sink data object
	 * @throws SummaryXMLException
	 */
	private FlowSink createSink(MethodSummaries summary, Map attributes) throws SummaryXMLException {
		if (isField(attributes)) {
			return new FlowSink(SourceSinkType.Field, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					taintSubFields(attributes), getGapDefinition(attributes, summary), isMatchStrict(attributes),
					isConstrained(attributes));
		} else if (isParameter(attributes)) {
			return new FlowSink(SourceSinkType.Parameter, parameterIdx(attributes), getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					taintSubFields(attributes), getGapDefinition(attributes, summary), isMatchStrict(attributes),
					isConstrained(attributes));
		} else if (isReturn(attributes)) {
			return new FlowSink(SourceSinkType.Return, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					taintSubFields(attributes), getGapDefinition(attributes, summary), isMatchStrict(attributes),
					isConstrained(attributes));
		} else if (isGapBaseObject(attributes)) {
			return new FlowSink(SourceSinkType.GapBaseObject, -1, getBaseType(attributes), false,
					getGapDefinition(attributes, summary), isMatchStrict(attributes), isConstrained(attributes));
		}
		throw new SummaryXMLException();
	}

	/**
	 * Creates a new taint kill data object from the given XML attributes
	 *
	 * @param summary    The method summary for which to create the new flow source
	 * @param attributes The XML attributes for the source
	 * @return The newly created source data object
	 * @throws SummaryXMLException
	 */
	private FlowClear createClear(MethodSummaries summary, Map attributes) throws SummaryXMLException {
		if (isField(attributes)) {
			return new FlowClear(SourceSinkType.Field, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getGapDefinition(attributes, summary), isConstrained(attributes));
		} else if (isParameter(attributes)) {
			return new FlowClear(SourceSinkType.Parameter, parameterIdx(attributes), getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getGapDefinition(attributes, summary), isConstrained(attributes));
		} else if (isGapBaseObject(attributes)) {
			return new FlowClear(SourceSinkType.GapBaseObject, getBaseType(attributes),
					getGapDefinition(attributes, summary), isConstrained(attributes));
		}
		throw new SummaryXMLException("Invalid flow clear definition");
	}

	private FlowConstraint createKeyConstraint(Map attributes) throws SummaryXMLException {
		if (isParameter(attributes))
			return new KeyConstraint(SourceSinkType.Parameter, parameterIdx(attributes), getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)));
		if (isAny(attributes))
			return new KeyConstraint(SourceSinkType.Any, -1, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)));
		throw new SummaryXMLException();
	}

	private FlowConstraint createIndexConstraint(Map attributes) throws SummaryXMLException {
		if (isParameter(attributes))
			return new IndexConstraint(SourceSinkType.Parameter, parameterIdx(attributes), getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)), null);
		if (isImplicit(attributes))
			return new IndexConstraint(SourceSinkType.Implicit, -1, getBaseType(attributes),
					new AccessPathFragment(getAccessPath(attributes), getAccessPathTypes(attributes)),
					getImplicitLocation(attributes));
		throw new SummaryXMLException();
	}

	private ImplicitLocation getImplicitLocation(Map attributes) {
		String implLoc = attributes.get(XMLConstants.ATTRIBUTE_IMPL_LOC);
		switch (implLoc.toLowerCase()) {
		case "first":
			return ImplicitLocation.First;
		case "last":
			return ImplicitLocation.Last;
		case "next":
			return ImplicitLocation.Next;
		default:
			throw new RuntimeException("Missing case!");
		}
	}

	private boolean isReturn(Map attributes) {
		if (attributes != null) {
			String attr = attributes.get(ATTRIBUTE_FLOWTYPE);
			return attr != null && attr.equals(SourceSinkType.Return.toString());
		}
		return false;
	}

	private boolean isField(Map attributes) {
		if (attributes != null) {
			String attr = attributes.get(ATTRIBUTE_FLOWTYPE);
			return attr != null && attr.equals(SourceSinkType.Field.toString());
		}
		return false;
	}

	private boolean isImplicit(Map attributes) {
		if (attributes != null) {
			String attr = attributes.get(ATTRIBUTE_FLOWTYPE);
			return attr != null && attr.equals(SourceSinkType.Implicit.toString());
		}
		return false;
	}

	private ConstraintType isConstrained(Map attributes) {
		if (attributes != null) {
			String attr = attributes.get(XMLConstants.ATTRIBUTE_CONSTRAINED);
			if (attr == null)
				return ConstraintType.FALSE;
			switch (attr.toLowerCase()) {
			case VALUE_TRUE:
				return ConstraintType.TRUE;
			case VALUE_FALSE:
				return ConstraintType.FALSE;
			case XMLConstants.CONSTRAINT_KEEP:
				return ConstraintType.KEEP;
			case XMLConstants.CONSTRAINT_RO:
				return ConstraintType.READONLY;
			case "shiftright":
				return ConstraintType.SHIFT_RIGHT;
			case "shiftleft":
				return ConstraintType.SHIFT_LEFT;
			case "nomatch":
				return ConstraintType.NO_MATCH;
			case "append":
				return ConstraintType.APPEND;
			default:
				throw new RuntimeException("Unknown constraint type: " + attr);
			}
		}
		return ConstraintType.FALSE;
	}

	private String[] getAccessPath(Map attributes) {
		String ap = attributes.get(XMLConstants.ATTRIBUTE_ACCESSPATH);
		if (ap != null) {
			if (ap.length() > 3) {
				String[] res = ap.substring(1, ap.length() - 1).split(",");
				for (int i = 0; i < res.length; i++) {
					String curElement = res[i].trim();

					// We don't require the XML file to contain Soot's signature
					// brackets
					if (!curElement.startsWith("<"))
						curElement = "<" + curElement;
					if (!curElement.endsWith(">"))
						curElement = curElement + ">";

					res[i] = curElement;
				}
				return res;
			}
		}
		return null;
	}

	private String[] getAccessPathTypes(Map attributes) {
		String ap = attributes.get(XMLConstants.ATTRIBUTE_ACCESSPATHTYPES);
		if (ap != null) {
			if (ap.length() > 3) {
				String[] res = ap.substring(1, ap.length() - 1).split(",");
				for (int i = 0; i < res.length; i++)
					res[i] = res[i].trim();
				return res;
			}
		}
		return null;
	}

	private boolean isMatchStrict(Map attributes) {
		String str = attributes.get(ATTRIBUTE_MATCH_STRICT);
		if (str != null && !str.isEmpty())
			return Boolean.valueOf(str);
		return false;
	}

	private boolean isParameter(Map attributes) {
		return attributes.get(ATTRIBUTE_FLOWTYPE).equals(SourceSinkType.Parameter.toString());
	}

	private boolean isAny(Map attributes) {
		return attributes.get(ATTRIBUTE_FLOWTYPE).equals(SourceSinkType.Any.toString());
	}

	private boolean isGapBaseObject(Map attributes) {
		return attributes != null && attributes.get(ATTRIBUTE_FLOWTYPE).equals(SourceSinkType.GapBaseObject.toString());
	}

	private int parameterIdx(Map attributes) {
		String strIdx = attributes.get(ATTRIBUTE_PARAMETER_INDEX);
		if (strIdx == null || strIdx.isEmpty())
			throw new RuntimeException("Parameter index not specified");
		if (strIdx.equals("*"))
			return FlowSource.ANY_PARAMETER;
		return Integer.parseInt(strIdx);
	}

	private String getBaseType(Map attributes) {
		return attributes.get(ATTRIBUTE_BASETYPE);
	}

	private boolean taintSubFields(Map attributes) {
		String val = attributes.get(ATTRIBUTE_TAINT_SUB_FIELDS);
		return val != null && val.equals(VALUE_TRUE);
	}

	private GapDefinition getGapDefinition(Map attributes, MethodSummaries summary) {
		String id = attributes.get(XMLConstants.ATTRIBUTE_GAP);
		if (id == null || id.isEmpty())
			return null;

		// Do we already have a suitable gap definition?
		GapDefinition gap = summary.getGap(Integer.parseInt(id));
		if (gap != null)
			return gap;

		// We have not read in this gap definition yet and need to create a stub
		// for the time being.
		return summary.createTemporaryGap(Integer.parseInt(id));
	}

	/**
	 * Sets whether summaries shall be validated after they are read from disk
	 *
	 * @param validateSummariesOnRead True if summaries shall be validated after
	 *                                they are read from disk, otherwise false
	 */
	public void setValidateSummariesOnRead(boolean validateSummariesOnRead) {
		this.validateSummariesOnRead = validateSummariesOnRead;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy