package com.coverity.ps.sac.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.xpath.XPathExpression;
import org.xml.sax.SAXException;
import com.coverity.ps.sac.parser.Parser;
/**
* Parses an SA input specification and creates the a C# output intermediate
* directory.
*
* @author rhollines
*/
public class InputParser {
private final static String CONFIGURATION_FILE = "defect-spec.xml";
private List<CoveritySaFormatter.Defect> defects = new ArrayList<CoveritySaFormatter.Defect>();
private String filename;
private int functionCount = 0;
private int lineCount = 0;
public static void main(String[] args) {
new InputParser(args[0]);
}
/**
* Default constructor
*
* @param filename
* file to parse
*/
public InputParser(String filename) {
this.filename = filename;
}
private InputConfiguration loadConfigurationFile() throws SAXException,
IOException, ParserConfigurationException {
System.out.println("Parsing configuration file...");
DocumentBuilderFactory documentFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder documentBuilder = documentFactory.newDocumentBuilder();
Document document = documentBuilder.parse(CONFIGURATION_FILE);
// get parser tag
NodeList parserNode = document.getDocumentElement()
.getElementsByTagName("parser");
if (parserNode.getLength() != 1) {
System.err.println("Invalid or missing parser configuration tag!");
}
final String parserClassName = ((Element) parserNode.item(0))
.getAttribute("class");
if (parserClassName.length() == 0) {
System.err.println("Invalid or missing parser configuration tag!");
System.exit(1);
}
// get file tag
NodeList fileNode = document.getDocumentElement().getElementsByTagName(
"file-tag");
if (fileNode.getLength() != 1) {
System.err.println("Invalid or missing file configuration tag!");
System.exit(1);
}
Element fileElem = (Element) fileNode.item(0);
final String fileElemName = fileElem.getAttribute("path");
final String fileAttribName = fileElem.getAttribute("attrib");
if (fileElemName.length() == 0 || fileAttribName.length() == 0) {
System.err.println("Invalid or missing file configuration tag!");
System.exit(1);
}
// get defect tag
NodeList defectNode = fileElem.getElementsByTagName("defect-tag");
if (defectNode.getLength() != 1) {
System.err.println("Invalid or missing defect configuration tag!");
System.exit(1);
}
final String defectElemName = ((Element) defectNode.item(0))
.getAttribute("path");
if (defectElemName.length() == 0) {
System.err.println("Invalid or missing defect configuration tag!");
System.exit(1);
}
// get checker tag
NodeList checkerNode = fileElem.getElementsByTagName("checker-tag");
if (checkerNode.getLength() != 1) {
System.err.println("Invalid or missing checker configuration tag!");
System.exit(1);
}
final String checkerElemName = ((Element) checkerNode.item(0))
.getAttribute("path");
final String checkerAttribName = ((Element) checkerNode.item(0))
.getAttribute("attrib");
if (checkerElemName.length() == 0 || checkerAttribName.length() == 0) {
System.err.println("Invalid or missing checker configuration tag!");
System.exit(1);
}
// get event tag
NodeList eventNode = fileElem.getElementsByTagName("event-tag");
if (eventNode.getLength() != 1) {
System.err.println("Invalid or missing event configuration tag!");
System.exit(1);
}
final String eventElemName = ((Element) eventNode.item(0))
.getAttribute("path");
final String eventAttribName = ((Element) eventNode.item(0))
.getAttribute("attrib");
if (eventElemName.length() == 0 || eventAttribName.length() == 0) {
System.err.println("Invalid or missing event configuration tag!");
System.exit(1);
}
// get line tag
NodeList lineNode = fileElem.getElementsByTagName("line-tag");
if (lineNode.getLength() != 1) {
System.err.println("Invalid or missing line configuration tag!");
System.exit(1);
}
final String lineElemName = ((Element) lineNode.item(0))
.getAttribute("path");
final String lineAttribName = ((Element) lineNode.item(0))
.getAttribute("attrib");
if (lineElemName.length() == 0 || lineAttribName.length() == 0) {
System.err.println("Invalid or missing file configuration tag!");
System.exit(1);
}
// get function tag
NodeList functionNode = fileElem.getElementsByTagName("function-tag");
String functionElemName = "";
String functionAttribName = "";
if (functionNode.getLength() == 1) {
functionElemName = ((Element) functionNode.item(0))
.getAttribute("path");
functionAttribName = ((Element) functionNode.item(0))
.getAttribute("attrib");
}
// get description tag
NodeList descriptionNode = fileElem
.getElementsByTagName("description-tag");
if (descriptionNode.getLength() != 1) {
System.err
.println("Invalid or missing description configuration tag!");
System.exit(1);
}
final String descriptionElemName = ((Element) descriptionNode.item(0))
.getAttribute("path");
final String descriptionAttribName = ((Element) descriptionNode.item(0))
.getAttribute("attrib");
if (descriptionElemName.length() == 0
|| descriptionAttribName.length() == 0) {
System.err
.println("Invalid or missing description configuration tag!");
System.exit(1);
}
return new InputConfiguration(parserClassName, defectElemName,
fileElemName, fileAttribName, checkerElemName,
checkerAttribName, eventElemName, eventAttribName,
lineElemName, lineAttribName, functionElemName,
functionAttribName, descriptionElemName, descriptionAttribName);
}
private void prepareIntermediateDirectory() throws IOException {
// parse PMD input
FileWriter versionEmitFile = null;
FileWriter domainEmitFile = null;
FileWriter versionOutputFile = null;
FileWriter domainOutputFile = null;
try {
// setup directories
System.out.println("Preparing intermdireate directory");
File outputDirectory = new File("output/intdir");
outputDirectory.mkdir();
outputDirectory = new File(CoveritySaFormatter.OUTPUT_PATH);
outputDirectory.mkdir();
outputDirectory = new File(CoveritySaFormatter.OUTPUT_PATH
+ "/emit");
outputDirectory.mkdir();
outputDirectory = new File(CoveritySaFormatter.OUTPUT_PATH
+ "/output");
outputDirectory.mkdir();
// create meta files
versionEmitFile = new FileWriter(CoveritySaFormatter.OUTPUT_PATH
+ "/emit/version");
versionEmitFile
.write("# Version file created with Prevent version 5.4.1\n64");
domainEmitFile = new FileWriter(CoveritySaFormatter.OUTPUT_PATH
+ "/emit/cov-domain-tag");
domainEmitFile.write("C#\n");
versionOutputFile = new FileWriter(CoveritySaFormatter.OUTPUT_PATH
+ "/output/version");
versionOutputFile
.write("# Version file created with Prevent version 5.4.1\n64");
domainOutputFile = new FileWriter(CoveritySaFormatter.OUTPUT_PATH
+ "/output/cov-domain-tag");
domainOutputFile.write("C#\n");
} finally {
try {
if (versionEmitFile != null) {
versionEmitFile.close();
}
if (versionOutputFile != null) {
versionOutputFile.close();
}
if (domainEmitFile != null) {
domainEmitFile.close();
}
if (domainOutputFile != null) {
domainOutputFile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void parse() {
try {
// read the configuration file and prepare the intermediate
// directory
InputConfiguration configuration = loadConfigurationFile();
prepareIntermediateDirectory();
System.out.println("Parsing input file: " + filename);
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(this.filename);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression fileExpr = xpath.compile(configuration
.getFileElemName());
xpath = factory.newXPath();
XPathExpression defectExpr = xpath.compile(configuration
.getDefectElemName());
xpath = factory.newXPath();
XPathExpression checkerExpr = xpath.compile(configuration
.getCheckerElemName());
xpath = factory.newXPath();
XPathExpression eventExpr = xpath.compile(configuration
.getEventElemName());
xpath = factory.newXPath();
XPathExpression lineExpr = xpath.compile(configuration
.getLineElemName());
xpath = factory.newXPath();
XPathExpression descExpr = xpath.compile(configuration
.getDescriptionElemName());
NodeList fileNodes = (NodeList) fileExpr.evaluate(doc,
XPathConstants.NODESET);
StringBuffer functionMetrics = new StringBuffer();
if (fileNodes != null) {
for (int i = 0; i < fileNodes.getLength(); i++) {
Element fileElem = (Element) fileNodes.item(i);
final String filename = fileElem.getAttribute(configuration
.getFileAttribName()).replace('\\', '/');
// load the parser
Parser parser = null;
final String parserClassName = configuration.getParserClassName();
if (parserClassName.length() > 0) {
parser = (Parser) Class.forName(parserClassName).newInstance();
}
System.out.println("Parsing source file: " + filename);
// TODO: not parse if filename is provided
if (parser.parse(filename, functionMetrics)) {
this.functionCount += parser.getFunctionCount();
this.lineCount += parser.getLineCount();
// generate a list of defects
NodeList defectNodes = (NodeList) defectExpr.evaluate(
fileElem, XPathConstants.NODESET);
for (int j = 0; j < defectNodes.getLength(); j++) {
Element defectElem = (Element) defectNodes.item(j);
// get rule
NodeList checkerNodes = (NodeList) checkerExpr
.evaluate(defectElem,
XPathConstants.NODESET);
if (checkerNodes.getLength() != 1) {
System.err.println("Invalid checker tag!");
System.exit(1);
}
Element checkerElem = (Element) checkerNodes
.item(0);
String rule;
if (!configuration.getCheckerAttribName().equals(
"#")) {
rule = checkerElem.getAttribute(configuration
.getCheckerAttribName());
} else {
rule = checkerElem.getFirstChild()
.getNodeValue();
}
rule = rule.substring(rule.lastIndexOf('.') + 1,
rule.length());
rule = "EXT:" + rule;
// get event
NodeList eventNodes = (NodeList) eventExpr
.evaluate(defectElem,
XPathConstants.NODESET);
if (eventNodes.getLength() != 1) {
System.err.println("Invalid event tag!");
System.exit(1);
}
Element eventElem = (Element) eventNodes.item(0);
String event;
if (!configuration.getEventAttribName().equals("#")) {
event = eventElem.getAttribute(configuration
.getEventAttribName());
} else {
event = eventElem.getFirstChild()
.getNodeValue();
}
// get line
NodeList lineNodes = (NodeList) lineExpr.evaluate(
defectElem, XPathConstants.NODESET);
if (lineNodes.getLength() != 1) {
System.err.println("Invalid line tag!");
System.exit(1);
}
Element lineElem = (Element) lineNodes.item(0);
String line;
if (!configuration.getLineAttribName().equals("#")) {
line = lineElem.getAttribute(configuration
.getLineAttribName());
} else {
line = lineElem.getFirstChild().getNodeValue();
}
// get function
String function = parser.getFunction(Integer.parseInt(line));
// get description
NodeList descNodes = (NodeList) descExpr.evaluate(
defectElem, XPathConstants.NODESET);
if (descNodes.getLength() != 1) {
System.err.println("Invalid desc tag!");
System.exit(1);
}
Element descElem = (Element) descNodes.item(0);
String description;
if (!configuration.getDescriptionAttribName()
.equals("#")) {
description = descElem
.getAttribute(configuration
.getDescriptionAttribName());
} else {
description = descElem.getFirstChild()
.getNodeValue();
}
if(filename == null || filename.length() == 0) {
System.err.println("Invalid filename value!");
System.exit(1);
}
if(rule == null || rule.length() == 0) {
System.err.println("Invalid rule value!");
System.exit(1);
}
if(event == null || event.length() == 0) {
System.err.println("Invalid event value!");
System.exit(1);
}
if(line == null || line.length() == 0) {
System.err.println("Invalid line value!");
System.exit(1);
}
if(function == null || function.length() == 0) {
System.err.println("Invalid function value!");
System.exit(1);
}
if(description == null || description.length() == 0) {
System.err.println("Invalid description value!");
System.exit(1);
}
// add new defect
defects.add(new CoveritySaFormatter.Defect(
filename, rule, event, line, function,
description));
}
} else {
throw new IOException("Unable to parse source file "
+ filename);
}
}
}
// generate intermediate files
if (fileNodes.getLength() > 0) {
System.out.println("Writing intermdireate files");
CoveritySaFormatter writer = new CoveritySaFormatter(defects, functionMetrics.toString());
writer.write();
System.out.println("------------------");
DecimalFormat decimalFormat = new DecimalFormat("###,###,###");
System.out.println("Processed "
+ decimalFormat.format(fileNodes.getLength())
+ " file(s), " + decimalFormat.format(this.lineCount)
+ " LOC and "
+ decimalFormat.format(this.functionCount)
+ " function(s)");
} else {
System.out
.println("No defects where deteced or no files were scanned.");
System.exit(1);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
System.err
.println("Unable to open input file or write intermediate directory.");
} catch (InstantiationException e) {
System.err.println("Unable unable to load specified parser.");
} catch (IllegalAccessException e) {
System.err.println("Unable unable to load specified parser.");
} catch (ClassNotFoundException e) {
System.err.println("Unable unable to load specified parser.");
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
}