/*
* PDFCM
*
* PDF Convert and Merge
* Uses Open Office 2.3 or better to convert supported file types to PDF.
*
* Gregory Edwin Graham
* May 16, 2008
*/
package pdfcm;
import java.io.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
/**
* Main class for PDFCM - parses parameters and drives program.
*
* @author Gregory Edwin Graham
*/
public class Main {
/**
* Returns a String array of trimmed values from an input string and separator
*
* @param input The String array to split and trim
* @param separator The separator on which to run the String split
* @return A String array of trimmed values from an input string and separator
*/
protected static String[] GetTrimmedArray(String input, String separator) {
if ( input == null || separator == null ) return null;
String[] tmp = input.split(separator);
String[] retval = new String[tmp.length];
for ( int i = 0; i < tmp.length; i++ ) {
retval[i] = tmp[i].trim();
}
return retval;
}
/**
* Prints out a usage string and exits.
*
* @param exVal Exit value to return to the OS.
*/
public static void Usage(int exVal) {
System.out.println();
System.out.println("Usage: java pdfcm.Main [-m mergeFile] [-d] file1 [file2 [file3...]]");
System.out.println("Usage (jarfile): java -jar pdfcm.jar [-m mergeFile] [-d] file1 [file2 [file3...]]");
System.out.println();
System.out.println(" Converts all given input files to PDF. Output filenames have the same base");
System.out.println(" filenames as the input files and the extension \"pdf\". PDF files on the");
System.out.println(" input are not processed.");
System.out.println();
System.out.println(" INPUT OPTIONS");
System.out.println();
System.out.println(" -m mergeFile");
System.out.println(" Causes converted PDF files and existing PDF (unprocessed) files on the");
System.out.println(" input to be merged into a single PDF file given by mergeFile as a final");
System.out.println(" step.");
System.out.println();
System.out.println(" -d");
System.out.println(" Causes input files to be removed after successful processing. When");
System.out.println(" used in conjunction with the -m option, all intermediate files as well");
System.out.println(" as any PDF files on the input are removed after successful processing.");
System.out.println();
System.out.println(" In case of a name collision between an input filename and the merge filename,");
System.out.println(" in the case that the -d option is given, the collision will be resolved. If");
System.out.println(" the -d option is not given, then an error will be generated to prevent");
System.out.println(" accidental overwrite of a file.");
System.exit(exVal);
}
/**
* Prints a custom error message to stdout and exits with the standard
* usage message and given exit code.
*
* @param errm Custom error message to pring to stdout
* @param exVal Exit value to return to the OS.
*/
public static void Usage(String errm, int exVal) {
System.out.println();
System.out.println(errm);
Usage(exVal);
}
/**
* Assuming the two inputs are filenames, checks the base parts of each
* filename for equality.
*
* @param f1 The first filename to compare
* @param f2 The second filename to compare
* @return true if the base parts of each filename are equal, or false if not or if both inputs are null.
*/
protected static boolean CompareFilenameBase(String f1, String f2) {
if (f1 == null || f2 == null) {
return false;
}
int lastDot1 = f1.lastIndexOf('.');
if (lastDot1 < 0) {
return false;
}
int lastDot2 = f2.lastIndexOf('.');
if (lastDot2 < 0) {
return false;
}
if (lastDot1 != lastDot2) {
return false;
}
if (lastDot1 == 0) {
return true;
}
return (f1.substring(0, lastDot1).contentEquals(f2.substring(0, lastDot2)));
}
/**
* Main method
*
* @param args Command line arguments
*/
public static void main(String[] args) {
// Sanity check the command line input
if (args.length == 0) {
Usage(0);
}
// Get paths of Open Office, Ghostscript and file extension map from the config file.
String ooLibPath = null;
String gsExePath = null;
String gsExeName = null;
String shellCommandStyle = null;
String wTypes = null;
String cTypes = null;
String dTypes = null;
String nTypes = null;
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
InputStream is = loader.getResourceAsStream("pdfcm/config.properties");
Properties props = new Properties();
props.load(is);
is.close();
ooLibPath = props.getProperty("ooLibPath");
gsExePath = props.getProperty("gsExePath");
gsExeName = props.getProperty("gsExeName");
shellCommandStyle = props.getProperty("shellCommandStyle");
wTypes = props.getProperty("writerTypes");
cTypes = props.getProperty("calcTypes");
dTypes = props.getProperty("drawTypes");
nTypes = props.getProperty("nativeTypes");
} catch (Exception ex) {
System.out.println("Could not get configuration from config.properties: " +
ex.getMessage());
}
// Instantiate the converter class
PDFConvert pdfc = new PDFConvert();
// Configure the converter
pdfc.setOOLibPath(ooLibPath);
pdfc.setGSExePath(gsExePath);
pdfc.setGSExeName(gsExeName);
pdfc.setShellCommandStyle(shellCommandStyle);
// Configue file extensions
pdfc.SetWriterTypes(GetTrimmedArray(wTypes,","));
pdfc.SetCalcTypes(GetTrimmedArray(cTypes,","));
pdfc.SetDrawTypes(GetTrimmedArray(dTypes,","));
pdfc.SetNativeTypes(GetTrimmedArray(nTypes,","));
// Set options from the command line
pdfc.setDeleteOnFinish(false);
pdfc.setDoMerge(false);
// This will hold the real output filename in case a merge filename
// collides with a processed input filename
String oFileName = null;
// Process arguments
int iArg = 0;
List<String> rawFileNames = new ArrayList<String>();
while (iArg < args.length) {
// Is it a merge?
if (args[iArg].contentEquals("-m")) {
// Reject a trailing "-m"
if (iArg + 1 > args.length) {
Usage(-1);
}
// Reject multiple "-m"
if (pdfc.getDoMerge()) {
Usage("Use the \"-m\" option only once.", -1);
}
// Set merge parameters
pdfc.setDoMerge(true);
pdfc.setOutputFilename(args[iArg + 1]);
oFileName = args[iArg + 1];
iArg += 2;
} else // Is it a delete-on-success?
if (args[iArg].contentEquals("-d")) {
pdfc.setDeleteOnFinish(true);
iArg++;
} else // Treat as a filename
{
rawFileNames.add(args[iArg]);
iArg++;
}
}
// Reject if no input files were given
if (rawFileNames.size() == 0) {
Usage("Please enter at least one input file.", -1);
}
// Check existence of input files
boolean isMissingFile = false;
String[] inputFiles = new String[rawFileNames.size()];
for (int i = 0; i < rawFileNames.size(); i++) {
File file = new File(rawFileNames.get(i));
if (file.exists()) {
inputFiles[i] = file.getAbsolutePath();
} else {
System.out.println("Input file not found: " + file.getAbsolutePath());
isMissingFile = true;
}
}
// If any files are missing, quit.
if (isMissingFile) {
Usage(-1);
}
// Check for collisions between filenames of a merged file and an
// intermediate file and temproarily change the output filename.
boolean isCollision = false;
if (pdfc.getDoMerge() && pdfc.getOutputFilename() != null) {
String testName = pdfc.getOutputFilename();
for (int i = 0; i < rawFileNames.size(); i++) {
if (CompareFilenameBase(rawFileNames.get(i), testName)) {
isCollision = true;
break;
}
}
}
if (isCollision) {
if (!pdfc.getDeleteOnFinish()) {
// If -d is not given, then processing would overwrite a
// file the user might expect to be there afterwards.
Usage("Merge filename conflicts with an intermediate filename: " + oFileName +
"\nPlease choose another filename or use the -d option.", -1);
} else {
// Name collision is OK if -d was also given since the user expects the
// intermediate file to be removed anyway. So create a temporary unique
// filename for the output
StringBuffer uniquifier = new StringBuffer();
for (int i = 0; i < rawFileNames.size(); i++) {
uniquifier.append((rawFileNames.get(i).charAt(i) == 'a' ? 'b' : 'a'));
}
pdfc.setOutputFilename(uniquifier.toString() + oFileName);
}
}
// Phew! We made it...
boolean done = pdfc.DoConvert(inputFiles);
// Check and report any errors
if (!done) {
System.out.println("Conversion failed: " + pdfc.getStatusText());
System.exit(-1);
} else {
// Rename the merge file if it was uniquified to avoid name collision
if (pdfc.getDoMerge()) {
File orig = new File(pdfc.getOutputFilename());
if (orig.exists()) {
File dest = new File(oFileName);
orig.renameTo(dest);
System.out.println("Conversion succeeded.");
System.exit(0);
} else {
// Check and report any errors
System.out.println("Conversion and merge apparently succeeded, but output file was not found: " +
pdfc.getOutputFilename());
System.exit(-1);
}
} else {
System.out.println("Conversion succeeded.");
System.exit(0);
}
}
}
}