diff --git a/mustang/toecount/pom.xml b/mustang/toecount/pom.xml
new file mode 100644
index 00000000..68b9f0f2
--- /dev/null
+++ b/mustang/toecount/pom.xml
@@ -0,0 +1,88 @@
+
+ 4.0.0
+ org.mustangproject.ZUGFeRD
+ toecount
+ 0.0.4-SNAPSHOT
+ ZUGFeRD PDF checker
+ Shows statistics on how many PDFs in a directory are ZUGFeRD-Compliant
+
+
+ mustang-mvn-repo
+ https://raw.github.com/Rayman2200/PDFA3/mvn-repo/
+
+
+ sonatype-oss-public
+ https://oss.sonatype.org/content/groups/public/
+
+ true
+
+
+ true
+
+
+
+
+
+
+ org.mustangproject.ZUGFeRD
+ mustang
+ 1.1.2
+
+
+ org.apache.pdfbox
+ pdfbox
+ 1.8.8
+
+
+ com.sanityinc
+ jargs
+ 2.0-SNAPSHOT
+
+
+
+
+
+
+
+
+ maven-assembly-plugin
+
+
+
+ toecount.Toecount
+
+
+
+
+
+ jar-with-dependencies
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+
+ true
+ toecount.Toecount
+
+
+
+ jar-with-dependencies
+
+
+
+ 1.7
+ 1.7
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mustang/toecount/src/main/java/toecount/FileChecker.java b/mustang/toecount/src/main/java/toecount/FileChecker.java
new file mode 100644
index 00000000..ef955335
--- /dev/null
+++ b/mustang/toecount/src/main/java/toecount/FileChecker.java
@@ -0,0 +1,55 @@
+package toecount;
+
+import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
+
+public class FileChecker {
+ String filename;
+ StatRun thisRun;
+ boolean isPDF=false;
+ boolean checkFileExt=true;
+
+ public FileChecker(String filename, StatRun statistics) {
+ this.filename=filename;
+ thisRun=statistics;
+ thisRun.incFileCount();
+ String extension = "";
+ if (checkFileExt) {
+ int extIndex = filename.lastIndexOf(".");
+ if (extIndex >= 0) {
+ extension = filename.substring(extIndex).toLowerCase();
+ isPDF=extension.equals(".pdf");// alternative check for PDF: File starts with %PDF-
+ thisRun.incPDFCount();
+ }
+
+ } else {
+ thisRun.incPDFCount();
+ }
+ }
+
+ public boolean checkForZUGFeRD() {
+ if ((!isPDF)&&(checkFileExt)) {
+ return false;
+ }
+ ZUGFeRDImporter zi=new ZUGFeRDImporter();
+ zi.extract(filename);
+ if (zi.canParse()) {
+ thisRun.incZUGFeRDCount();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean isPDF() {
+ return isPDF;
+ }
+
+ public String getOutputLine() {
+ return thisRun.getOutputLine();
+ }
+
+ public void ignoreFileExtension() {
+ checkFileExt=false;
+ }
+
+}
diff --git a/mustang/toecount/src/main/java/toecount/FileTraverser.java b/mustang/toecount/src/main/java/toecount/FileTraverser.java
new file mode 100644
index 00000000..461d254e
--- /dev/null
+++ b/mustang/toecount/src/main/java/toecount/FileTraverser.java
@@ -0,0 +1,65 @@
+package toecount;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+public class FileTraverser extends SimpleFileVisitor {
+
+
+ private StatRun thisRun;
+ private boolean checkFileExt=true;
+ public FileTraverser(StatRun statistics) {
+ this.thisRun=statistics;
+ }
+
+ /***
+ * check each file
+ */
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
+ if (attr.isSymbolicLink()) {
+ // Not yet handled
+ } else if (attr.isRegularFile()) {
+ String filename = file.toString();
+ FileChecker fc = new FileChecker(filename, thisRun);
+ if (!checkFileExt) {
+ fc.ignoreFileExtension();
+ }
+ fc.checkForZUGFeRD();
+ System.out.print(fc.getOutputLine());
+
+ } else {
+ // Not yet handled
+ }
+ return CONTINUE;
+ }
+
+ /***
+ * for each directory
+ */
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ // System.out.format("Directory: %s%n", dir);
+ thisRun.incDirCount();
+ return CONTINUE;
+ }
+
+
+ /***
+ * show errors like file permission stacktraces
+ */
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ System.err.println(exc);
+ return CONTINUE;
+ }
+
+ public void ignoreFileExtension() {
+ checkFileExt=false;
+ }
+}
diff --git a/mustang/toecount/src/main/java/toecount/StatRun.java b/mustang/toecount/src/main/java/toecount/StatRun.java
new file mode 100644
index 00000000..cdfffecd
--- /dev/null
+++ b/mustang/toecount/src/main/java/toecount/StatRun.java
@@ -0,0 +1,61 @@
+package toecount;
+
+public class StatRun {
+ private int pdfCount = 0;
+ private int horseCount = 0;
+ private int fileCount = 0;
+ private int dirCount = 0;
+
+ public void incFileCount(){
+ fileCount++;
+ }
+
+ public void incPDFCount(){
+ pdfCount++;
+ }
+
+ public void incZUGFeRDCount(){
+ horseCount++;
+ }
+
+ public void incDirCount(){
+ dirCount++;
+ }
+
+ public int getFileCount(){
+ return fileCount;
+ }
+
+ public int getPDFCount(){
+ return pdfCount;
+ }
+
+ public int getZUGFeRDCount(){
+ return horseCount;
+ }
+
+ public int getDirCount(){
+ return dirCount;
+ }
+
+ /***
+ * returns final statistics
+ * @return
+ */
+ public String getSummaryLine() {
+
+ return "\r\n===================================================================\r\n"+String.format(
+ "Files:\t%d\tDirs:\t%d\tPDF:\t%d\tZUGFeRD:\t%d\r\n",
+ getFileCount(), getDirCount(), getPDFCount(), getZUGFeRDCount());
+
+ }
+ /***
+ * show that something is happening
+ * @return String
+ */
+ public String getOutputLine() {
+ return ".";
+ }
+
+
+}
diff --git a/mustang/toecount/src/main/java/toecount/Toecount.java b/mustang/toecount/src/main/java/toecount/Toecount.java
new file mode 100644
index 00000000..5a20eef3
--- /dev/null
+++ b/mustang/toecount/src/main/java/toecount/Toecount.java
@@ -0,0 +1,127 @@
+package toecount;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import com.sanityinc.jargs.CmdLineParser;
+import com.sanityinc.jargs.CmdLineParser.Option;
+
+public class Toecount {
+//build with: /opt/local/bin/mvn clean compile assembly:single
+ private static void printUsage() {
+ System.err
+ .println(getUsage());
+ }
+
+ private static String getUsage() {
+ return "Usage: Toecount [-d,--directory] [-l,--listfromstdin] [-i,--ignorefileextension] [-h,--help]\r\n";
+ }
+ private static void printHelp() {
+ System.out
+ .println("Mustangproject.org's Toecount 0.0.4 \r\n"
+ + "A Apache Public License command line tool for statistics on PDF invoices with\r\n"
+ + "ZUGFeRD Metadata (http://www.zugferd.de)\r\n"
+ + "\r\n"
+ + getUsage()
+ + "\t--directory= can specify a single PDF or a directory to be scanned\r\n"
+ + "\t\tIf it is a directory, it will recurse.\r\n"
+ + "\t--listfromstdin allows to specify a list of linefeed separated files on runtime.\r\n"
+ + "\t\tIt will start once a blank line has been entered.\r\n"
+ + "\t--ignorefileextension check *.* instead of *.pdf files");
+ }
+
+
+ // /opt/local/bin/mvn clean compile assembly:single
+ public static void main(String[] args) {
+ CmdLineParser parser = new CmdLineParser();
+ Option dirnameOption = parser.addStringOption('d', "directory");
+ Option filesFromStdInOption = parser.addBooleanOption('l',
+ "listfromstdin");
+ Option ignoreFileExtOption = parser.addBooleanOption('i',
+ "ignorefileextension");
+ Option helpOption = parser.addBooleanOption('h',
+ "help");
+
+ if (args.length==0) {
+ printUsage();
+ System.exit(2);
+
+ }
+ try {
+ parser.parse(args);
+ } catch (CmdLineParser.OptionException e) {
+ System.err.println(e.getMessage());
+ printUsage();
+ System.exit(2);
+ }
+
+ String directoryName = parser.getOptionValue(dirnameOption);
+
+ Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption,
+ Boolean.FALSE);
+
+ Boolean helpRequested = parser.getOptionValue(helpOption,
+ Boolean.FALSE);
+
+ Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption,
+ Boolean.FALSE);
+
+ if (helpRequested) {
+ printHelp();
+ }
+
+ StatRun sr=new StatRun();
+ if (directoryName != null) {
+ Path startingDir = Paths.get(directoryName);
+
+ if (Files.isRegularFile(startingDir)) {
+ String filename = startingDir.toString();
+ FileChecker fc = new FileChecker(filename, sr);
+ if (ignoreFileExt) {
+ fc.ignoreFileExtension();
+ }
+ fc.checkForZUGFeRD();
+ System.out.print(fc.getOutputLine());
+
+ } else if (Files.isDirectory(startingDir)) {
+ FileTraverser pf = new FileTraverser(sr);
+ if (ignoreFileExt) {
+ pf.ignoreFileExtension();
+ }
+ try {
+ Files.walkFileTree(startingDir, pf);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ }
+
+ if (filesFromStdIn) {
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+ String s;
+ try {
+ while ((s = in.readLine()) != null && s.length() != 0) {
+ FileChecker fc = new FileChecker(s, sr);
+ if (ignoreFileExt) {
+ fc.ignoreFileExtension();
+ }
+ fc.checkForZUGFeRD();
+ System.out.print(fc.getOutputLine());
+
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+ System.out.println(sr.getSummaryLine());
+ }
+}