Created
April 28, 2021 16:12
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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