diff --git a/build.gradle b/build.gradle
index 6c2e70e..ff87c5b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,16 +9,6 @@ repositories {
apply plugin: 'java'
apply plugin: 'application'
-ext {
- sourceCompatibility = '1.8'
- targetCompatibility = '1.8'
-
- swtVersion = "4.6.1"
- junitVersion = "4.12"
- antVersion = "1.8.2"
- commonsLang3Version = "3.7"
-}
-
mainClassName = 'com.webcodepro.applecommander.ui.AppleCommander'
version "${version}"
@@ -61,14 +51,18 @@ tasks.withType(Jar) {
'Implementation-Version': version
}
from('LICENSE', 'CONTRIB', 'TODO', 'VERSIONS')
+ doFirst {
+ // Pick and include ShrinkIt contents
+ from { configurations.runtime.collect { it.name.startsWith('ShrinkItArchive') ? zipTree(it) : 'fake' } }
+ }
}
dependencies {
+ compile "net.sf.applecommander:ShrinkItArchive:$shkVersion"
compileOnly "org.apache.ant:ant:$antVersion"
testCompile "junit:junit:$junitVersion"
testCompile "org.apache.commons:commons-lang3:$commonsLang3Version"
-
}
task acJar(type: Jar) {
diff --git a/gradle.properties b/gradle.properties
index 716c03b..af8fd29 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,3 +2,9 @@
# - Naming JAR file.
# - The build will insert this into a file that is read at run time as well.
version=1.4.0-BETA
+
+shkVersion=1.1.0
+swtVersion=4.6.1
+junitVersion=4.12
+antVersion=1.8.2
+commonsLang3Version=3.7
diff --git a/src/main/java/com/webcodepro/applecommander/storage/Disk.java b/src/main/java/com/webcodepro/applecommander/storage/Disk.java
index fb01ffc..9d9883d 100644
--- a/src/main/java/com/webcodepro/applecommander/storage/Disk.java
+++ b/src/main/java/com/webcodepro/applecommander/storage/Disk.java
@@ -212,7 +212,7 @@ public class Disk {
if (isSDK() || isSHK() || isBXY()) {
// If we have an SDK, unpack it and send along the byte array
// If we have a SHK, build a new disk and unpack the contents on to it
- diskImage = com.webcodepro.shrinkit.Utilities.unpackSHKFile(filename, startBlocks);
+ diskImage = com.webcodepro.applecommander.util.ShrinkItUtilities.unpackSHKFile(filename, startBlocks);
diskSize = diskImage.length;
// Since we don't want to overwrite their shrinkit with a raw ProDOS image,
// add a .po extension to it
diff --git a/src/main/java/com/webcodepro/shrinkit/Utilities.java b/src/main/java/com/webcodepro/applecommander/util/ShrinkItUtilities.java
similarity index 96%
rename from src/main/java/com/webcodepro/shrinkit/Utilities.java
rename to src/main/java/com/webcodepro/applecommander/util/ShrinkItUtilities.java
index 3229c87..6fc04dc 100644
--- a/src/main/java/com/webcodepro/shrinkit/Utilities.java
+++ b/src/main/java/com/webcodepro/applecommander/util/ShrinkItUtilities.java
@@ -1,4 +1,4 @@
-package com.webcodepro.shrinkit;
+package com.webcodepro.applecommander.util;
/*
* Copyright (C) 2012 by David Schmidt
@@ -34,7 +34,9 @@ import com.webcodepro.applecommander.storage.physical.ByteArrayImageLayout;
import com.webcodepro.applecommander.storage.physical.ImageOrder;
import com.webcodepro.applecommander.storage.physical.ProdosOrder;
import com.webcodepro.applecommander.ui.ac.Name;
-import com.webcodepro.applecommander.util.TextBundle;
+import com.webcodepro.shrinkit.HeaderBlock;
+import com.webcodepro.shrinkit.NuFileArchive;
+import com.webcodepro.shrinkit.ThreadRecord;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
/**
@@ -42,7 +44,7 @@ import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
*
* @author david__schmidt at users.sourceforge.net
*/
-public class Utilities
+public class ShrinkItUtilities
{
/**
* Interpret a NuFile/NuFX/Shrinkit archive as a full disk image.
diff --git a/src/main/java/com/webcodepro/shrinkit/CRC16.java b/src/main/java/com/webcodepro/shrinkit/CRC16.java
deleted file mode 100644
index 7ca20d6..0000000
--- a/src/main/java/com/webcodepro/shrinkit/CRC16.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.util.zip.Checksum;
-
-/**
- * Crc16: Calculate 16-bit Cyclic Redundancy Check.
- * License: GPL, incorporated by reference.
- *
- * @author John B. Matthews
- */
-public class CRC16 implements Checksum {
-
- /** CCITT polynomial: x^16 + x^12 + x^5 + 1 -> 0x1021 (1000000100001) */
- private static final int poly = 0x1021;
- private static final int[] table = new int[256];
- private int value = 0;
-
- static { // initialize static lookup table
- for (int i = 0; i < 256; i++) {
- int crc = i << 8;
- for (int j = 0; j < 8; j++) {
- if ((crc & 0x8000) == 0x8000) {
- crc = (crc << 1) ^ poly;
- } else {
- crc = (crc << 1);
- }
- }
- table[i] = crc & 0xffff;
- }
- }
-
- /**
- * Update 16-bit CRC.
- *
- * @param crc starting CRC value
- * @param bytes input byte array
- * @param off start offset to data
- * @param len number of bytes to process
- * @return 16-bit unsigned CRC
- */
- private int update(int crc, byte[] bytes, int off, int len) {
- for (int i = off; i < (off + len); i++) {
- int b = (bytes[i] & 0xff);
- crc = (table[((crc >> 8) & 0xff) ^ b] ^ (crc << 8)) & 0xffff;
- }
- return crc;
- }
-
- public static int[] getTable() {
- return table;
- }
-
- public long getValue() {
- return value;
- }
-
- public void reset() {
- value = 0;
- }
-
- /**
- * Update 16-bit CRC.
- *
- * @param b input byte
- */
- public void update(int b) {
- byte[] ba = { (byte) (b & 0xff) };
- value = update(value, ba, 0, 1);
- }
-
- /**
- * Update 16-bit CRC.
- *
- * @param b input byte array
- */
- public void update(byte[] b) {
- value = update(value, b, 0, b.length);
- }
-
- /**
- * Update 16-bit CRC.
- *
- * @param b input byte array
- * @param off starting offset to data
- * @param len number of bytes to process
- */
- public void update(byte[] b, int off, int len) {
- value = update(value, b, off, len);
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java b/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java
deleted file mode 100644
index a76106a..0000000
--- a/src/main/java/com/webcodepro/shrinkit/HeaderBlock.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
-
-/**
- * The Header Block contains information and content
- * about a single entry (be it a file or disk image).
- *
- * 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 HeaderBlock {
- private int headerCrc;
- private int attribCount;
- private int versionNumber;
- private long totalThreads;
- private int fileSysId;
- private int fileSysInfo;
- private long access;
- private long fileType;
- private long extraType;
- private int storageType;
- private Date createWhen;
- private Date modWhen;
- private Date archiveWhen;
- private int optionSize;
- private byte[] optionListBytes;
- private byte[] attribBytes;
- private String filename;
- private String rawFilename;
- private long headerSize = 0;
- private List threads = new ArrayList();
-
- /**
- * Create the Header Block. This is done dynamically since
- * the Header Block size varies significantly.
- */
- public HeaderBlock(LittleEndianByteInputStream bs) throws IOException {
- int type = bs.seekFileType(4);
- if (type == 0)
- throw new IOException("Unable to decode this archive."); // FIXME - NLS
- headerCrc = bs.readWord();
- attribCount = bs.readWord();
- versionNumber = bs.readWord();
- totalThreads = bs.readLong();
- fileSysId = bs.readWord();
- fileSysInfo = bs.readWord();
- access = bs.readLong();
- fileType = bs.readLong();
- extraType = bs.readLong();
- storageType = bs.readWord();
- createWhen = bs.readDate();
- modWhen = bs.readDate();
- archiveWhen = bs.readDate();
- // Read the mysterious option_list
- if (versionNumber >= 1) {
- optionSize = bs.readWord();
- if (optionSize > 0) {
- optionListBytes = bs.readBytes(optionSize-2);
- }
- }
- // Compute attribute bytes that exist and read (if needed)
- int sizeofAttrib = attribCount - 58;
- if (versionNumber >= 1) {
- if (optionSize == 0) sizeofAttrib -= 2;
- else sizeofAttrib -= optionSize;
- }
- if (sizeofAttrib > 0) {
- attribBytes = bs.readBytes(sizeofAttrib);
- }
- // Read the (defunct) filename
- int length = bs.readWord();
- if (length > 0) {
- rawFilename = new String(bs.readBytes(length));
- }
- }
- /**
- * Read in all data threads. All ThreadRecords are read and then
- * each thread's data is read (per NuFX spec).
- */
- public void readThreads(LittleEndianByteInputStream bs) throws IOException {
- for (long l=0; l getThreadRecords() {
- return threads;
- }
- public void setThreadRecords(List threads) {
- this.threads = threads;
- }
- public long getHeaderSize() {
- return headerSize;
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java b/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java
deleted file mode 100644
index efe05db..0000000
--- a/src/main/java/com/webcodepro/shrinkit/MasterHeaderBlock.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.io.IOException;
-import java.util.Date;
-
-import com.webcodepro.shrinkit.io.ByteConstants;
-import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
-
-/**
- * The Master Header Block contains information about the entire
- * ShrinkIt archive.
- *
- * 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;
- private boolean validCrc;
- private long totalRecords;
- private Date archiveCreateWhen;
- private Date archiveModWhen;
- private int masterVersion;
- private long masterEof;
-
- /**
- * Create the Master Header Block, based on the LittleEndianByteInputStream.
- */
- public MasterHeaderBlock(LittleEndianByteInputStream bs) throws IOException {
- int fileType = 0, headerOffset = 0;
- fileType = bs.seekFileType();
-
- if (fileType == NuFileArchive.BXY_ARCHIVE) {
- bs.readBytes(127 - ByteConstants.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."); // FIXME - NLS
- fileType = bs.seekFileType();
- }
- if (!(fileType == NuFileArchive.NUFILE_ARCHIVE)) {
- throw new IOException("Unable to decode this archive."); // FIXME - NLS
- }
- 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();
- masterVersion = bs.readWord();
- if (masterVersion > 0) {
- bs.readBytes(8); // documented to be null, but we don't care
- masterEof = bs.readLong();
- } else {
- masterEof = -1;
- }
- // Read whatever remains of the fixed size header
- while (bs.getTotalBytesRead() < MASTER_HEADER_LENGTH + headerOffset) {
- bs.readByte();
- }
- validCrc = (masterCrc == bs.getCrcValue());
- }
-
- // 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;
- }
- public boolean isValidCrc() {
- return validCrc;
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/NuFileArchive.java b/src/main/java/com/webcodepro/shrinkit/NuFileArchive.java
deleted file mode 100644
index fb1f7d0..0000000
--- a/src/main/java/com/webcodepro/shrinkit/NuFileArchive.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
-
-/**
- * Basic reading of a NuFX archive.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class NuFileArchive {
- private MasterHeaderBlock master;
- private List headers;
- private long totalSize = 0;
-
- /**
- * Need to enumerate some basic sub-types of archives.
- */
- public static final int NUFILE_ARCHIVE = 1;
- public static final int NUFX_ARCHIVE = 2;
- public static final int BXY_ARCHIVE = 3;
-
- /**
- * Read in the NuFile/NuFX/Shrinkit archive.
- */
- public NuFileArchive(InputStream inputStream) throws IOException {
- LittleEndianByteInputStream bs = new LittleEndianByteInputStream(inputStream);
- master = new MasterHeaderBlock(bs);
- headers = new ArrayList();
- for (int i=0; i getHeaderBlocks() {
- return headers;
- }}
diff --git a/src/main/java/com/webcodepro/shrinkit/ThreadClass.java b/src/main/java/com/webcodepro/shrinkit/ThreadClass.java
deleted file mode 100644
index ba8da6f..0000000
--- a/src/main/java/com/webcodepro/shrinkit/ThreadClass.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.webcodepro.shrinkit;
-
-/**
- * Define and decode the thread_class field.
- * @author robgreene@users.sourceforge.net
- */
-public enum ThreadClass {
- MESSAGE, CONTROL, DATA, FILENAME;
-
- /**
- * Find the given ThreadClass.
- * @throws IllegalArgumentException if the thread_class is unknown
- */
- public static ThreadClass find(int threadClass) {
- switch (threadClass) {
- case 0x0000: return MESSAGE;
- case 0x0001: return CONTROL;
- case 0x0002: return DATA;
- case 0x0003: return FILENAME;
- default:
- throw new IllegalArgumentException("Unknown thread_class of " + threadClass);
- }
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java b/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java
deleted file mode 100644
index 97f9f82..0000000
--- a/src/main/java/com/webcodepro/shrinkit/ThreadFormat.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.webcodepro.shrinkit;
-
-/**
- * Define and decode the thread_format field.
- * @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);
-
- /** Associate the hex codes with the enum */
- private int threadFormat;
-
- private ThreadFormat(int threadFormat) {
- this.threadFormat = threadFormat;
- }
-
- public int getThreadFormat() {
- return threadFormat;
- }
-
- /**
- * Find the ThreadFormat.
- * @throws IllegalArgumentException if the thread_format is unknown
- */
- public static ThreadFormat find(int threadFormat) {
- for (ThreadFormat f : values()) {
- if (threadFormat == f.getThreadFormat()) return f;
- }
- throw new IllegalArgumentException("Unknown thread_format of " + threadFormat);
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/ThreadKind.java b/src/main/java/com/webcodepro/shrinkit/ThreadKind.java
deleted file mode 100644
index 2418b60..0000000
--- a/src/main/java/com/webcodepro/shrinkit/ThreadKind.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.webcodepro.shrinkit;
-
-/**
- * Define and decode the thread_kind field.
- * @author robgreene@users.sourceforge.net
- */
-public enum ThreadKind {
- ASCII_TEXT, ALLOCATED_SPACE, APPLE_IIGS_ICON, CREATE_DIRECTORY, DATA_FORK, DISK_IMAGE, RESOURCE_FORK,
- FILENAME;
-
- /**
- * Find the specific ThreadKind.
- * @throws IllegalArgumentException when the thread_kind cannot be determined
- */
- public static ThreadKind find(int threadKind, ThreadClass threadClass) {
- switch (threadClass) {
- case MESSAGE:
- switch (threadKind) {
- case 0x0000: return ASCII_TEXT;
- case 0x0001: return ALLOCATED_SPACE;
- case 0x0002: return APPLE_IIGS_ICON;
- }
- throw new IllegalArgumentException("Unknown thread_kind "+threadKind+" for message thread_class of " + threadClass);
- case CONTROL:
- if (threadKind == 0x0000) return CREATE_DIRECTORY;
- throw new IllegalArgumentException("Unknown thread_kind "+threadKind+" for control thread_class of " + threadClass);
- case DATA:
- switch (threadKind) {
- case 0x0000: return DATA_FORK;
- case 0x0001: return DISK_IMAGE;
- case 0x0002: return RESOURCE_FORK;
- }
- throw new IllegalArgumentException("Unknown thread_kind "+threadKind+" for data thread_class of " + threadClass);
- case FILENAME:
- if (threadKind == 0x0000) return FILENAME;
- throw new IllegalArgumentException("Unknown thread_kind "+threadKind+" for filename thread_class of " + threadClass);
- default:
- throw new IllegalArgumentException("Unknown thread_class of " + threadClass);
- }
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/ThreadRecord.java b/src/main/java/com/webcodepro/shrinkit/ThreadRecord.java
deleted file mode 100644
index a32003c..0000000
--- a/src/main/java/com/webcodepro/shrinkit/ThreadRecord.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
-import com.webcodepro.shrinkit.io.NufxLzw1InputStream;
-import com.webcodepro.shrinkit.io.NufxLzw2InputStream;
-
-/**
- * This represents a single thread from the Shrinkit archive.
- * As it is constructed, the thread "header" is read. Once all
- * threads have been constructed, use readThreadData
- * to load up the data.
- *
- * Depending on the type of thread, the data may be text. If so,
- * isText
will return true and getText
- * will return the string. Otherwise the data should be read through
- * one of the InputStream
options.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class ThreadRecord {
- private ThreadClass threadClass;
- private ThreadFormat threadFormat;
- private ThreadKind threadKind;
- private int threadCrc;
- private long threadEof;
- private long compThreadEof;
- private byte[] threadData;
-
- /**
- * Construct the ThreadRecord and read the header details with no hints
- * from the Header Block.
- */
- public ThreadRecord(LittleEndianByteInputStream bs) throws IOException {
- this(null, bs);
- }
-
- /**
- * Construct the ThreadRecord and read the header details.
- */
- public ThreadRecord(HeaderBlock hb, LittleEndianByteInputStream bs) throws IOException {
- threadClass = ThreadClass.find(bs.readWord());
- threadFormat = ThreadFormat.find(bs.readWord());
- threadKind = ThreadKind.find(bs.readWord(), threadClass);
- threadCrc = bs.readWord();
- threadEof = bs.readLong();
- compThreadEof = bs.readLong();
- if ((threadKind == ThreadKind.DISK_IMAGE) && (hb != null)) {
- /* If we have hints from the header block, repair some disk image related bugs. */
- if (hb.getStorageType() <= 13 ) {
- /* supposed to be block size, but SHK v3.0.1 stored it wrong */
- threadEof = hb.getExtraType() * 512;
- // System.out.println("Found erroneous storage type... fixing.");
- } else if (hb.getStorageType() == 256 &&
- hb.getExtraType() == 280 &&
- hb.getFileSysId() == 2 ) { // FileSysDOS33
- /*
- * Fix for less-common ShrinkIt problem: looks like an old
- * version of GS/ShrinkIt used 256 as the block size when
- * compressing DOS 3.3 images from 5.25" disks. If that
- * appears to be the case here, crank up the block size.
- */
- threadEof = hb.getExtraType() * 512;
- } else {
- threadEof = hb.getExtraType() * hb.getStorageType();
- }
- }
- }
-
- /**
- * Read the raw thread data. This must be called.
- */
- public void readThreadData(LittleEndianByteInputStream bs) throws IOException {
- threadData = bs.readBytes((int)compThreadEof);
- }
- /**
- * Determine if this is a text-type field.
- */
- public boolean isText() {
- return threadKind == ThreadKind.ASCII_TEXT || threadKind == ThreadKind.FILENAME;
- }
- /**
- * Return the text data.
- */
- public String getText() {
- return isText() ? new String(threadData, 0, (int)threadEof) : null;
- }
- /**
- * Get raw data bytes (compressed).
- */
- public byte[] getBytes() {
- return threadData;
- }
- /**
- * Get the raw data input stream.
- */
- public InputStream getRawInputStream() {
- return new ByteArrayInputStream(threadData);
- }
- /**
- * Get the appropriate input data stream for this thread to decompress the contents.
- */
- public InputStream getInputStream() throws IOException {
- switch (threadFormat) {
- case UNCOMPRESSED:
- return getRawInputStream();
- case DYNAMIC_LZW1:
- return new NufxLzw1InputStream(new LittleEndianByteInputStream(getRawInputStream()));
- case DYNAMIC_LZW2:
- return new NufxLzw2InputStream(new LittleEndianByteInputStream(getRawInputStream()));
- default:
- throw new IOException("The thread format " + threadFormat + " does not have an InputStream associated with it!");
- }
- }
-
- // GENERATED CODE
-
- public ThreadClass getThreadClass() {
- return threadClass;
- }
- public void setThreadClass(ThreadClass threadClass) {
- this.threadClass = threadClass;
- }
- public ThreadFormat getThreadFormat() {
- return threadFormat;
- }
- public void setThreadFormat(ThreadFormat threadFormat) {
- this.threadFormat = threadFormat;
- }
- public ThreadKind getThreadKind() {
- return threadKind;
- }
- public void setThreadKind(ThreadKind threadKind) {
- this.threadKind = threadKind;
- }
- public int getThreadCrc() {
- return threadCrc;
- }
- public void setThreadCrc(int threadCrc) {
- this.threadCrc = threadCrc;
- }
- public long getThreadEof() {
- return threadEof;
- }
- public void setThreadEof(long threadEof) {
- this.threadEof = threadEof;
- }
- public long getCompThreadEof() {
- return compThreadEof;
- }
- public void setCompThreadEof(long compThreadEof) {
- this.compThreadEof = compThreadEof;
- }
- public byte[] getThreadData() {
- return threadData;
- }
- public void setThreadData(byte[] threadData) {
- this.threadData = threadData;
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/TimeRec.java b/src/main/java/com/webcodepro/shrinkit/TimeRec.java
deleted file mode 100644
index 7ae035e..0000000
--- a/src/main/java/com/webcodepro/shrinkit/TimeRec.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.webcodepro.shrinkit;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-
-/**
- * Apple IIgs Toolbox TimeRec object.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class TimeRec {
- private static final int SECOND = 0;
- private static final int MINUTE = 1;
- private static final int HOUR = 2;
- private static final int YEAR = 3;
- private static final int DAY = 4;
- private static final int MONTH = 5;
- private static final int WEEKDAY = 7;
- private static final int LENGTH = 8;
- private byte[] data = null;
-
- /**
- * Construct a TimeRec with the current date.
- */
- public TimeRec() {
- this(new Date());
- }
- /**
- * Construct a TimeRec with the specified date. You may pass in a null for a null date (all 0x00's).
- */
- public TimeRec(Date date) {
- setDate(date);
- }
- /**
- * Construct a TimeRec from the given LENGTH byte array.
- */
- public TimeRec(byte[] bytes, int offset) {
- if (bytes == null || bytes.length - offset < LENGTH) {
- throw new IllegalArgumentException("TimeRec requires a " + LENGTH + " byte array.");
- }
- //data = Arrays.copyOfRange(bytes, offset, LENGTH);
- data = new byte[LENGTH];
- System.arraycopy(bytes, offset, data, 0, LENGTH);
- }
- /**
- * Construct a TimeRec from the InputStream.
- */
- public TimeRec(InputStream inputStream) throws IOException {
- data = new byte[LENGTH];
- for (int i=0; i
- * Warning: The read(byte[])
and read(byte[], int, int)
- * methods of InputStream
will not work appropriately with any
- * bit size > 8 bits.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class BitInputStream extends InputStream implements BitConstants {
- /** Our source of data. */
- private InputStream is;
- /** The number of bits to read for a request. This can be adjusted dynamically. */
- private int requestedNumberOfBits;
- /** The current bit mask to use when returning a read()
request. */
- private int bitMask;
- /** The buffer containing our bits. An int allows 32 bits which should cover up to a 24 bit read if my math is correct. :-) */
- private int data = 0;
- /** Number of bits remaining in our buffer */
- private int bitsOfData = 0;
-
- /**
- * Create a BitInputStream wrapping the given InputStream
- * and reading the number of bits specified.
- */
- public BitInputStream(InputStream is, int startingNumberOfBits) {
- this.is = is;
- setRequestedNumberOfBits(startingNumberOfBits);
- }
-
- /**
- * Set the number of bits to be read with each call to read()
.
- */
- public void setRequestedNumberOfBits(int numberOfBits) {
- this.requestedNumberOfBits = numberOfBits;
- this.bitMask = BIT_MASKS[numberOfBits];
- }
-
- /**
- * Increase the requested number of bits by one.
- * This is the general usage and prevents client from needing to track
- * the requested number of bits or from making various method calls.
- */
- public void increaseRequestedNumberOfBits() {
- setRequestedNumberOfBits(requestedNumberOfBits + 1);
- }
-
- /**
- * Answer with the current bit mask for the current bit size.
- */
- public int getBitMask() {
- return bitMask;
- }
-
- /**
- * Read a number of bits off of the wrapped InputStream.
- */
- public int read() throws IOException {
- while (bitsOfData < requestedNumberOfBits) {
- int b = is.read();
- if (b == -1) return b;
- if (bitsOfData > 0) {
- b <<= bitsOfData; // We're placing b on the high-bit side
- }
- data|= b;
- bitsOfData+= 8;
- }
- int b = data & bitMask;
- data >>= requestedNumberOfBits;
- bitsOfData-= requestedNumberOfBits;
- return b;
- }
-
- /**
- * When shifting from buffer to buffer, the input stream also should be reset.
- * This allows the "left over" bits to be cleared.
- */
- public void clearRemainingBitsOfData() {
- this.bitsOfData = 0;
- this.data = 0;
- }
-}
-
diff --git a/src/main/java/com/webcodepro/shrinkit/io/BitOutputStream.java b/src/main/java/com/webcodepro/shrinkit/io/BitOutputStream.java
deleted file mode 100644
index ca81b7b..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/BitOutputStream.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * The BitOutputStream allows varying bit sizes to be written to the wrapped
- * OutputStream. This is useful for LZW type compression algorithms
- * where 9-12 bit codes are used instead of the 8-bit byte.
- *
- * Warning: The write(byte[])
and write(byte[], int, int)
- * methods of OutputStream
will not work appropriately with any
- * bit size > 8 bits.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class BitOutputStream extends OutputStream implements BitConstants {
- /** Our data target. */
- private OutputStream os;
- /** The number of bits to write for a request. This can be adjusted dynamically. */
- private int requestedNumberOfBits;
- /** The current bit mask to use for a write(int)
request. */
- private int bitMask;
- /** The buffer containing our bits. */
- private int data = 0;
- /** Number of bits remaining in our buffer */
- private int bitsOfData = 0;
-
- /**
- * Create a BitOutpuStream wrapping the given OutputStream
- * and writing the number of bits specified.
- */
- public BitOutputStream(OutputStream os, int startingNumberOfBits) {
- this.os = os;
- setRequestedNumberOfBits(startingNumberOfBits);
- }
-
- /**
- * Set the number of bits to be write with each call to write(int)
.
- */
- public void setRequestedNumberOfBits(int numberOfBits) {
- this.requestedNumberOfBits = numberOfBits;
- this.bitMask = BIT_MASKS[numberOfBits];
- }
-
- /**
- * Increase the requested number of bits by one.
- * This is the general usage and prevents client from needing to track
- * the requested number of bits or from making various method calls.
- */
- public void increaseRequestedNumberOfBits() {
- setRequestedNumberOfBits(requestedNumberOfBits + 1);
- }
-
- /**
- * Answer with the current bit mask for the current bit size.
- */
- public int getBitMask() {
- return bitMask;
- }
-
- /**
- * Write the number of bits to the wrapped OutputStream.
- */
- public void write(int b) throws IOException {
- b &= bitMask; // Ensure we don't have extra baggage
- b <<= bitsOfData; // Move beyond existing bits of data
- data|= b; // Add in the additional data
- bitsOfData+= requestedNumberOfBits;
- while (bitsOfData >= 8) {
- os.write(data & 0xff);
- data >>= 8;
- bitsOfData-= 8;
- }
- }
-
- /**
- * When shifting from buffer to buffer, this OutputStream also should be reset.
- * This allows the "left over" bits to be cleared.
- */
- public void clearRemainingBitsOfData() {
- this.bitsOfData = 0;
- this.data = 0;
- }
-
- /**
- * Close the output stream and write any remaining byte to the output.
- * Note that we may very well end up with extra bits if there are < 8
- * bits remaining.
- */
- public void close() throws IOException {
- if (bitsOfData > 0) {
- write(0x00); // forces a flush of the remaining bits in the proper order
- }
- }
-
-}
-
diff --git a/src/main/java/com/webcodepro/shrinkit/io/ByteConstants.java b/src/main/java/com/webcodepro/shrinkit/io/ByteConstants.java
deleted file mode 100644
index e1c7e1a..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/ByteConstants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-
-/**
- * Provides constants for the LittleEndianByteInputStream and ByteTarget classes.
- *
- * @author robgreene@users.sourceforge.net
- * @see LittleEndianByteInputStream
- * @see ByteTarget
- */
-public interface ByteConstants {
- /** 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 };
- /** Binary II identifier "magic" bytes. */
- public static final byte[] BXY_ID = { 0x0a, 0x47, 0x4c };
- /** Apple IIgs Toolbox TimeRec seconds byte position. */
- public static final int TIMEREC_SECOND = 0;
- /** Apple IIgs Toolbox TimeRec seconds byte position. */
- public static final int TIMEREC_MINUTE = 1;
- /** Apple IIgs Toolbox TimeRec minutes byte position. */
- public static final int TIMEREC_HOUR = 2;
- /** Apple IIgs Toolbox TimeRec hours byte position. */
- public static final int TIMEREC_YEAR = 3;
- /** Apple IIgs Toolbox TimeRec year byte position. */
- public static final int TIMEREC_DAY = 4;
- /** Apple IIgs Toolbox TimeRec day byte position. */
- public static final int TIMEREC_MONTH = 5;
- /** Apple IIgs Toolbox TimeRec weekday (Mon, Tue, etc) byte position. */
- public static final int TIMEREC_WEEKDAY = 7;
- /** Apple IIgs Toolbox TimeRec length. */
- public static final int TIMEREC_LENGTH = 8;
- /** A null TimeRec */
- public static final byte[] TIMEREC_NULL = new byte[TIMEREC_LENGTH];
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java b/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java
deleted file mode 100644
index bf5c145..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/LittleEndianByteInputStream.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.GregorianCalendar;
-
-import com.webcodepro.shrinkit.CRC16;
-import com.webcodepro.shrinkit.NuFileArchive;
-
-/**
- * A simple class to hide the source of byte data.
- * @author robgreene@users.sourceforge.net
- */
-public class LittleEndianByteInputStream extends InputStream implements ByteConstants {
- private InputStream inputStream;
- private long bytesRead = 0;
- private CRC16 crc = new CRC16();
-
- /**
- * Construct a LittleEndianByteInputStream from an InputStream.
- */
- public LittleEndianByteInputStream(InputStream inputStream) {
- this.inputStream = inputStream;
- }
- /**
- * Construct a LittleEndianByteInputStream from a byte array.
- */
- public LittleEndianByteInputStream(byte[] data) {
- this.inputStream = new ByteArrayInputStream(data);
- }
-
- /**
- * Get the next byte.
- * Returns -1 if at end of input.
- * 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 {
- int b = inputStream.read();
- if (b != -1) {
- crc.update(b);
- bytesRead++;
- }
- return b;
- }
- /**
- * Get the next byte and fail if we are at EOF.
- * Note that an unsigned byte needs to be returned in a larger container (ie, a short or int or long).
- */
- public int readByte() throws IOException {
- int i = read();
- if (i == -1) throw new IOException("Expecting a byte but at EOF");
- return i;
- }
- /**
- * Get the next set of bytes as an array.
- * If EOF encountered, an IOException is thrown.
- */
- public byte[] readBytes(int bytes) throws IOException {
- byte[] data = new byte[bytes];
- 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))
- read = 0;
- if (read < bytes) {
- throw new IOException("Requested " + bytes + " bytes, but " + read + " read");
- }
- crc.update(data);
- return data;
- }
-
- /**
- * Test the beginning of the data stream for a magic signature, for up to a total
- * of 2k bytes of leading garbage
- */
- public int seekFileType() throws IOException {
- return seekFileType(6);
- }
- /**
- * Test the beginning of the data stream for a magic signature, specifying the
- * maximum size of a signature to test for
- */
- public int seekFileType(int max) throws IOException {
- byte[] data = new byte[2048];
- byte[] testNUFILE = new byte[6];
- byte[] testNUFX = new byte[4];
- byte[] testBXY = new byte[3];
- int type = 0, i, pos = 0;
- for (i = 0;i> 8);
- }
- /**
- * Write a "Long".
- */
- public void writeLong(long l) throws IOException {
- write((int)(l & 0xff));
- write((int)((l >> 8) & 0xff));
- write((int)((l >> 16) & 0xff));
- write((int)((l >> 24) & 0xff));
- }
- /**
- * Write the Java Date object as a TimeRec.
- * Note that years 2000-2039 are assumed to be 00-39 per the NuFX addendum
- * at http://www.nulib.com/library/nufx-addendum.htm.
- * @see http://www.nulib.com/library/nufx-addendum.htm
- */
- public void writeDate(Date date) throws IOException {
- byte[] data = null;
- if (date == null) {
- data = TIMEREC_NULL;
- } else {
- data = new byte[TIMEREC_LENGTH];
- GregorianCalendar gc = new GregorianCalendar();
- gc.setTime(date);
- int year = gc.get(Calendar.YEAR);
- year -= (year < 2000) ? 1900 : 2000;
- data[TIMEREC_YEAR] = (byte)(year & 0xff);
- data[TIMEREC_MONTH] = (byte)(gc.get(Calendar.MONTH) + 1);
- data[TIMEREC_DAY] = (byte)gc.get(Calendar.DAY_OF_MONTH);
- data[TIMEREC_HOUR] = (byte)gc.get(Calendar.HOUR_OF_DAY);
- data[TIMEREC_MINUTE] = (byte)gc.get(Calendar.MINUTE);
- data[TIMEREC_SECOND] = (byte)gc.get(Calendar.SECOND);
- data[TIMEREC_WEEKDAY] = (byte)gc.get(Calendar.DAY_OF_WEEK);
- }
- write(data);
- }
-
- /**
- * 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 written.
- */
- public long getTotalBytesWritten() {
- return bytesWritten;
- }
-
- /**
- * Pass the flush request to the wrapped stream.
- */
- public void flush() throws IOException {
- outputStream.flush();
- }
- /**
- * Pass the close request to the wrapped stream.
- */
- public void close() throws IOException {
- outputStream.close();
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/LzwInputStream.java b/src/main/java/com/webcodepro/shrinkit/io/LzwInputStream.java
deleted file mode 100644
index 3204544..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/LzwInputStream.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * This is the generic Shrinkit LZW decompression algorithm.
- * It does not deal with the vagaries of the LZW/1 and LZW/2 data streams.
- * It does, however, deal with dictionary clears (0x100) and the
- * BitInputStream
bit sizes.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class LzwInputStream extends InputStream {
- private BitInputStream is;
- private List dictionary;
- private Queue outputBuffer = new ConcurrentLinkedQueue();
- private boolean newBuffer = true;
- // See Wikipedia entry on LZW for variable naming
- private int k;
- private int[] w;
- private int[] entry;
-
- /**
- * Create the LzwInputStream
based on the given
- * BitInputStream
.
- * @see BitInputStream
- */
- public LzwInputStream(BitInputStream is) {
- this.is = is;
- }
-
- /**
- * Answer with the next byte from the (now) decompressed input stream.
- */
- public int read() throws IOException {
- if (outputBuffer.isEmpty()) {
- fillBuffer();
- }
- return outputBuffer.remove();
- }
-
- /**
- * Fill the buffer up with some decompressed data.
- * This may range from one byte to many bytes, depending on what is in the
- * dictionary.
- * @see http://en.wikipedia.org/wiki/Lzw for the general algorithm
- */
- public void fillBuffer() throws IOException {
- if (dictionary == null) {
- is.setRequestedNumberOfBits(9);
- // Setup default dictionary for all bytes
- dictionary = new ArrayList();
- for (short i=0; i<256; i++) dictionary.add(new int[] { i });
- dictionary.add(new int[] { 0x100 }); // 0x100 not used by NuFX
- }
- if (newBuffer) {
- // Setup for decompression;
- k = is.read();
- outputBuffer.add(k);
- if (k == -1) return;
- w = new int[] { k };
- newBuffer = false;
- }
- // LZW decompression
- k = is.read();
- if (k == -1) {
- outputBuffer.add(k);
- return;
- }
- if (k == 0x100) {
- dictionary = null;
- is.setRequestedNumberOfBits(9);
- k = 0;
- w = null;
- entry = null;
- newBuffer = true;
- fillBuffer(); // Warning: recursive call
- return;
- }
- if (k < dictionary.size()) {
- entry = dictionary.get(k);
- } else if (k == dictionary.size()) {
- //entry = Arrays.copyOf(w, w.length+1);
- entry = new int[w.length+1];
- System.arraycopy(w, 0, entry, 0, w.length);
- entry[w.length] = w[0];
- } else {
- throw new IOException("Invalid code of <" + k + "> encountered");
- }
- for (int i : entry) outputBuffer.add(i);
- //int[] newEntry = Arrays.copyOf(w, w.length+1);
- int[] newEntry = new int[w.length+1];
- System.arraycopy(w, 0, newEntry, 0, w.length);
- newEntry[w.length] = entry[0];
- dictionary.add(newEntry);
- w = entry;
- // Exclusive-OR the current bitmask against the new dictionary size -- if all bits are
- // on, we'll get 0. (That is, all 9 bits on is 0x01ff exclusive or bit mask of 0x01ff
- // yields 0x0000.) This tells us we need to increase the number of bits we're pulling
- // from the bit stream.
- if ((dictionary.size() ^ is.getBitMask()) == 0) {
- is.increaseRequestedNumberOfBits();
- }
- }
-
- /**
- * Clear out the dictionary. It will be rebuilt on the next call to
- * fillBuffer
.
- */
- public void clearDictionary() {
- dictionary = null;
- is.setRequestedNumberOfBits(9);
- is.clearRemainingBitsOfData();
- outputBuffer.clear();
- k = 0;
- w = null;
- entry = null;
- newBuffer = true;
- }
-
- /**
- * Provide necessary housekeeping to reset LZW stream between NuFX buffer changes.
- * The dictionary is the only item that is not cleared -- that needs to be done
- * explicitly since behavior between LZW/1 and LZW/2 differ.
- */
- public void clearData() {
- is.clearRemainingBitsOfData();
- outputBuffer.clear();
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/LzwOutputStream.java b/src/main/java/com/webcodepro/shrinkit/io/LzwOutputStream.java
deleted file mode 100644
index 0389903..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/LzwOutputStream.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.webcodepro.shrinkit.CRC16;
-
-/**
- * This is the generic Shrinkit LZW compression algorithm.
- * It does not deal with the vagaries of the LZW/1 and LZW/2 data streams.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class LzwOutputStream extends OutputStream {
- private BitOutputStream os;
- private Map dictionary = new HashMap();
- private int[] w = new int[0];
- private int nextCode = 0x101;
-
- /**
- * This simple class can be used as a key into a Map.
- *
- * @author robgreene@users.sourceforge.net
- */
- private class ByteArray {
- /** Data being managed. */
- private int[] data;
- /** The computed hash code -- CRC-16 for lack of imagination. */
- private int hashCode;
-
- public ByteArray(int d) {
- this(new int[] { d });
- }
- public ByteArray(int[] data) {
- this.data = data;
- CRC16 crc = new CRC16();
- for (int b : data) crc.update(b);
- hashCode = (int)crc.getValue();
- }
- public boolean equals(Object obj) {
- ByteArray ba = (ByteArray)obj;
- if (data.length != ba.data.length) return false;
- for (int i=0; i 0) System.arraycopy(w, 0, wc, 0, w.length);
- wc[wc.length-1]= c;
- if (dictionary.containsKey(new ByteArray(wc))) {
- w = wc;
- } else {
- dictionary.put(new ByteArray(wc), nextCode++);
- os.write(dictionary.get(new ByteArray(w)));
- w = new int[] { c };
- }
- // Exclusive-OR the current bitmask against the new dictionary size -- if all bits are
- // on, we'll get 0. (That is, all 9 bits on is 0x01ff exclusive or bit mask of 0x01ff
- // yields 0x0000.) This tells us we need to increase the number of bits we're writing
- // to the bit stream.
- if ((dictionary.size() ^ os.getBitMask()) == 0) {
- os.increaseRequestedNumberOfBits();
- }
- }
-
- @Override
- public void flush() throws IOException {
- os.write(dictionary.get(new ByteArray(w)));
- }
-
- @Override
- public void close() throws IOException {
- flush();
- os.flush();
- os.close();
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/NufxLzw1InputStream.java b/src/main/java/com/webcodepro/shrinkit/io/NufxLzw1InputStream.java
deleted file mode 100644
index 520c6da..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/NufxLzw1InputStream.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.webcodepro.shrinkit.CRC16;
-
-/**
- * The NufxLzw1InputStream
reads a data fork or
- * resource fork written in the NuFX LZW/1 format.
- *
- * The layout of the LZW/1 data is as follows:
- *
- *
- * "Fork" Header |
- *
- * +0 |
- * Word |
- * CRC-16 of the uncompressed data within the thread |
- *
- * +2 |
- * Byte |
- * Low-level volume number use to format 5.25" disks |
- *
- * +3 |
- * Byte |
- * RLE character used to decode this thread |
- *
- * Each subsequent 4K chunk of data |
- *
- * +0 |
- * Word |
- * Length after RLE compression (if RLE is not used, length
- * will be 4096 |
- *
- * +2 |
- * Byte |
- * A $01 indicates LZW applied to this chunk; $00 that LZW
- * was not applied to this chunk |
- *
- *
- *
- * Note that the LZW string table is cleared after
- * every chunk.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class NufxLzw1InputStream extends InputStream {
- /** This is the raw data stream with all markers and compressed data. */
- private LittleEndianByteInputStream dataStream;
- /** Used for an LZW-only InputStream
. */
- private LzwInputStream lzwStream;
- /** Used for an RLE-only InputStream
. */
- private RleInputStream rleStream;
- /** Used for an LZW+RLE InputStream
. */
- private InputStream lzwRleStream;
- /** This is the generic decompression stream from which we read. */
- private InputStream decompressionStream;
- /** Counts the number of bytes in the 4096 byte chunk. */
- private int bytesLeftInChunk;
- /** This is the CRC-16 for the uncompressed fork. */
- private int givenCrc = -1;
- /** This is the volume number for 5.25" disks. */
- private int volumeNumber;
- /** This is the RLE character to use. */
- private int rleCharacter;
- /** Used to track the CRC of data we've extracted */
- private CRC16 dataCrc = new CRC16();
-
- /**
- * Create the LZW/1 input stream.
- */
- public NufxLzw1InputStream(LittleEndianByteInputStream dataStream) {
- this.dataStream = dataStream;
- }
-
- /**
- * Read the next byte in the decompressed data stream.
- */
- public int read() throws IOException {
- if (givenCrc == -1) { // read the data or resource fork header
- givenCrc = dataStream.readWord();
- volumeNumber = dataStream.readByte();
- rleCharacter = dataStream.readByte();
- lzwStream = new LzwInputStream(new BitInputStream(dataStream, 9));
- rleStream = new RleInputStream(dataStream, rleCharacter);
- lzwRleStream = new RleInputStream(lzwStream);
- }
- if (bytesLeftInChunk == 0) { // read the chunk header
- bytesLeftInChunk = 4096; // NuFX always reads 4096 bytes
- lzwStream.clearDictionary(); // Always clear dictionary
- int length = dataStream.readWord();
- int lzwFlag = dataStream.readByte();
- int flag = lzwFlag + (length == 4096 ? 0 : 2);
- switch (flag) {
- case 0: decompressionStream = dataStream;
- break;
- case 1: decompressionStream = lzwStream;
- break;
- case 2: decompressionStream = rleStream;
- break;
- case 3: decompressionStream = lzwRleStream;
- break;
- default: throw new IOException("Unknown type of decompression, flag = " + flag);
- }
- }
- // Now we can read a data byte
- int b = decompressionStream.read();
- bytesLeftInChunk--;
- dataCrc.update(b);
- return b;
- }
-
- /**
- * Indicates if the computed CRC matches the CRC given in the data stream.
- */
- public boolean isCrcValid() {
- return givenCrc == dataCrc.getValue();
- }
-
- // GENERATED CODE
-
- public int getGivenCrc() {
- return givenCrc;
- }
- public void setGivenCrc(int givenCrc) {
- this.givenCrc = givenCrc;
- }
- public int getVolumeNumber() {
- return volumeNumber;
- }
- public void setVolumeNumber(int volumeNumber) {
- this.volumeNumber = volumeNumber;
- }
- public int getRleCharacter() {
- return rleCharacter;
- }
- public void setRleCharacter(int rleCharacter) {
- this.rleCharacter = rleCharacter;
- }
- public long getDataCrc() {
- return dataCrc.getValue();
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/NufxLzw2InputStream.java b/src/main/java/com/webcodepro/shrinkit/io/NufxLzw2InputStream.java
deleted file mode 100644
index d38af67..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/NufxLzw2InputStream.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import com.webcodepro.shrinkit.CRC16;
-
-/**
- * The NufxLzw2InputStream
reads a data fork or
- * resource fork written in the NuFX LZW/2 format.
- *
- * The layout of the LZW/2 data is as follows:
- *
- *
- * "Fork" Header |
- *
- * +0 |
- * Byte |
- * Low-level volume number used to format 5.25" disks |
- *
- * +1 |
- * Byte |
- * RLE character used to decode this thread |
- *
- * Each subsequent 4K chunk of data |
- *
- * +0 |
- * Word |
- * Bits 0-12: Length after RLE compression
- * Bit 15: LZW flag (set to 1 if LZW used) |
- *
- * +2 |
- * Word |
- * If LZW flag = 1, total bytes in chunk
- * Else (flag = 0) start of data |
- *
- *
- *
- * The LZW/2 dictionary is only cleared when the table becomes full and is indicated
- * in the input stream by 0x100. It is also cleared whenever a chunk that is not
- * LZW encoded is encountered.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class NufxLzw2InputStream extends InputStream {
- /** This is the raw data stream with all markers and compressed data. */
- private LittleEndianByteInputStream dataStream;
- /** Used for an LZW-only InputStream
. */
- private LzwInputStream lzwStream;
- /** Used for an RLE-only InputStream
. */
- private RleInputStream rleStream;
- /** Used for an LZW+RLE InputStream
. */
- private InputStream lzwRleStream;
- /** This is the generic decompression stream from which we read. */
- private InputStream decompressionStream;
- /** Counts the number of bytes in the 4096 byte chunk. */
- private int bytesLeftInChunk;
- /** This is the volume number for 5.25" disks. */
- private int volumeNumber = -1;
- /** This is the RLE character to use. */
- private int rleCharacter;
- /** Used to track the CRC of data we've extracted */
- private CRC16 dataCrc = new CRC16();
-
- /**
- * Create the LZW/2 input stream.
- */
- public NufxLzw2InputStream(LittleEndianByteInputStream dataStream) {
- this.dataStream = dataStream;
- }
-
- /**
- * Read the next byte in the decompressed data stream.
- */
- public int read() throws IOException {
- if (volumeNumber == -1) { // read the data or resource fork header
- volumeNumber = dataStream.readByte();
- rleCharacter = dataStream.readByte();
- lzwStream = new LzwInputStream(new BitInputStream(dataStream, 9));
- rleStream = new RleInputStream(dataStream, rleCharacter);
- lzwRleStream = new RleInputStream(lzwStream);
- }
- if (bytesLeftInChunk == 0) { // read the chunk header
- bytesLeftInChunk = 4096; // NuFX always reads 4096 bytes
- lzwStream.clearData(); // Allow the LZW stream to do a little housekeeping
- int word = dataStream.readWord();
- int length = word & 0x7fff;
- int lzwFlag = word & 0x8000;
- if (lzwFlag == 0) { // We clear dictionary whenever a non-LZW chunk is encountered
- lzwStream.clearDictionary();
- } else {
- dataStream.readWord(); // At this time, I just throw away the total bytes in this chunk...
- }
- int flag = (lzwFlag == 0 ? 0 : 1) + (length == 4096 ? 0 : 2);
- switch (flag) {
- case 0: decompressionStream = dataStream;
- break;
- case 1: decompressionStream = lzwStream;
- break;
- case 2: decompressionStream = rleStream;
- break;
- case 3: decompressionStream = lzwRleStream;
- break;
- default: throw new IOException("Unknown type of decompression, flag = " + flag);
- }
- }
- // Now we can read a data byte
- int b = decompressionStream.read();
- bytesLeftInChunk--;
- dataCrc.update(b);
- return b;
- }
-
- // GENERATED CODE
-
- public int getVolumeNumber() {
- return volumeNumber;
- }
- public void setVolumeNumber(int volumeNumber) {
- this.volumeNumber = volumeNumber;
- }
- public int getRleCharacter() {
- return rleCharacter;
- }
- public void setRleCharacter(int rleCharacter) {
- this.rleCharacter = rleCharacter;
- }
- public long getDataCrc() {
- return dataCrc.getValue();
- }
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/RleInputStream.java b/src/main/java/com/webcodepro/shrinkit/io/RleInputStream.java
deleted file mode 100644
index 9e2d42d..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/RleInputStream.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-
-/**
- * The RleInputStream handles the NuFX RLE data stream.
- * This data stream is byte oriented. If a repeat occurs,
- * the data stream will contain the marker byte, byte to
- * repeat, and the number of repeats (zero based; ie, $00=1,
- * $01=2, ... $ff=256). The default marker is $DB.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class RleInputStream extends InputStream {
- private InputStream bs;
- private int escapeChar;
- private int repeatedByte;
- private int numBytes = -1;
-
- /**
- * Create an RLE input stream with the default marker byte.
- */
- public RleInputStream(InputStream bs) {
- this(bs, 0xdb);
- }
- /**
- * Create an RLE input stream with the specified marker byte.
- */
- public RleInputStream(InputStream bs, int escapeChar) {
- this.bs = bs;
- this.escapeChar = escapeChar;
- }
-
- /**
- * Read the next byte from the input stream.
- */
- public int read() throws IOException {
- if (numBytes == -1) {
- int b = bs.read();
- if (b == escapeChar) {
- repeatedByte = bs.read();
- numBytes = bs.read();
- } else {
- return b;
- }
- }
- numBytes--;
- return repeatedByte;
- }
-
-}
diff --git a/src/main/java/com/webcodepro/shrinkit/io/RleOutputStream.java b/src/main/java/com/webcodepro/shrinkit/io/RleOutputStream.java
deleted file mode 100644
index b365245..0000000
--- a/src/main/java/com/webcodepro/shrinkit/io/RleOutputStream.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.webcodepro.shrinkit.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * The RleOutputStream handles the NuFX RLE data stream.
- * This data stream is byte oriented. If a repeat occurs,
- * the data stream will contain the marker byte, byte to
- * repeat, and the number of repeats (zero based; ie, $00=1,
- * $01=2, ... $ff=256). The default marker is $DB.
- *
- * @author robgreene@users.sourceforge.net
- */
-public class RleOutputStream extends OutputStream {
- private OutputStream os;
- private int escapeChar;
- private int repeatedByte;
- private int numBytes = -1;
-
- /**
- * Create an RLE output stream with the default marker byte.
- */
- public RleOutputStream(OutputStream bs) {
- this(bs, 0xdb);
- }
- /**
- * Create an RLE output stream with the specified marker byte.
- */
- public RleOutputStream(OutputStream os, int escapeChar) {
- this.os = os;
- this.escapeChar = escapeChar;
- }
-
- /**
- * Write the next byte to the output stream.
- */
- public void write(int b) throws IOException {
- if (numBytes == -1) {
- repeatedByte = b;
- numBytes++;
- } else if (repeatedByte == b) {
- numBytes++;
- if (numBytes > 255) {
- flush();
- }
- } else {
- flush();
- repeatedByte = b;
- numBytes++;
- }
- }
-
- /**
- * Flush out any remaining data.
- * If we only have 1 byte and it is not the repeated
- * byte, we can just dump that byte. Otherwise, we need to
- * write out the escape character, the repeated byte, and
- * the number of bytes.
- */
- public void flush() throws IOException {
- if (numBytes != -1) {
- if (numBytes == 0 && escapeChar != repeatedByte) {
- os.write(repeatedByte);
- } else {
- os.write(escapeChar);
- os.write(repeatedByte);
- os.write(numBytes);
- }
- numBytes = -1;
- }
- }
-
- /**
- * Close out the data stream. Makes sure the repeate buffer
- * is flushed.
- */
- public void close() throws IOException {
- flush();
- os.close();
- }
-}