Added ability to get the CRC-16 from a ByteSource and for the MasterHeaderBlock to validate its CRC-16.

This commit is contained in:
Robert Greene 2008-06-17 04:09:56 +00:00
parent 6c241ea036
commit 4371c7a730
5 changed files with 69 additions and 9 deletions

View File

@ -13,6 +13,8 @@ import java.util.GregorianCalendar;
*/
public class ByteSource implements ByteConstants {
private InputStream inputStream;
private long bytesRead = 0;
private CRC16 crc = new CRC16();
/**
* Construct a ByteSource from an InputStream.
@ -33,7 +35,12 @@ public class ByteSource implements ByteConstants {
* Note that an unsigned byte needs to be returned in a larger container (ie, a short or int or long).
*/
public int read() throws IOException {
return inputStream.read();
int b = inputStream.read();
if (b != -1) {
crc.update(b);
bytesRead++;
}
return b;
}
/**
* Get the next byte and fail if we are at EOF.
@ -51,9 +58,11 @@ public class ByteSource implements ByteConstants {
public byte[] readBytes(int bytes) throws IOException {
byte[] data = new byte[bytes];
int read = inputStream.read(data);
bytesRead+= read;
if (read < bytes) {
throw new IOException("Requested " + bytes + " bytes, but " + read + " read");
}
crc.update(data);
return data;
}
@ -102,4 +111,24 @@ public class ByteSource implements ByteConstants {
data[TIMEREC_HOUR], data[TIMEREC_MINUTE], data[TIMEREC_SECOND]);
return gc.getTime();
}
/**
* Reset the CRC-16 to $0000.
*/
public void resetCrc() {
crc.reset();
}
/**
* Get the current CRC-16 value.
*/
public long getCrcValue() {
return crc.getValue();
}
/**
* Answer with the total number of bytes read.
*/
public long getTotalBytesRead() {
return bytesRead;
}
}

View File

