All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.gov.nationalarchives.droid.signatureFile.FFSignatureFile Maven / Gradle / Ivy

/*
 * The National Archives 2005-2006.  All rights reserved.
 * See Licence.txt for full licence details.
 *
 * Developed by:
 * Tessella Support Services plc
 * 3 Vineyard Chambers
 * Abingdon, OX14 3PX
 * United Kingdom
 * http://www.tessella.com
 *
 * Tessella/NPD/4305
 * PRONOM 4
 *
 * $Id: FFSignatureFile.java,v 1.6 2006/03/13 15:15:29 linb Exp $
 *
 * $Logger: FFSignatureFile.java,v $
 * Revision 1.6  2006/03/13 15:15:29  linb
 * Changed copyright holder from Crown Copyright to The National Archives.
 * Added reference to licence.txt
 * Changed dates to 2005-2006
 *
 * Revision 1.5  2006/02/07 17:16:22  linb
 * - Change fileReader to ByteReader in formal parameters of methods
 * - use new static constructors
 * - Add detection of if a filePath is a URL or not
 *
 * Revision 1.4  2006/02/07 12:34:57  gaur
 * Removed restriction on priority relationships so that they can be applied between any combination of generic and specific signatures (second recommit because of missing logging)
 *
 *
 * $History: FFSignatureFile.java $
 * 
 * *****************  Version 7  *****************
 * User: Walm         Date: 19/04/05   Time: 18:24
 * Updated in $/PRONOM4/FFIT_SOURCE/signatureFile
 * Provide initial values for version and dateCreated
 * 
 * *****************  Version 6  *****************
 * User: Walm         Date: 18/03/05   Time: 12:39
 * Updated in $/PRONOM4/FFIT_SOURCE/signatureFile
 * add some more exception handling
 * 
 * *****************  Version 5  *****************
 * User: Walm         Date: 15/03/05   Time: 14:39
 * Updated in $/PRONOM4/FFIT_SOURCE/signatureFile
 * fileReader class now holds reference to identificationFile object
 * 
 * *****************  Version 4  *****************
 * User: Mals         Date: 14/03/05   Time: 15:08
 * Updated in $/PRONOM4/FFIT_SOURCE/signatureFile
 * Takes into account of IdentificationFile objects in checkExtension
 * 
 * *****************  Version 3  *****************
 * User: Mals         Date: 14/03/05   Time: 14:30
 * Updated in $/PRONOM4/FFIT_SOURCE/signatureFile
 * runFileIdentification accepts IdentificationFile parameter
 *
 */
package uk.gov.nationalarchives.droid.signatureFile;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import uk.gov.nationalarchives.droid.base.DroidConstants;
import uk.gov.nationalarchives.droid.base.FileFormatHit;
import uk.gov.nationalarchives.droid.base.MessageDisplay;
import uk.gov.nationalarchives.droid.base.SimpleElement;
import uk.gov.nationalarchives.droid.binFileReader.ByteReader;

/**
 * holds details of a signature file and uses it to identify binary files
 * 
 * @author Martin Waller
 * @version 4.0.0
 */
public class FFSignatureFile extends SimpleElement {

	private String version = "";
	private String dateCreated = "";
	private FileFormatCollection fFcollection;
	private InternalSignatureCollection intSigs;

	public FFSignatureFile() {

	}

	public FFSignatureFile(Collection fcollection,
			Collection intSigs) {
		fFcollection = new FileFormatCollection();
		fFcollection.formats.addAll(fcollection);
		this.intSigs = new InternalSignatureCollection();
		this.intSigs.intSigs.addAll(intSigs);
	}

	public String getDateCreated() {
		return this.dateCreated;
	}

	public FileFormat getFileFormat(final int theIndex) {
		return (FileFormat) this.fFcollection.getFileFormats().get(theIndex);
	}

	public InternalSignature getInternalSignature(final int theIndex) {
		return this.intSigs.getInternalSignatures().get(theIndex);
	}

	public int getNumFileFormats() {
		return this.fFcollection.getFileFormats().size();
	}

	/* getters */
	public int getNumInternalSignatures() {
		return this.intSigs.getInternalSignatures().size();
	}

	public List getSignatures() {
		return this.intSigs.getInternalSignatures();
	}

	public String getVersion() {
		return this.version;
	}

	/**
	 * This method must be run after the signature file data has been read and
	 * before the FFSignatureFile class is used. It points internal signatures
	 * to the fileFormat objects they identify, and it ensures that the sequence
	 * fragments are in the correct order.
	 */
	public void prepareForUse() {
		setAllSignatureFileFormats();
		reorderAllSequenceFragments();
		reorderByteSequences();
	}

	/**
	 * Identify the current file
	 * 
	 * @param targetFile
	 *            The binary file to be identified
	 */
	public synchronized void runFileIdentification(final ByteReader targetFile) {

		final List signatureList = getSignatures();
		// record all positive identifications
		for (final InternalSignature internalSig : signatureList) {
			if (internalSig.isFileCompliant(targetFile)) {
				// File matches this internal signature
				targetFile.setPositiveIdent();
				for (int i = 0; i < internalSig.getNumFileFormats(); i++) {
					final FileFormatHit fileHit = new FileFormatHit(
							internalSig.getFileFormat(i),
							DroidConstants.HIT_TYPE_POSITIVE_GENERIC_OR_SPECIFIC,
							internalSig.isSpecific(), "");
					targetFile.addHit(fileHit);
				}
			}
		}

		// remove any hits for which there is a higher priority hit
		if (targetFile.getNumHits() > 1) {
			removeLowerPriorityHits(targetFile);
		}

		// if there are still no hits then classify as unidentified
		if (targetFile.getNumHits() == 0) {
			targetFile.setNoIdent();
		}
	}

