Fields Summary |
---|
private File | fileFile for which checksum is to be calculated. |
private File | todirRoot directory in which the checksum files will be written.
If not specified, the checksum files will be written
in the same directory as each file. |
private String | algorithmMessageDigest algorithm to be used. |
private String | providerMessageDigest Algorithm provider |
private String | fileextFile Extension that is be to used to create or identify
destination file |
private String | propertyHolds generated checksum and gets set as a Project Property. |
private Map | allDigestsHolds checksums for all files (both calculated and cached on disk).
Key: java.util.File (source file)
Value: java.lang.String (digest) |
private Map | relativeFilePathsHolds relative file names for all files (always with a forward slash).
This is used to calculate the total hash.
Key: java.util.File (source file)
Value: java.lang.String (relative file name) |
private String | totalpropertyProperty where totalChecksum gets set. |
private boolean | forceOverwriteWhether or not to create a new file.
Defaults to false . |
private String | verifyPropertyContains the result of a checksum verification. ("true" or "false") |
private FileUnion | resourcesResource Collection. |
private Hashtable | includeFileMapStores SourceFile, DestFile pairs and SourceFile, Property String pairs. |
private MessageDigest | messageDigestMessage Digest instance |
private boolean | isConditionis this task being used as a nested condition element? |
private int | readBufferSizeSize of the read buffer to use. |
private MessageFormat | formatFormater for the checksum file. |
Methods Summary |
---|
public void | add(org.apache.tools.ant.types.ResourceCollection rc)Add a resource collection.
if (rc == null) {
return;
}
resources = (resources == null) ? new FileUnion() : resources;
resources.add(rc);
|
public void | addFileset(org.apache.tools.ant.types.FileSet set)Files to generate checksums for.
add(set);
|
private void | addToIncludeFileMap(java.io.File file)Add key-value pair to the hashtable upon which
to later operate upon.
if (file.exists()) {
if (property == null) {
File checksumFile = getChecksumFile(file);
if (forceOverwrite || isCondition
|| (file.lastModified() > checksumFile.lastModified())) {
includeFileMap.put(file, checksumFile);
} else {
log(file + " omitted as " + checksumFile + " is up to date.",
Project.MSG_VERBOSE);
if (totalproperty != null) {
// Read the checksum from disk.
String checksum = readChecksum(checksumFile);
byte[] digest = decodeHex(checksum.toCharArray());
allDigests.put(file, digest);
}
}
} else {
includeFileMap.put(file, property);
}
} else {
String message = "Could not find file "
+ file.getAbsolutePath()
+ " to generate checksum for.";
log(message);
throw new BuildException(message, getLocation());
}
|
private java.lang.String | createDigestString(byte[] fileDigest)
StringBuffer checksumSb = new StringBuffer();
for (int i = 0; i < fileDigest.length; i++) {
String hexStr = Integer.toHexString(0x00ff & fileDigest[i]);
if (hexStr.length() < 2) {
checksumSb.append("0");
}
checksumSb.append(hexStr);
}
return checksumSb.toString();
|
public static byte[] | decodeHex(char[] data)Converts an array of characters representing hexadecimal values into an
array of bytes of those same values. The returned array will be half the
length of the passed array, as it takes two characters to represent any
given byte. An exception is thrown if the passed char array has an odd
number of elements.
NOTE: This code is copied from jakarta-commons codec.
int l = data.length;
if ((l & 0x01) != 0) {
throw new BuildException("odd number of characters.");
}
byte[] out = new byte[l >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < l; i++) {
int f = Character.digit(data[j++], 16) << 4;
f = f | Character.digit(data[j++], 16);
out[i] = (byte) (f & 0xFF);
}
return out;
|
public boolean | eval()Calculate the checksum(s)
isCondition = true;
return validateAndExecute();
|
public void | execute()Calculate the checksum(s).
isCondition = false;
boolean value = validateAndExecute();
if (verifyProperty != null) {
getProject().setNewProperty(
verifyProperty,
(value ? Boolean.TRUE.toString() : Boolean.FALSE.toString()));
}
|
private boolean | generateChecksums()Generate checksum(s) using the message digest created earlier.
boolean checksumMatches = true;
FileInputStream fis = null;
FileOutputStream fos = null;
byte[] buf = new byte[readBufferSize];
try {
for (Enumeration e = includeFileMap.keys(); e.hasMoreElements();) {
messageDigest.reset();
File src = (File) e.nextElement();
if (!isCondition) {
log("Calculating " + algorithm + " checksum for " + src, Project.MSG_VERBOSE);
}
fis = new FileInputStream(src);
DigestInputStream dis = new DigestInputStream(fis,
messageDigest);
while (dis.read(buf, 0, readBufferSize) != -1) {
// Empty statement
}
dis.close();
fis.close();
fis = null;
byte[] fileDigest = messageDigest.digest ();
if (totalproperty != null) {
allDigests.put(src, fileDigest);
}
String checksum = createDigestString(fileDigest);
//can either be a property name string or a file
Object destination = includeFileMap.get(src);
if (destination instanceof java.lang.String) {
String prop = (String) destination;
if (isCondition) {
checksumMatches
= checksumMatches && checksum.equals(property);
} else {
getProject().setNewProperty(prop, checksum);
}
} else if (destination instanceof java.io.File) {
if (isCondition) {
File existingFile = (File) destination;
if (existingFile.exists()) {
try {
String suppliedChecksum =
readChecksum(existingFile);
checksumMatches = checksumMatches
&& checksum.equals(suppliedChecksum);
} catch (BuildException be) {
// file is on wrong format, swallow
checksumMatches = false;
}
} else {
checksumMatches = false;
}
} else {
File dest = (File) destination;
fos = new FileOutputStream(dest);
fos.write(format.format(new Object[] {
checksum,
src.getName(),
}).getBytes());
fos.write(StringUtils.LINE_SEP.getBytes());
fos.close();
fos = null;
}
}
}
if (totalproperty != null) {
// Calculate the total checksum
// Convert the keys (source files) into a sorted array.
Set keys = allDigests.keySet();
Object[] keyArray = keys.toArray();
// File is Comparable, so sorting is trivial
Arrays.sort(keyArray);
// Loop over the checksums and generate a total hash.
messageDigest.reset();
for (int i = 0; i < keyArray.length; i++) {
File src = (File) keyArray[i];
// Add the digest for the file content
byte[] digest = (byte[]) allDigests.get(src);
messageDigest.update(digest);
// Add the file path
String fileName = (String) relativeFilePaths.get(src);
messageDigest.update(fileName.getBytes());
}
String totalChecksum = createDigestString(messageDigest.digest());
getProject().setNewProperty(totalproperty, totalChecksum);
}
} catch (Exception e) {
throw new BuildException(e, getLocation());
} finally {
FileUtils.close(fis);
FileUtils.close(fos);
}
return checksumMatches;
|
private java.io.File | getChecksumFile(java.io.File file)
File directory;
if (todir != null) {
// A separate directory was explicitly declared
String path = (String) relativeFilePaths.get(file);
if (path == null) {
//bug 37386. this should not occur, but it has, once.
throw new BuildException(
"Internal error: "
+ "relativeFilePaths could not match file"
+ file + "\n"
+ "please file a bug report on this");
}
directory = new File(todir, path).getParentFile();
// Create the directory, as it might not exist.
directory.mkdirs();
} else {
// Just use the same directory as the file itself.
// This directory will exist
directory = file.getParentFile();
}
File checksumFile = new File(directory, file.getName() + fileext);
return checksumFile;
|
private java.lang.String | readChecksum(java.io.File f)reads the checksum from a file using the specified format.
BufferedReader diskChecksumReader = null;
try {
diskChecksumReader = new BufferedReader(new FileReader(f));
Object[] result = format.parse(diskChecksumReader.readLine());
if (result == null || result.length == 0 || result[0] == null) {
throw new BuildException("failed to find a checksum");
}
return (String) result[0];
} catch (IOException e) {
throw new BuildException("Couldn't read checksum file " + f, e);
} catch (ParseException e) {
throw new BuildException("Couldn't read checksum file " + f, e);
} finally {
FileUtils.close(diskChecksumReader);
}
|
public void | setAlgorithm(java.lang.String algorithm)Specifies the algorithm to be used to compute the checksum.
Defaults to "MD5". Other popular algorithms like "SHA" may be used as well.
this.algorithm = algorithm;
|
public void | setFile(java.io.File file)Sets the file for which the checksum is to be calculated.
this.file = file;
|
public void | setFileext(java.lang.String fileext)Sets the file extension that is be to used to
create or identify destination file.
this.fileext = fileext;
|
public void | setForceOverwrite(boolean forceOverwrite)Whether or not to overwrite existing file irrespective of
whether it is newer than
the source file. Defaults to false.
this.forceOverwrite = forceOverwrite;
|
public void | setFormat(org.apache.tools.ant.taskdefs.Checksum$FormatElement e)Select the in/output pattern via a well know format name.
format = e.getFormat();
|
public void | setPattern(java.lang.String p)Specify the pattern to use as a MessageFormat pattern.
{0} gets replaced by the checksum, {1} by the filename.
format = new MessageFormat(p);
|
public void | setProperty(java.lang.String property)Sets the property to hold the generated checksum.
this.property = property;
|
public void | setProvider(java.lang.String provider)Sets the MessageDigest algorithm provider to be used
to calculate the checksum.
this.provider = provider;
|
public void | setReadBufferSize(int size)The size of the read buffer to use.
this.readBufferSize = size;
|
public void | setTodir(java.io.File todir)Sets the root directory where checksum files will be
written/read
this.todir = todir;
|
public void | setTotalproperty(java.lang.String totalproperty)Sets the property to hold the generated total checksum
for all files.
this.totalproperty = totalproperty;
|
public void | setVerifyproperty(java.lang.String verifyProperty)Sets the verify property. This project property holds
the result of a checksum verification - "true" or "false"
this.verifyProperty = verifyProperty;
|
private boolean | validateAndExecute()Validate attributes and get down to business.
String savedFileExt = fileext;
if (file == null && (resources == null || resources.size() == 0)) {
throw new BuildException(
"Specify at least one source - a file or a resource collection.");
}
if (!(resources == null || resources.isFilesystemOnly())) {
throw new BuildException("Can only calculate checksums for file-based resources.");
}
if (file != null && file.exists() && file.isDirectory()) {
throw new BuildException("Checksum cannot be generated for directories");
}
if (file != null && totalproperty != null) {
throw new BuildException("File and Totalproperty cannot co-exist.");
}
if (property != null && fileext != null) {
throw new BuildException("Property and FileExt cannot co-exist.");
}
if (property != null) {
if (forceOverwrite) {
throw new BuildException(
"ForceOverwrite cannot be used when Property is specified");
}
int ct = 0;
if (resources != null) {
ct += resources.size();
}
if (file != null) {
ct++;
}
if (ct > 1) {
throw new BuildException(
"Multiple files cannot be used when Property is specified");
}
}
if (verifyProperty != null) {
isCondition = true;
}
if (verifyProperty != null && forceOverwrite) {
throw new BuildException("VerifyProperty and ForceOverwrite cannot co-exist.");
}
if (isCondition && forceOverwrite) {
throw new BuildException(
"ForceOverwrite cannot be used when conditions are being used.");
}
messageDigest = null;
if (provider != null) {
try {
messageDigest = MessageDigest.getInstance(algorithm, provider);
} catch (NoSuchAlgorithmException noalgo) {
throw new BuildException(noalgo, getLocation());
} catch (NoSuchProviderException noprovider) {
throw new BuildException(noprovider, getLocation());
}
} else {
try {
messageDigest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException noalgo) {
throw new BuildException(noalgo, getLocation());
}
}
if (messageDigest == null) {
throw new BuildException("Unable to create Message Digest", getLocation());
}
if (fileext == null) {
fileext = "." + algorithm;
} else if (fileext.trim().length() == 0) {
throw new BuildException("File extension when specified must not be an empty string");
}
try {
if (resources != null) {
for (Iterator i = resources.iterator(); i.hasNext();) {
FileResource fr = (FileResource) i.next();
File src = fr.getFile();
if (totalproperty != null || todir != null) {
// Use '/' to calculate digest based on file name.
// This is required in order to get the same result
// on different platforms.
relativeFilePaths.put(src, fr.getName().replace(File.separatorChar, '/"));
}
addToIncludeFileMap(src);
}
}
if (file != null) {
if (totalproperty != null || todir != null) {
relativeFilePaths.put(
file, file.getName().replace(File.separatorChar, '/"));
}
addToIncludeFileMap(file);
}
return generateChecksums();
} finally {
fileext = savedFileExt;
includeFileMap.clear();
}
|