@ -17,6 +17,7 @@ import java.util.Date;
public class MasterHeaderBlock {
private static final int MASTER_HEADER_LENGTH = 48;
private int masterCrc;
private boolean validCrc;
private long totalRecords;
private Date archiveCreateWhen;
private Date archiveModWhen;
@ -25,15 +26,11 @@ public class MasterHeaderBlock {
/**
* Create the Master Header Block, based on the ByteSource.
* To avoid byte counting, we read in the fixed size header
* and then work our way through the data. When we are done,
* that data is thrown away, and we don't need to ensure
* that we've read a consistent number of bytes.
*/
public MasterHeaderBlock(ByteSource bs) throws IOException {
bs = new ByteSource(bs.readBytes(MASTER_HEADER_LENGTH));
bs.checkNuFileId();
masterCrc = bs.readWord();
bs.resetCrc(); // CRC is computed from this point to the end of the header
totalRecords = bs.readLong();
archiveCreateWhen = bs.readDate();
archiveModWhen = bs.readDate();
@ -44,6 +41,11 @@ public class MasterHeaderBlock {
} else {
masterEof = -1;
}
// Read whatever remains of the fixed size header
while (bs.getTotalBytesRead() < MASTER_HEADER_LENGTH) {
bs.readByte();
}
validCrc = (masterCrc == bs.getCrcValue());
}
// GENERATED CODE
@ -84,4 +86,7 @@ public class MasterHeaderBlock {
public void setMasterEof(long masterEof) {
this.masterEof = masterEof;
}
public boolean isValidCrc() {
return validCrc;
}
}

View File

@ -17,6 +17,7 @@ public class ByteSourceTest extends TestCase {
ByteSource bs = new ByteSource("a".getBytes());
assertEquals('a', bs.read());
assertEquals(-1, bs.read());
assertEquals(1, bs.getTotalBytesRead());
}
public void testReadB() throws IOException {
// Just to ensure we can get more than one byte...
@ -27,6 +28,7 @@ public class ByteSourceTest extends TestCase {
assertEquals('l', bs.read());
assertEquals('o', bs.read());
assertEquals(-1, bs.read());
assertEquals(5, bs.getTotalBytesRead());
}
public void testReadBytesInt() throws IOException {
// Ensure we read the requested data.
@ -34,6 +36,7 @@ public class ByteSourceTest extends TestCase {
assertEquals("Hello", new String(bs.readBytes(5)));
assertEquals("World", new String(bs.readBytes(5)));
assertEquals(-1, bs.read());
assertEquals(10, bs.getTotalBytesRead());
}
public void textReadBytesIntError() {
// Ensure that we fail appropriately
@ -43,17 +46,20 @@ public class ByteSourceTest extends TestCase {
fail();
} catch (IOException ex) {
assertTrue(true); // Expected
assertEquals(2, bs.getTotalBytesRead());
}
}
public void testCheckNuFileId() throws IOException {
ByteSource bs = new ByteSource(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 });
assertTrue(bs.checkNuFileId());
assertEquals(6, bs.getTotalBytesRead());
bs = new ByteSource("NotNuFile".getBytes());
assertFalse(bs.checkNuFileId());
}
public void testCheckNuFxId() throws IOException {
ByteSource bs = new ByteSource(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 });
assertTrue(bs.checkNuFxId());
assertEquals(4, bs.getTotalBytesRead());
bs = new ByteSource("NotNuFx".getBytes());
assertFalse(bs.checkNuFxId());
}
@ -61,18 +67,22 @@ public class ByteSourceTest extends TestCase {
ByteSource bs = new ByteSource(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 });
assertEquals(0x0201, bs.readWord());
assertEquals(0x0403, bs.readWord());
assertEquals(4, bs.getTotalBytesRead());
}
public void testReadWordHighBitSet() throws IOException {
ByteSource bs = new ByteSource(new byte[] { (byte)0xff, (byte)0xff });
assertEquals(0xffff, bs.readWord());
assertEquals(2, bs.getTotalBytesRead());
}
public void testReadLong() throws IOException {
ByteSource bs = new ByteSource(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 });
assertEquals(0x04030201, bs.readLong());
assertEquals(4, bs.getTotalBytesRead());
}
public void testReadLongHighBitSet() throws IOException {
ByteSource bs = new ByteSource(new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff });
assertEquals(0xffffffffL, bs.readLong());
assertEquals(4, bs.getTotalBytesRead());
}
public void testReadDate() throws IOException {
ByteSource bs = new ByteSource(new byte[] {
@ -84,11 +94,13 @@ public class ByteSourceTest extends TestCase {
assertEquals(new GregorianCalendar(1988, Calendar.OCTOBER, 22, 1, 10, 0).getTime(), bs.readDate());
assertEquals(new GregorianCalendar(1988, Calendar.NOVEMBER, 17, 11, 16, 0).getTime(), bs.readDate());
assertEquals(new GregorianCalendar(1988, Calendar.OCTOBER, 22, 13, 12, 0).getTime(), bs.readDate());
assertEquals(24, bs.getTotalBytesRead());
}
public void testReadNullDate() throws IOException {
ByteSource bs = new ByteSource(new byte[] {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // null date
});
assertNull(bs.readDate());
assertEquals(8, bs.getTotalBytesRead());
}
}

View File

@ -11,7 +11,7 @@ import junit.framework.TestCase;
* @author robgreene@users.sourceforge.net
*/
public class MasterHeaderBlockTest extends TestCase {
public void test1() throws IOException {
public void testWithValidCrc() throws IOException {
ByteSource bs = new ByteSource(new byte[] {
0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5, (byte)0xdc, 0x1b,
0x2d, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x14, 0x5f,
@ -28,5 +28,19 @@ public class MasterHeaderBlockTest extends TestCase {
assertEquals(new ByteSource(new byte[] {0x29, 0x0d, 0x14, 0x5f, 0x08, 0x07, 0x01, 0x04}).readDate(), b.getArchiveModWhen());
assertEquals(0x01, b.getMasterVersion());
assertEquals(0x1acae, b.getMasterEof());
assertTrue(b.isValidCrc());
}
public void testWithInvalidCrc() throws IOException {
ByteSource bs = new ByteSource(new byte[] {
0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5, 0x00, 0x00, // <-- Bad CRC!
0x2d, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x14, 0x5f,
0x08, 0x07, 0x30, 0x04, 0x29, 0x0d, 0x14, 0x5f,
0x08, 0x07, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xae, (byte)0xac,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
});
MasterHeaderBlock b = new MasterHeaderBlock(bs);
assertFalse(b.isValidCrc());
}
}

View File

@ -33,9 +33,9 @@ public class NuFileArchiveTest extends TestCase {
MasterHeaderBlock m = a.getMasterHeaderBlock();
System.out.printf("Master Header Block\n==================\n"
+ "master_crc=$%x\ntotal_records=%d\narchive_create_when=%tc\narchive_mod_when=%tc\n"
+ "master_version=%d\nmaster_eof=$%x\n\n",
+ "master_version=%d\nmaster_eof=$%x\nisValidCrc = %b\n\n",
m.getMasterCrc(), m.getTotalRecords(), m.getArchiveCreateWhen(), m.getArchiveModWhen(),
m.getMasterVersion(), m.getMasterEof());
m.getMasterVersion(), m.getMasterEof(), m.isValidCrc());
for (HeaderBlock b : a.getHeaderBlocks()) {
System.out.printf("\tHeader Block\n\t============\n");
System.out.printf("\theader_crc=$%x\n\tattrib_count=%d\n\tversion_number=%d\n\ttotal_threads=%d\n\t"