Files
Brainstorm/Encryption Utility Application/src/com/eua/local/view/controller/EncryptViewController.java

531 lines
19 KiB
Java
Raw Normal View History

2014-05-30 10:31:51 -07:00
package com.eua.local.view.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.util.Random;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import com.foundation.metadata.Attribute;
import com.foundation.util.IManagedList;
import com.foundation.util.ManagedList;
import com.foundation.view.ControlDecoration;
import com.foundation.view.IViewContext;
import com.foundation.view.swt.DirectoryDialog;
import com.foundation.view.swt.FileDialog;
import com.common.comparison.Comparator;
import com.common.debug.Debug;
import com.common.io.StreamSupport;
import com.common.io.SymmetricOutputStream;
import com.common.security.ISymmetricAlgorithm;
import com.common.security.Rijndael;
import com.common.security.Sha1;
import com.common.util.LiteHashSet;
import com.common.util.StringSupport;
import com.eua.controller.SettingsController;
import com.eua.local.view.EncryptView;
import com.eua.model.FileMetadata;
/**
* Copyright Declarative Engineering LLC 2009<p>
*/
public class EncryptViewController extends AbstractViewController {
private static final int METRIC_BYTES = 0;
private static final int METRIC_KILO_BYTES = 1;
private static final int METRIC_MEGA_BYTES = 2;
private static final int METRIC_GIGA_BYTES = 3;
//Note: The metrics must be in ascending sequential order starting with zero for both the options array and the names array.//
private static final Integer[] METRIC_OPTIONS = new Integer[] {new Integer(METRIC_BYTES), new Integer(METRIC_KILO_BYTES), new Integer(METRIC_MEGA_BYTES), new Integer(METRIC_GIGA_BYTES)};
private static final String[] METRIC_OPTION_NAMES = new String[] {"Bytes", "Kilobytes", "Megabytes", "Gigabytes"};
public static final Attribute FILES = registerCollection(EncryptViewController.class, "files", AO_REFERENCED | AO_LAZY);
public static final Attribute SELECTED_FILES = registerCollection(EncryptViewController.class, "selectedFiles", AO_REFERENCED | AO_LAZY);
public static final Attribute SPLIT = registerAttribute(EncryptViewController.class, "split", Boolean.FALSE);
public static final Attribute MAXIMUM_OUTPUT_SIZE = registerAttribute(EncryptViewController.class, "maximumOutputSize", new Long(1));
public static final Attribute MAXIMUM_OUTPUT_METRIC = registerAttribute(EncryptViewController.class, "maximumOutputMetric", new Integer(METRIC_MEGA_BYTES));
public static final Attribute PASSWORD = registerAttribute(EncryptViewController.class, "password");
public static final Attribute OUTPUT_DIRECTORY = registerAttribute(EncryptViewController.class, "outputDirectory", AO_LAZY);
public static final Attribute OUTPUT_NAME = registerAttribute(EncryptViewController.class, "outputName", AO_LAZY);
public static final Attribute FILE_METADATA_SET = registerAttribute(EncryptViewController.class, "fileMetadataSet", AO_REFERENCED | AO_LAZY);
public static final Attribute INPUT_DIRECTORY = registerAttribute(EncryptViewController.class, "inputDirectory", AO_REFERENCED | AO_LAZY);
/**
* EncryptViewController constructor.
* @param viewContext
*/
public EncryptViewController(IViewContext viewContext) {
super(viewContext);
}//EncryptViewController()//
/* (non-Javadoc)
* @see com.foundation.common.Entity#lazyLoadAttribute(int)
*/
protected Object lazyLoadAttribute(Attribute attributeNumber) {
Object result = null;
if(attributeNumber == FILES) {
result = new ManagedList(10, 100);
}//if//
else if(attributeNumber == SELECTED_FILES) {
result = new ManagedList(10, 100);
}//else if//
else if(attributeNumber == INPUT_DIRECTORY) {
result = SettingsController.getSingleton().getInputDirectory();
if(result == null) {
File desktop = new File(System.getProperty("user.home"), "desktop");
if(desktop.exists()) {
result = desktop.getAbsolutePath();
}//if//
else {
result = System.getProperty("user.dir");
}//else//
}//if//
}//else if//
else if(attributeNumber == OUTPUT_DIRECTORY) {
result = SettingsController.getSingleton().getEncryptionOutputDirectory();
if(result == null) {
File desktop = new File(System.getProperty("user.home"), "desktop");
if(desktop.exists()) {
result = desktop.getAbsolutePath();
}//if//
else {
result = System.getProperty("user.dir");
}//else//
}//if//
}//else if//
else if(attributeNumber == OUTPUT_NAME) {
result = SettingsController.getSingleton().getEncryptedFileName();
if(result == null) {
result = "encrypted";
}//if//
}//else if//
else if(attributeNumber == FILE_METADATA_SET) {
result = new LiteHashSet(10, LiteHashSet.DEFAULT_LOAD_FACTOR, Comparator.getLogicalComparator(), LiteHashSet.STYLE_NO_DUPLICATES);
}//else if//
else {
result = super.lazyLoadAttribute(attributeNumber);
}//else//
return result;
}//lazyLoadAttribute()//
/* (non-Javadoc)
* @see com.foundation.controller.ViewController#getViewClass()
*/
protected Class getViewClass() {
return EncryptView.class;
}//getViewClass()//
/* (non-Javadoc)
* @see com.foundation.controller.ViewController#validate()
*/
public boolean validate() {
boolean result = true;
getDecorationManager().clearDecorations();
if(getSplit().booleanValue() && (getMaximumOutputSize() == null || getMaximumOutputSize().longValue() <= 0)) {
getDecorationManager().addDecoration(this, MAXIMUM_OUTPUT_SIZE, new ControlDecoration(IMAGE_ERROR, "Missing output size."));
result = false;
}//if//
else if(getSplit().booleanValue() && getMaximumOutputMetric().intValue() == METRIC_BYTES && getMaximumOutputSize().longValue() < 1000) {
getDecorationManager().addDecoration(this, MAXIMUM_OUTPUT_SIZE, new ControlDecoration(IMAGE_ERROR, "Maximum output size must be greater than 1000 if measured in bytes."));
result = false;
}//else if//
if(getPassword() == null || getPassword().length() == 0) {
getDecorationManager().addDecoration(this, PASSWORD, new ControlDecoration(IMAGE_ERROR, "Password required."));
result = false;
}//if//
if(getOutputDirectory() == null || getOutputDirectory().trim().length() == 0) {
getDecorationManager().addDecoration(this, OUTPUT_DIRECTORY, new ControlDecoration(IMAGE_ERROR, "Output directory required."));
result = false;
}//if//
if(getOutputName() == null || getOutputName().trim().length() == 0) {
getDecorationManager().addDecoration(this, OUTPUT_NAME, new ControlDecoration(IMAGE_ERROR, "Output name required."));
result = false;
}//if//
getDecorationManager().applyDecorationChanges();
return result;
}//validate()//
/**
* Cancels the log-in process and closes the client.
*/
public void doCancel() {
close();
}//doCancel()//
/**
* Initiates the validation process and opens the next view upon sucsessful validation.
*/
public void doEncrypt() {
synchronize();
if(validate()) {
if(getFiles().getSize() > 0 && getPassword() != null) {
BigDecimal totalSize = new BigDecimal(0);
BigDecimal maximumOutputSize = getSplit().booleanValue() ? new BigDecimal(getMaximumOutputSize().longValue()) : null;
int currentFileIndex = 0;
FileMetadata nextFile = (FileMetadata) getFiles().getFirst();
FileInputStream fin = null;
FileOutputStream fout = null;
byte[] buffer = new byte[100000]; //100k
ISymmetricAlgorithm algorithm = new Rijndael(new Random(StringSupport.hash(getPassword())));
SymmetricOutputStream sout = null;
ZipOutputStream zout = null;
File outputFile = new File(getOutputDirectory(), getOutputName() + ".enc");
try {
fin = new FileInputStream(new File(nextFile.getPath(), nextFile.getName()));
//Calculate the maximum output size of each split segment in terms of bytes.//
if(maximumOutputSize != null) {
switch(getMaximumOutputMetric().intValue()) {
case METRIC_GIGA_BYTES: {
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1073741824)); //1024^3
break;
}//case//
case METRIC_MEGA_BYTES: {
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1048576)); //1024^2
break;
}//case//
case METRIC_KILO_BYTES: {
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1024));
break;
}//case//
default: {
//Do nothing.//
break;
}//default//
}//switch//
}//if//
//Calculate the total size of all the input content.//
for(int index = 0; index < getFiles().getSize(); index++) {
FileMetadata next = (FileMetadata) getFiles().get(index);
totalSize = totalSize.add(new BigDecimal(next.getLength().longValue()));
}//for//
fout = new FileOutputStream(outputFile);
//Write the magic number which is used when reading to verify that the file is generated by this same tool.//
StreamSupport.writeInt(MAGIC_NUMBER, fout);
//Write the version number of the tool being used to generate the encrypted data.//
StreamSupport.writeInt(VERSION, fout);
//Create the symmetric encryption output stream.//
sout = new SymmetricOutputStream(fout, algorithm);
sout.encrypt(true);
//Create the zip output stream to ensure all encrypted content is first compressed.//
zout = new ZipOutputStream(sout);
zout.putNextEntry(new ZipEntry("main"));
//Write the number of input files.//
StreamSupport.writeInt(getFiles().getSize(), zout);
//Write each file name and size.//
for(int index = 0; index < getFiles().getSize(); index++) {
FileMetadata next = (FileMetadata) getFiles().get(index);
StreamSupport.writeString(next.getName(), zout);
StreamSupport.writeLong(next.getLength().longValue(), zout);
}//for//
//Write the file data as long as we have an input stream.//
while(fin != null) {
int readCount = 0;
//Read in a whole buffer of content.//
while(readCount < buffer.length && fin != null) {
readCount += StreamSupport.readBytes(fin, buffer, readCount, buffer.length - readCount);
//If we couldn't fill the buffer (due to not enough bytes in the input stream), then open a stream on the next file.//
if(readCount != buffer.length) {
fin.close();
//Increment to the next file and open an input stream.//
if(++currentFileIndex != getFiles().getSize()) {
nextFile = (FileMetadata) getFiles().get(currentFileIndex);
fin = new FileInputStream(new File(nextFile.getPath(), nextFile.getName()));
}//if//
else {
fin = null;
nextFile = null;
}//else//
}//if//
}//while//
zout.write(buffer, 0, readCount);
}//while//
zout.closeEntry();
zout.flush();
zout.finish();
sout.encrypt(false);
sout.flush();
zout.close();
sout.close();
fout.close();
//If the output should be split then split the generated file now.//
if(getSplit().booleanValue() && maximumOutputSize.compareTo(new BigDecimal(outputFile.length())) < 0) {
int outputFileIndex = 0;
BigDecimal bufferSize = new BigDecimal(buffer.length);
fin = new FileInputStream(outputFile);
fout = null;
//Keep reading and writing until the input stream is empty.//
while(fin != null) {
BigDecimal writeSize = new BigDecimal(0);
if(fout != null) {
fout.close();
}//if//
fout = new FileOutputStream(outputFile.getAbsolutePath() + "." + ++outputFileIndex);
//Keep writing to the current file until we can't write any more.//
while(fin != null && writeSize.compareTo(maximumOutputSize) < 0) {
int readCount;
BigDecimal readLength = maximumOutputSize.subtract(writeSize);
//If the read length is greater than the buffer size then use the buffer size.//
if(readLength.compareTo(bufferSize) > 0) {
readLength = bufferSize;
}//if//
readCount = StreamSupport.readBytes(fin, buffer, 0, readLength.intValue());
fout.write(buffer, 0, readCount);
writeSize = writeSize.add(new BigDecimal(readCount));
//Check to see if the input stream is empty.//
if(readCount != readLength.intValue()) {
fin.close();
fin = null;
}//if//
}//while//
}//while//
fout.close();
fout = new FileOutputStream(outputFile);
//Write the magic number which is used when reading to verify that the file is generated by this same tool.//
StreamSupport.writeInt(SEQUENCE_MAGIC_NUMBER, fout);
//Write the version number of the tool being used to generate the encrypted data.//
StreamSupport.writeInt(SEQUENCE_VERSION, fout);
//Write the number of files in the sequence.//
StreamSupport.writeInt(outputFileIndex, fout);
fout.close();
fout = null;
displayInformation("Encryption Successful", "The content was successfully encrypted and split. All results placed in \"" + outputFile.getParentFile().getCanonicalPath() + "\".");
}//if//
else {
displayInformation("Encryption Successful", "The content was successfully encrypted to \"" + outputFile.getCanonicalPath() + "\".");
}//else//
SettingsController.getSingleton().setEncryptionSettings(getOutputDirectory(), getOutputName(), getInputDirectory());
}//try//
catch(Throwable e) {
Debug.log(e);
}//catch//
finally {
if(fin != null) {
try {fin.close();}catch(Throwable e) {}
}//if//
if(fout != null) {
try {fout.close();}catch(Throwable e) {}
}//if//
}//finally//
}//if//
}//if//
}//doEncrypt()//
/**
* Changes the output directory by opening a dialog for the user to choose a location.
*/
public void doChangeOutputDirectory() {
DirectoryDialog dialog = new DirectoryDialog(getView(), 0);
String directory;
dialog.setMessage("Choose the output directory.");
if((directory = dialog.open()) != null) {
setOutputDirectory(directory);
}//if//
}//doChangeOutputDirectory()//
/**
* Adds files to the collection to be encrypted.
*/
public void doAddFiles() {
FileDialog dialog = new FileDialog(getView(), FileDialog.STYLE_MULTI);
String path;
dialog.setFilterPath(getInputDirectory());
dialog.setText("Select the files you wish to encrypt.");
if((path = dialog.open()) != null) {
String[] fileNames = dialog.getFileNames();
File pathFile = new File(path);
//Get the actual path. Doing this because the dialog's result isn't a directory path, but rather a path to the first selected file.//
path = pathFile.getParent();
setInputDirectory(path);
for(int index = 0; index < fileNames.length; index++) {
FileMetadata fileMetadata = new FileMetadata(fileNames[index], path);
if(getFileMetadataSet().add(fileMetadata) != -1) {
getFiles().add(fileMetadata);
}//if//
}//for//
}//if//
}//doAddFiles()//
/**
* Removes files from the collection to be encrypted.
*/
public void doRemoveFiles() {
if(getSelectedFiles().getSize() > 0) {
getFiles().removeAll(getSelectedFiles());
getSelectedFiles().removeAll();
}//if//
}//doRemoveFiles()//
/**
* Gets the files value.
* @return The files value.
*/
public IManagedList getFiles() {
return (IManagedList) getAttributeValue(FILES);
}//getFiles()//
/**
* Gets the selectedFiles value.
* @return The selectedFiles value.
*/
public IManagedList getSelectedFiles() {
return (IManagedList) getAttributeValue(SELECTED_FILES);
}//getSelectedFiles()//
/**
* Gets the split value.
* @return The split value.
*/
public Boolean getSplit() {
return (Boolean) getAttributeValue(SPLIT);
}//getSplit()//
/**
* Sets the split value.
* @param split The split value.
*/
public void setSplit(Boolean split) {
setAttributeValue(SPLIT, split);
}//setSplit()//
/**
* Gets the maximumOutputSize value.
* @return The maximumOutputSize value.
*/
public Long getMaximumOutputSize() {
return (Long) getAttributeValue(MAXIMUM_OUTPUT_SIZE);
}//getMaximumOutputSize()//
/**
* Sets the maximumOutputSize value.
* @param maximumOutputSize The maximumOutputSize value.
*/
public void setMaximumOutputSize(Long maximumOutputSize) {
setAttributeValue(MAXIMUM_OUTPUT_SIZE, maximumOutputSize);
}//setMaximumOutputSize()//
/**
* Gets the maximumOutputMetric value.
* @return The maximumOutputMetric value.
*/
public Integer getMaximumOutputMetric() {
return (Integer) getAttributeValue(MAXIMUM_OUTPUT_METRIC);
}//getMaximumOutputMetric()//
/**
* Sets the metric for the maximum output value.
* @param maximumOutputMetric The metric for the maximum output value.
*/
public void setMaximumOutputMetric(Integer maximumOutputMetric) {
setAttributeValue(MAXIMUM_OUTPUT_METRIC, maximumOutputMetric);
}//setMaximumOutputMetric()//
/**
* Gets the set of metrics allowed for the maximum output metric.
* @return The metrics allowed.
*/
public Integer[] getMetrics() {
return METRIC_OPTIONS;
}//getMetrics()//
/**
* Gets the metric name for the given metric identifier.
* @param metric The metric number.
* @return The name for the metric.
*/
public String getMetricName(Integer metric) {
return METRIC_OPTION_NAMES[metric.intValue()];
}//getMetricName()//
/**
* Gets the password value.
* @return The password value.
*/
public String getPassword() {
return (String) getAttributeValue(PASSWORD);
}//getPassword()//
/**
* Sets the password value.
* @param password The password value.
*/
public void setPassword(String password) {
setAttributeValue(PASSWORD, password);
}//setPassword()//
/**
* Gets the outputDirectory value.
* @return The outputDirectory value.
*/
public String getOutputDirectory() {
return (String) getAttributeValue(OUTPUT_DIRECTORY);
}//getOutputDirectory()//
/**
* Sets the outputDirectory value.
* @param outputDirectory The outputDirectory value.
*/
public void setOutputDirectory(String outputDirectory) {
setAttributeValue(OUTPUT_DIRECTORY, outputDirectory);
}//setOutputDirectory()//
/**
* Gets the outputName value.
* @return The outputName value.
*/
public String getOutputName() {
return (String) getAttributeValue(OUTPUT_NAME);
}//getOutputName()//
/**
* Sets the outputName value.
* @param outputName The outputName value.
*/
public void setOutputName(String outputName) {
setAttributeValue(OUTPUT_NAME, outputName);
}//setOutputName()//
/**
* Gets the fileMetadataSet value.
* @return The fileMetadataSet value.
*/
protected LiteHashSet getFileMetadataSet() {
return (LiteHashSet) getAttributeValue(FILE_METADATA_SET);
}//getFileMetadataSet()//
/**
* Gets the last used directory for selecting files to encrypt.
* @return The input directory path.
*/
public String getInputDirectory() {
return (String) getAttributeValue(INPUT_DIRECTORY);
}//getInputDirectory()//
/**
* Sets the last used directory for selecting files to encrypt.
* @param inputDirectory The input directory path.
*/
public void setInputDirectory(String inputDirectory) {
setAttributeValue(INPUT_DIRECTORY, inputDirectory);
}//setInputDirectory()//
}//EncryptViewController//