Skip to content

Instantly share code, notes, and snippets.

@Andrew-William-Smith
Created April 28, 2021 16:12
Show Gist options
  • Save Andrew-William-Smith/07e261161870151a0ce0187259409000 to your computer and use it in GitHub Desktop.
Save Andrew-William-Smith/07e261161870151a0ce0187259409000 to your computer and use it in GitHub Desktop.
A simple utility to verify the downloaded CIA Factbook file for the Huffman assignment.
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
* A simple utility to validate that the 2008 CIA Factbook text file used for
* the CS 314 Huffman Coding assignment was downloaded correctly without being
* improperly transcoded.
*
* License: GNU GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.en.html)
*
* @author Andrew Smith ([email protected])
*/
public class FactbookValidator {
/** A URL for the cumulative archive of Huffman files. */
private static final String ARCHIVE_URL =
"https://www.cs.utexas.edu/~scottm/cs314/javacode/A10_Huffman/A10_Huffman_All_Files.zip";
private static final String REDOWNLOAD_REQUEST =
"Please use only the version of the CIA Factbook provided in the cumulative Huffman archive: "
+ ARCHIVE_URL;
/** The number of bytes in the correct CIA Factbook file. */
private static final long FACTBOOK_FILE_SIZE = 9637228;
/** The MD5 checksum of the correct CIA Factbook file. */
private static final byte[] FACTBOOK_FILE_CHECKSUM = {
-63, 60, 77, 5, -91, -125, 16, 93, 125, 20, 19, -72, 97, -111, 37, 96
};
public static void main(String[] args) throws IOException {
// Request the Factbook file from the user.
File factbook = getUserFile();
if (factbook == null) {
System.err.println("You must select a CIA Factbook file to validate.");
System.exit(-1);
}
// Ensure that the file does not contain any carriage returns and compute its MD5 checksum.
byte[] checksum = computeChecksum(factbook);
if (checksum == null) {
System.err.println("Your CIA Factbook file contains Windows-style (CRLF) line endings. "
+ REDOWNLOAD_REQUEST);
System.exit(-1);
}
// Ensure that the file is the correct size.
long factbookSize = factbook.length();
if (factbookSize != FACTBOOK_FILE_SIZE) {
System.err.printf("Your CIA Factbook file contains the wrong number of bytes (expected %d, actual %d), "
+ "indicating that it was truncated when it was downloaded. " + REDOWNLOAD_REQUEST + "\n",
FACTBOOK_FILE_SIZE, factbookSize);
System.exit(-1);
}
// Ensure that the checksum of the factbook file is correct.
if (!Arrays.equals(checksum, FACTBOOK_FILE_CHECKSUM)) {
System.err.println("The checksum of your CIA Factbook file is incorrect, indicating that the file could "
+ "have been mangled while you were downloading it. " + REDOWNLOAD_REQUEST);
System.exit(-1);
}
System.out.println("Your CIA Factbook file is correct!");
}
/**
* Request a text file from the user using a graphical dialog.
*
* @return A handle to the file selected by the user, or null if the user
* closed the dialog without selecting a file.
*/
private static File getUserFile() {
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Select your CIA Factbook text file");
// Only allow the user to select files with the .txt extension.
fc.setFileFilter(new FileNameExtensionFilter("Text files", "txt"));
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile();
} else {
return null;
}
}
/**
* Compute the MD5 checksum for the specified CIA Factbook file, provided
* that the file does not contain carriage returns.
*
* @param factbook The CIA Factbook file for which to generate a checksum.
* @return An array of bytes constituting the MD5sum of the factbook, or
* null if the file contained any carriage returns.
*/
private static byte[] computeChecksum(File factbook) throws IOException {
// Attempt to instantiate an MD5 checksum generator.
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
System.err.println("Unable to instantiate an MD5 checksum generator.");
return null;
}
BufferedInputStream is = new BufferedInputStream(new FileInputStream(factbook));
DigestInputStream digestStream = new DigestInputStream(is, md5);
// Read the file's contents using the MD5 digest input stream.
int read;
boolean foundCarriageReturn = false;
while ((read = digestStream.read()) != -1 && !foundCarriageReturn) {
foundCarriageReturn = read == '\r';
}
digestStream.close();
// If a carriage return was found, we could not compute the checksum.
return foundCarriageReturn ? null : md5.digest();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment