Merging in changes from applecommander2 project. API did change a bit on

HeaderBlock.
This commit is contained in:
Rob Greene 2018-03-11 15:13:24 -05:00
parent 8f4ca7fb9f
commit e9469fe5a0
7 changed files with 93 additions and 30 deletions

View File

@ -46,8 +46,9 @@ public class HeaderBlock {
*/ */
public HeaderBlock(LittleEndianByteInputStream bs) throws IOException { public HeaderBlock(LittleEndianByteInputStream bs) throws IOException {
int type = bs.seekFileType(4); int type = bs.seekFileType(4);
if (type == 0) if (type == 0) {
throw new IOException("Unable to decode this archive."); // FIXME - NLS throw new IOException("Unable to decode this archive."); // FIXME - NLS
}
headerCrc = bs.readWord(); headerCrc = bs.readWord();
attribCount = bs.readWord(); attribCount = bs.readWord();
versionNumber = bs.readWord(); versionNumber = bs.readWord();
@ -82,6 +83,9 @@ public class HeaderBlock {
if (length > 0) { if (length > 0) {
rawFilename = new String(bs.readBytes(length)); rawFilename = new String(bs.readBytes(length));
} }
if (rawFilename == null) {
rawFilename = "Unknown";
}
} }
/** /**
* Read in all data threads. All ThreadRecords are read and then * Read in all data threads. All ThreadRecords are read and then
@ -128,15 +132,21 @@ public class HeaderBlock {
/** /**
* Get the data fork. * Get the data fork.
* Note that this first searches the data fork and then searches for a disk image;
* this may not be correct behavior.
*/ */
public ThreadRecord getDataForkInputStream() throws IOException { public ThreadRecord getDataForkThreadRecord() {
return findThreadRecord(ThreadKind.DATA_FORK); ThreadRecord thread = findThreadRecord(ThreadKind.DATA_FORK);
if (thread == null) {
thread = findThreadRecord(ThreadKind.DISK_IMAGE);
}
return thread;
} }
/** /**
* Get the resource fork. * Get the resource fork.
*/ */
public ThreadRecord getResourceForkInputStream() throws IOException { public ThreadRecord getResourceForkThreadRecord() {
return findThreadRecord(ThreadKind.RESOURCE_FORK); return findThreadRecord(ThreadKind.RESOURCE_FORK);
} }
@ -149,6 +159,48 @@ public class HeaderBlock {
} }
return null; return null;
} }
// HELPER METHODS
/**
* Helper method to determine the file system separator.
* Due to some oddities, breaking apart by byte value...
*/
public String getFileSystemSeparator() {
switch (getFileSysInfo() & 0xff) {
case 0xaf:
case 0x2f:
return "/";
case 0x3a:
case 0xba:
case 0x3f: // Note that $3F is per the documentation(!)
return ":";
case 0x5c:
case 0xdc:
return "\\";
default:
return "";
}
}
public long getUncompressedSize() {
long size = 0;
for (ThreadRecord r : threads) {
if (r.getThreadClass() == ThreadClass.DATA) {
size+= r.getThreadEof();
}
}
return size;
}
public long getCompressedSize() {
long size = 0;
for (ThreadRecord r : threads) {
if (r.getThreadClass() == ThreadClass.DATA) {
size+= r.getCompThreadEof();
}
}
return size;
}
// GENERATED CODE // GENERATED CODE

View File

@ -38,8 +38,9 @@ public class MasterHeaderBlock {
bs.readBytes(127 - ByteConstants.NUFILE_ID.length); bs.readBytes(127 - ByteConstants.NUFILE_ID.length);
headerOffset = 128; headerOffset = 128;
int count = bs.read(); int count = bs.read();
if (count != 0) if (count != 0) {
throw new IOException("This is actually a Binary II archive with multiple files in it."); // FIXME - NLS throw new IOException("This is actually a Binary II archive with multiple files in it."); // FIXME - NLS
}
fileType = bs.seekFileType(); fileType = bs.seekFileType();
} }
if (!(fileType == NuFileArchive.NUFILE_ARCHIVE)) { if (!(fileType == NuFileArchive.NUFILE_ARCHIVE)) {

View File

@ -5,19 +5,28 @@ package com.webcodepro.shrinkit;
* @author robgreene@users.sourceforge.net * @author robgreene@users.sourceforge.net
*/ */
public enum ThreadFormat { public enum ThreadFormat {
UNCOMPRESSED(0x0000), HUFFMAN_SQUEEZE(0x0001), DYNAMIC_LZW1(0x0002), DYNAMIC_LZW2(0x0003), UNCOMPRESSED(0x0000, "Uncompressed"),
UNIX_12BIT_COMPRESS(0x0004), UNIX_16BIT_COMPRESS(0x0005); HUFFMAN_SQUEEZE(0x0001, "Huffman Squeeze"),
DYNAMIC_LZW1(0x0002, "Dynamic LZW/1"),
DYNAMIC_LZW2(0x0003, "Dynamic LZW/2"),
UNIX_12BIT_COMPRESS(0x0004, "Unix 12-bit Compress"),
UNIX_16BIT_COMPRESS(0x0005, "Unix 16-bit Compress");
/** Associate the hex codes with the enum */ /** Associate the hex codes with the enum */
private int threadFormat; private final int threadFormat;
private final String name;
private ThreadFormat(int threadFormat) { private ThreadFormat(int threadFormat, String name) {
this.threadFormat = threadFormat; this.threadFormat = threadFormat;
this.name = name;
} }
public int getThreadFormat() { public int getThreadFormat() {
return threadFormat; return threadFormat;
} }
public String getName() {
return name;
}
/** /**
* Find the ThreadFormat. * Find the ThreadFormat.

View File

@ -63,8 +63,9 @@ public class LittleEndianByteInputStream extends InputStream implements ByteCons
int read = inputStream.read(data); int read = inputStream.read(data);
bytesRead+= read; bytesRead+= read;
// In the case where we have a zero-byte file, 'read' stays at -1, which is not correct. Fix it. // In the case where we have a zero-byte file, 'read' stays at -1, which is not correct. Fix it.
if ((bytes == 0) && (read == -1)) if ((bytes == 0) && (read == -1)) {
read = 0; read = 0;
}
if (read < bytes) { if (read < bytes) {
throw new IOException("Requested " + bytes + " bytes, but " + read + " read"); throw new IOException("Requested " + bytes + " bytes, but " + read + " read");
} }

View File

@ -148,6 +148,6 @@ public class HeaderBlockTest {
checkDate(new byte[] {0x00,0x11,0x11,0x5e,0x13,0x01,0x00,0x01}, b.getModWhen()); checkDate(new byte[] {0x00,0x11,0x11,0x5e,0x13,0x01,0x00,0x01}, b.getModWhen());
checkDate(new byte[] {0x38,0x0c,0x14,0x5f,0x08,0x07,0x00,0x04}, b.getArchiveWhen()); checkDate(new byte[] {0x38,0x0c,0x14,0x5f,0x08,0x07,0x00,0x04}, b.getArchiveWhen());
Assert.assertEquals(0x0000, b.getOptionSize()); Assert.assertEquals(0x0000, b.getOptionSize());
Assert.assertNull(b.getRawFilename()); Assert.assertEquals("Unknown", b.getRawFilename());
} }
} }

View File

@ -7,6 +7,8 @@ import java.util.GregorianCalendar;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.webcodepro.shrinkit.NuFileArchive;
/** /**
* Exercise the LittleEndianByteInputStream class. * Exercise the LittleEndianByteInputStream class.
* @author robgreene@users.sourceforge.net * @author robgreene@users.sourceforge.net
@ -56,24 +58,22 @@ public class LittleEndianByteInputStreamTest {
} }
} }
} }
// This methods got removed at some point but nobody updated the unit tests. Bad developer! @Test
// @Test public void testCheckNuFileId() throws IOException {
// public void testCheckNuFileId() throws IOException { try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(
// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 }); new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 })) {
// Assert.assertTrue(NuFileArchive.bs.checkNuFileId()); Assert.assertEquals(NuFileArchive.NUFILE_ARCHIVE, bs.seekFileType(6));
// Assert.assertEquals(6, bs.getTotalBytesRead()); Assert.assertEquals(6, bs.getTotalBytesRead());
// bs = new LittleEndianByteInputStream("NotNuFile".getBytes()); }
// Assert.assertFalse(bs.checkNuFileId()); }
// } @Test
// This methods got removed at some point but nobody updated the unit tests. Bad developer! public void testCheckNuFxId() throws IOException {
// @Test try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(
// public void testCheckNuFxId() throws IOException { new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 })) {
// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 }); Assert.assertEquals(NuFileArchive.NUFX_ARCHIVE, bs.seekFileType(4));
// Assert.assertTrue(bs.checkNuFxId()); Assert.assertEquals(4, bs.getTotalBytesRead());
// Assert.assertEquals(4, bs.getTotalBytesRead()); }
// bs = new LittleEndianByteInputStream("NotNuFx".getBytes()); }
// Assert.assertFalse(bs.checkNuFxId());
// }
@Test @Test
public void testReadWord() throws IOException { public void testReadWord() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })) { try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })) {

View File

@ -60,7 +60,7 @@ public class NufxLzwTest extends TestBase {
byte[] actual = null; byte[] actual = null;
for (HeaderBlock header : headers) { for (HeaderBlock header : headers) {
if (archiveFile.equals(header.getFilename())) { if (archiveFile.equals(header.getFilename())) {
ThreadRecord r = header.getDataForkInputStream(); ThreadRecord r = header.getDataForkThreadRecord();
long bytes = r.getThreadEof(); long bytes = r.getThreadEof();
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();
InputStream is = r.getInputStream(); InputStream is = r.getInputStream();