From e9469fe5a0427e4b9225f2563da1bf4ecd7781bb Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Sun, 11 Mar 2018 15:13:24 -0500 Subject: [PATCH] Merging in changes from applecommander2 project. API did change a bit on HeaderBlock. --- .../com/webcodepro/shrinkit/HeaderBlock.java | 60 +++++++++++++++++-- .../shrinkit/MasterHeaderBlock.java | 3 +- .../com/webcodepro/shrinkit/ThreadFormat.java | 17 ++++-- .../io/LittleEndianByteInputStream.java | 3 +- .../webcodepro/shrinkit/HeaderBlockTest.java | 2 +- .../io/LittleEndianByteInputStreamTest.java | 36 +++++------ .../webcodepro/shrinkit/io/NufxLzwTest.java | 2 +- 7 files changed, 93 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java b/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java index 4bbf2f5..b7e6f3d 100644 --- a/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java +++ b/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java @@ -46,8 +46,9 @@ public class HeaderBlock { */ public HeaderBlock(LittleEndianByteInputStream bs) throws IOException { int type = bs.seekFileType(4); - if (type == 0) + if (type == 0) { throw new IOException("Unable to decode this archive."); // FIXME - NLS + } headerCrc = bs.readWord(); attribCount = bs.readWord(); versionNumber = bs.readWord(); @@ -82,6 +83,9 @@ public class HeaderBlock { if (length > 0) { rawFilename = new String(bs.readBytes(length)); } + if (rawFilename == null) { + rawFilename = "Unknown"; + } } /** * Read in all data threads. All ThreadRecords are read and then @@ -128,15 +132,21 @@ public class HeaderBlock { /** * 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 { - return findThreadRecord(ThreadKind.DATA_FORK); + public ThreadRecord getDataForkThreadRecord() { + ThreadRecord thread = findThreadRecord(ThreadKind.DATA_FORK); + if (thread == null) { + thread = findThreadRecord(ThreadKind.DISK_IMAGE); + } + return thread; } /** * Get the resource fork. */ - public ThreadRecord getResourceForkInputStream() throws IOException { + public ThreadRecord getResourceForkThreadRecord() { return findThreadRecord(ThreadKind.RESOURCE_FORK); } @@ -149,6 +159,48 @@ public class HeaderBlock { } 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 diff --git a/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java b/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java index 7568820..27c57d8 100644 --- a/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java +++ b/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java @@ -38,8 +38,9 @@ public class MasterHeaderBlock { bs.readBytes(127 - ByteConstants.NUFILE_ID.length); headerOffset = 128; 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 + } fileType = bs.seekFileType(); } if (!(fileType == NuFileArchive.NUFILE_ARCHIVE)) { diff --git a/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java b/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java index 97f9f82..6f5dccd 100644 --- a/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java +++ b/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java @@ -5,19 +5,28 @@ package com.webcodepro.shrinkit; * @author robgreene@users.sourceforge.net */ public enum ThreadFormat { - UNCOMPRESSED(0x0000), HUFFMAN_SQUEEZE(0x0001), DYNAMIC_LZW1(0x0002), DYNAMIC_LZW2(0x0003), - UNIX_12BIT_COMPRESS(0x0004), UNIX_16BIT_COMPRESS(0x0005); + UNCOMPRESSED(0x0000, "Uncompressed"), + 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 */ - 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.name = name; } public int getThreadFormat() { return threadFormat; } + public String getName() { + return name; + } /** * Find the ThreadFormat. diff --git a/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java b/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java index 65f21b9..9992476 100644 --- a/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java +++ b/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java @@ -63,8 +63,9 @@ public class LittleEndianByteInputStream extends InputStream implements ByteCons int read = inputStream.read(data); bytesRead+= read; // 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; + } if (read < bytes) { throw new IOException("Requested " + bytes + " bytes, but " + read + " read"); } diff --git a/src/test/java/com/webcodepro/shrinkit/HeaderBlockTest.java b/src/test/java/com/webcodepro/shrinkit/HeaderBlockTest.java index adc0182..a2c196c 100644 --- a/src/test/java/com/webcodepro/shrinkit/HeaderBlockTest.java +++ b/src/test/java/com/webcodepro/shrinkit/HeaderBlockTest.java @@ -148,6 +148,6 @@ public class HeaderBlockTest { 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()); Assert.assertEquals(0x0000, b.getOptionSize()); - Assert.assertNull(b.getRawFilename()); + Assert.assertEquals("Unknown", b.getRawFilename()); } } diff --git a/src/test/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStreamTest.java b/src/test/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStreamTest.java index 714c786..cc5e042 100644 --- a/src/test/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStreamTest.java +++ b/src/test/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStreamTest.java @@ -7,6 +7,8 @@ import java.util.GregorianCalendar; import org.junit.Assert; import org.junit.Test; +import com.webcodepro.shrinkit.NuFileArchive; + /** * Exercise the LittleEndianByteInputStream class. * @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 -// public void testCheckNuFileId() throws IOException { -// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 }); -// Assert.assertTrue(NuFileArchive.bs.checkNuFileId()); -// Assert.assertEquals(6, bs.getTotalBytesRead()); -// bs = new LittleEndianByteInputStream("NotNuFile".getBytes()); -// Assert.assertFalse(bs.checkNuFileId()); -// } -// This methods got removed at some point but nobody updated the unit tests. Bad developer! -// @Test -// public void testCheckNuFxId() throws IOException { -// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 }); -// Assert.assertTrue(bs.checkNuFxId()); -// Assert.assertEquals(4, bs.getTotalBytesRead()); -// bs = new LittleEndianByteInputStream("NotNuFx".getBytes()); -// Assert.assertFalse(bs.checkNuFxId()); -// } + @Test + public void testCheckNuFileId() throws IOException { + try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream( + new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 })) { + Assert.assertEquals(NuFileArchive.NUFILE_ARCHIVE, bs.seekFileType(6)); + Assert.assertEquals(6, bs.getTotalBytesRead()); + } + } + @Test + public void testCheckNuFxId() throws IOException { + try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream( + new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 })) { + Assert.assertEquals(NuFileArchive.NUFX_ARCHIVE, bs.seekFileType(4)); + Assert.assertEquals(4, bs.getTotalBytesRead()); + } + } @Test public void testReadWord() throws IOException { try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })) { diff --git a/src/test/java/com/webcodepro/shrinkit/io/NufxLzwTest.java b/src/test/java/com/webcodepro/shrinkit/io/NufxLzwTest.java index b2a1e5b..0699fb8 100644 --- a/src/test/java/com/webcodepro/shrinkit/io/NufxLzwTest.java +++ b/src/test/java/com/webcodepro/shrinkit/io/NufxLzwTest.java @@ -60,7 +60,7 @@ public class NufxLzwTest extends TestBase { byte[] actual = null; for (HeaderBlock header : headers) { if (archiveFile.equals(header.getFilename())) { - ThreadRecord r = header.getDataForkInputStream(); + ThreadRecord r = header.getDataForkThreadRecord(); long bytes = r.getThreadEof(); ByteArrayOutputStream buf = new ByteArrayOutputStream(); InputStream is = r.getInputStream();