	@Override
	public void setAttributeValue(final String name, final String value) {
		if (name.equals("Version")) {
			setVersion(value.trim());
		} else if (name.equals("DateCreated")) {
			setDateCreated(value);
		} else {
			MessageDisplay.unknownAttributeWarning(name, getElementName());
		}
	}

	/* setters */
	public void setFileFormatCollection(final FileFormatCollection coll) {
		this.fFcollection = coll;
	}

	public void setInternalSignatureCollection(
			final InternalSignatureCollection col3) {
		this.intSigs = col3;
	}

	/**
	 * Remove any hits for which there is a higher priority hit
	 * 
	 * @param targetFile
	 *            The binary file to be identified
	 */
	private void removeLowerPriorityHits(final ByteReader targetFile) {
		// loop through specific hits and list any hits which these have
		// priority over
		final List hitsToRemove = new ArrayList();
		for (int i = 0; i < targetFile.getNumHits(); i++) {
			for (int j = 0; j < targetFile.getHit(i).getFileFormat()
					.getNumHasPriorityOver(); j++) {
				final int formatID = targetFile.getHit(i).getFileFormat()
						.getHasPriorityOver(j);
				for (int k = 0; k < targetFile.getNumHits(); k++) { // loop
					// through
					// hits to
					// find any
					// for this
					// file
					// format
					if (targetFile.getHit(k).getFileFormat().getID() == formatID) {
						hitsToRemove.add(k); // use string
						// representation as
						// ArrayList won't
						// take integers
						break;
					}
				}
			}
		}
		// Create sorted array of indexes for hits to be removed
		final int[] indexesOfHits = new int[hitsToRemove.size()];
		int numHitsToRemove = 0;
		for (int i = 0; i < hitsToRemove.size(); i++) { // loop through unsorted
			// list of hits to be
			// removed
			int j = numHitsToRemove;
			final int indexOfHit = hitsToRemove.get(i);
			while ((j > 0) && (indexesOfHits[j - 1] > indexOfHit)) {
				indexesOfHits[j] = indexesOfHits[j - 1];
				--j;
			}
			indexesOfHits[j] = indexOfHit;
			++numHitsToRemove;
		}
		// Delete hits in decreasing index order, ignorinmg any repetitions
		for (int i = indexesOfHits.length - 1; i >= 0; i--) {
			if (i == (indexesOfHits.length - 1)) {
				targetFile.removeHit(indexesOfHits[i]);
			} else if (indexesOfHits[i] != indexesOfHits[i + 1]) {
				targetFile.removeHit(indexesOfHits[i]);
			}
		}

	}

	/**
	 * Run prepareSeqFragments on all subSequences within all ByteSequences
	 * within all internalSignatures.
	 */
	private void reorderAllSequenceFragments() {
		for (int iSig = 0; iSig < getNumInternalSignatures(); iSig++) {
			for (int iBS = 0; iBS < getInternalSignature(iSig)
					.getNumByteSequences(); iBS++) {
				for (int iSS = 0; iSS < getInternalSignature(iSig)
						.getByteSequence(iBS).getNumSubSequences(); iSS++) {
					getInternalSignature(iSig).getByteSequence(iBS)
							.getSubSequence(iSS).prepareSeqFragments();
				}
			}
		}
	}

	/**
	 * Ensure that the BOFs and EOFs are searched for before the variable
	 * position byte sequences
	 * 
	 */
	private void reorderByteSequences() {
		for (int iSig = 0; iSig < getNumInternalSignatures(); iSig++) {
			final InternalSignature sig = getInternalSignature(iSig);
			final List BOFoffsetByteSequences = new ArrayList();
			final List EOFoffsetByteSequences = new ArrayList();
			final List variableByteSequences = new ArrayList();
			for (int iBS = 0; iBS < sig.getNumByteSequences(); iBS++) {
				final ByteSequence seq = sig.getByteSequence(iBS);
				if (seq.getReference().startsWith("BOF")) {
					BOFoffsetByteSequences.add(seq);
				}
				if (seq.getReference().startsWith("EOF")) {
					EOFoffsetByteSequences.add(seq);
				} else {
					variableByteSequences.add(seq);
				}
			}
			final List byteSequences = new ArrayList();
			byteSequences.addAll(BOFoffsetByteSequences);
			byteSequences.addAll(EOFoffsetByteSequences);
			byteSequences.addAll(variableByteSequences);
			sig.resetByteSequences(byteSequences);
		}
	}

	/**
	 * Points all internal signatures to the fileFormat objects they identify.
	 */
	private void setAllSignatureFileFormats() {
		for (int iFormat = 0; iFormat < getNumFileFormats(); iFormat++) { // loop
			// through
			// file
			// formats
			for (int iFileSig = 0; iFileSig < getFileFormat(iFormat)
					.getNumInternalSignatures(); iFileSig++) { // loop through
				// internal
				// signatures
				// for each file
				// format
				final int iFileSigID = getFileFormat(iFormat)
						.getInternalSignatureID(iFileSig);
				// loop through all internal signatures to find one with a
				// matching ID
				for (int iIntSig = 0; iIntSig < getNumInternalSignatures(); iIntSig++) {
					if (getInternalSignature(iIntSig).getID() == iFileSigID) {
						getInternalSignature(iIntSig).addFileFormat(
								getFileFormat(iFormat));
						break;
					}
				}
			}
		}
	}

	private void setDateCreated(final String dc) {
		this.dateCreated = dc;
	}

	private void setVersion(final String vers) {
		this.version = vers;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy