2008-06-16 03:37:52 +00:00
|
|
|
package com.webcodepro.shrinkit;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.Date;
|
|
|
|
|
2008-06-22 23:57:49 +00:00
|
|
|
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
|
|
|
|
|
2008-06-16 03:37:52 +00:00
|
|
|
/**
|
|
|
|
* The Master Header Block contains information about the entire
|
|
|
|
* ShrinkIt archive.
|
|
|
|
* <p>
|
|
|
|
* Note that we need to support multiple versions of the NuFX
|
|
|
|
* archive format. Some details may be invalid, depending on
|
|
|
|
* version, and those are documented in the getter methods.
|
|
|
|
*
|
|
|
|
* @author robgreene@users.sourceforge.net
|
|
|
|
* @see http://www.nulib.com/library/FTN.e08002.htm
|
|
|
|
*/
|
|
|
|
public class MasterHeaderBlock {
|
|
|
|
private static final int MASTER_HEADER_LENGTH = 48;
|
|
|
|
private int masterCrc;
|
2008-06-17 04:09:56 +00:00
|
|
|
private boolean validCrc;
|
2008-06-16 03:37:52 +00:00
|
|
|
private long totalRecords;
|
|
|
|
private Date archiveCreateWhen;
|
|
|
|
private Date archiveModWhen;
|
|
|
|
private int masterVersion;
|
|
|
|
private long masterEof;
|
2012-06-27 04:09:16 +00:00
|
|
|
private byte[] nuFileId = {0,0,0,0,0,0};
|
|
|
|
|
2008-06-16 03:37:52 +00:00
|
|
|
/**
|
2008-06-22 23:57:49 +00:00
|
|
|
* Create the Master Header Block, based on the LittleEndianByteInputStream.
|
2008-06-16 03:37:52 +00:00
|
|
|
*/
|
2008-06-22 23:57:49 +00:00
|
|
|
public MasterHeaderBlock(LittleEndianByteInputStream bs) throws IOException {
|
2012-06-27 04:09:16 +00:00
|
|
|
int headerOffset = 0;
|
|
|
|
nuFileId = bs.readBytes(6);
|
|
|
|
|
|
|
|
if (checkId(nuFileId,BXY_ID)) {
|
|
|
|
bs.readBytes(127 - NUFILE_ID.length);
|
|
|
|
headerOffset = 128;
|
|
|
|
int count = bs.read();
|
|
|
|
if (count != 0)
|
|
|
|
throw new IOException("This is actually a Binary II archive with multiple files in it.");
|
|
|
|
nuFileId = bs.readBytes(6);
|
|
|
|
}
|
|
|
|
if (!checkId(nuFileId,NUFILE_ID)) {
|
|
|
|
throw new IOException("Unable to decode this archive.");
|
|
|
|
}
|
2008-06-16 03:37:52 +00:00
|
|
|
masterCrc = bs.readWord();
|
2008-06-17 04:09:56 +00:00
|
|
|
bs.resetCrc(); // CRC is computed from this point to the end of the header
|
2008-06-16 03:37:52 +00:00
|
|
|
totalRecords = bs.readLong();
|
|
|
|
archiveCreateWhen = bs.readDate();
|
|
|
|
archiveModWhen = bs.readDate();
|
|
|
|
masterVersion = bs.readWord();
|
|
|
|
if (masterVersion > 0) {
|
|
|
|
bs.readBytes(8); // documented to be null, but we don't care
|
|
|
|
masterEof = bs.readLong();
|
|
|
|
} else {
|
|
|
|
masterEof = -1;
|
|
|
|
}
|
2008-06-17 04:09:56 +00:00
|
|
|
// Read whatever remains of the fixed size header
|
2012-06-27 04:09:16 +00:00
|
|
|
while (bs.getTotalBytesRead() < MASTER_HEADER_LENGTH + headerOffset) {
|
2008-06-17 04:09:56 +00:00
|
|
|
bs.readByte();
|
|
|
|
}
|
|
|
|
validCrc = (masterCrc == bs.getCrcValue());
|
2008-06-16 03:37:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GENERATED CODE
|
|
|
|
|
|
|
|
public int getMasterCrc() {
|
|
|
|
return masterCrc;
|
|
|
|
}
|
|
|
|
public void setMasterCrc(int masterCrc) {
|
|
|
|
this.masterCrc = masterCrc;
|
|
|
|
}
|
|
|
|
public long getTotalRecords() {
|
|
|
|
return totalRecords;
|
|
|
|
}
|
|
|
|
public void setTotalRecords(long totalRecords) {
|
|
|
|
this.totalRecords = totalRecords;
|
|
|
|
}
|
|
|
|
public Date getArchiveCreateWhen() {
|
|
|
|
return archiveCreateWhen;
|
|
|
|
}
|
|
|
|
public void setArchiveCreateWhen(Date archiveCreateWhen) {
|
|
|
|
this.archiveCreateWhen = archiveCreateWhen;
|
|
|
|
}
|
|
|
|
public Date getArchiveModWhen() {
|
|
|
|
return archiveModWhen;
|
|
|
|
}
|
|
|
|
public void setArchiveModWhen(Date archiveModWhen) {
|
|
|
|
this.archiveModWhen = archiveModWhen;
|
|
|
|
}
|
|
|
|
public int getMasterVersion() {
|
|
|
|
return masterVersion;
|
|
|
|
}
|
|
|
|
public void setMasterVersion(int masterVersion) {
|
|
|
|
this.masterVersion = masterVersion;
|
|
|
|
}
|
|
|
|
public long getMasterEof() {
|
|
|
|
return masterEof;
|
|
|
|
}
|
|
|
|
public void setMasterEof(long masterEof) {
|
|
|
|
this.masterEof = masterEof;
|
|
|
|
}
|
2008-06-17 04:09:56 +00:00
|
|
|
public boolean isValidCrc() {
|
|
|
|
return validCrc;
|
|
|
|
}
|
2012-06-27 04:09:16 +00:00
|
|
|
/**
|
|
|
|
* Test that the requested constant is present.
|
|
|
|
*/
|
|
|
|
private boolean checkId(byte[] data, byte[] constant) {
|
|
|
|
for (int i = 0; i < constant.length; i++){
|
|
|
|
if (data[i] != constant[i])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Master Header Block identifier "magic" bytes. */
|
|
|
|
public static final byte[] NUFILE_ID = { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 };
|
|
|
|
/** Header Block identifier "magic" bytes. */
|
|
|
|
public static final byte[] NUFX_ID = { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 };
|
|
|
|
/** Binay II identifier "magic" bytes. */
|
|
|
|
public static final byte[] BXY_ID = { 0x0a, 0x47, 0x4c };
|
|
|
|
|
2008-06-16 03:37:52 +00:00
|
|
|
}
|