Compare commits

...

15 Commits

Author SHA1 Message Date
A2 Geek
4ebc196313
Merge pull request #4 from AppleCommander/dependabot/gradle/junit-junit-4.13.2
Bump junit:junit from 4.12 to 4.13.2
2023-10-28 12:52:42 -05:00
dependabot[bot]
c666b30e30
Bump junit:junit from 4.12 to 4.13.2
Bumps [junit:junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.2.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.2)

---
updated-dependencies:
- dependency-name: junit:junit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-28 17:52:10 +00:00
A2 Geek
80d387277b
Create dependabot.yml 2023-10-28 12:51:53 -05:00
Rob Greene
7ec734be7a First round of updates. Leaving publication for later. #3 2020-11-24 19:35:38 -06:00
Rob Greene
932d688b36 Gradle tweaks: fix for Oracle javadoc doclint strictness; made the signing task a bit more intelligent. 2018-05-29 10:52:29 -05:00
Rob Greene
e6cddf25a7 Trying to remove signing dependencies when not signing. 2018-05-09 21:57:57 -05:00
Rob Greene
3b04415763 Adding some version information and fixing command-line to actually report version. 2018-04-04 21:34:04 -05:00
Rob Greene
aafb68f75c Bumping version. 2018-03-11 17:34:41 -05:00
Rob Greene
216c73d32b Missed this in the AC2 merge. 2018-03-11 17:34:28 -05:00
Rob Greene
b2f3a5a3e1 Bumping version. 2018-03-11 15:13:42 -05:00
Rob Greene
e9469fe5a0 Merging in changes from applecommander2 project. API did change a bit on
HeaderBlock.
2018-03-11 15:13:24 -05:00
Rob Greene
8f4ca7fb9f Making NufxScan a bit more useful. Include list of directories on the
command-line. Will recurse into subdirectories as well.
2018-03-10 22:09:27 -06:00
Rob Greene
e178f124ed Fixing yellow markers in test classes and switching to JUnit 4. 2018-03-10 21:45:24 -06:00
Rob Greene
e1fb963913 Cleaning up Javadoc warnings and errors. 2018-03-10 17:36:23 -06:00
Rob Greene
3b28ad7a07 Adding Gradle config to publish to the Maven Central Repository. 2018-03-07 19:59:46 -06:00
37 changed files with 813 additions and 460 deletions

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gradle" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ build/
.settings/
.classpath
.project
bin/

57
MAVEN-REPO.md Normal file
View File

@ -0,0 +1,57 @@
# Releasing to the Maven Central Repository
## GPG Keys
Summary of commands for GPG2 keys preparation...
Generate key:
```bash
$ gpg2 --gen-key
```
Publish key on public key server:
```bash
$ gpg2 --list-keys
$ gpg2 --list-secret-keys
$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys <key-id>
```
Extract secret key for the Gradle signing plugin:
```bash
$ gpg2 --export-secret-keys > secring.gpg
```
## Build and publish to Central Repository
Ensure full build passes:
```bash
$ ./gradlew clean test javadoc assemble
<...lots of stuff, primarily Javadoc issues...>
BUILD SUCCESSFUL in 3s
13 actionable tasks: 13 executed
```
Upload:
```bash
$ ./gradlew uploadArchives
BUILD SUCCESSFUL in 10s
10 actionable tasks: 1 executed, 9 up-to-date
```
Then follow "releasing the deployment" below.
## Tag and publish on GitHub
Just a reminder!
# References
* http://central.sonatype.org/pages/gradle.html
* http://central.sonatype.org/pages/releasing-the-deployment.html
* For all the other little pieces, Google is your friend. ;-)

View File

@ -3,3 +3,6 @@
This project is a direct off-shoot of the AppleCommander project and implements a pure Java API to manipulate ShrinkIt (NuFX)
archives ([Apple File Type Note $E0/8002](http://www.apple2online.com/web_documents/ft_e0.8002_shrinkit.pdf)).
*Developers*
Being new to Gradle, all of the Maven release components are in the `build.gradle` file. More a warning than anything, just in case it causes issues. Please make more portable and submit a PR.

View File

@ -1,12 +1,14 @@
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'maven'
apply plugin: 'signing'
repositories {
jcenter()
}
dependencies {
testCompile 'junit:junit:4.12'
testImplementation 'junit:junit:4.13.2'
}
mainClassName = 'com.webcodepro.shrinkit.NufxScan'
@ -14,7 +16,75 @@ mainClassName = 'com.webcodepro.shrinkit.NufxScan'
jar {
manifest {
attributes(
'Main-Class': mainClassName
'Main-Class': mainClassName,
'Implementation-Title': 'ShrinkItArchive',
'Implementation-Version': archiveVersion
)
}
}
javadoc {
options.addStringOption('Xdoclint:none', '-quiet')
}
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}
task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}
artifacts {
archives javadocJar, sourcesJar
}
signing {
// Only sign if we're uploading...
required { gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))
}
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication(userName: findProperty('ossrhUsername'), password: findProperty('ossrhPassword'))
}
pom.project {
name archivesBaseName
packaging 'jar'
description 'A Java library for managing Apple II ShrinkIt archives.'
url 'https://applecommander.github.io/'
scm {
url 'https://github.com/AppleCommander/ShrinkItArchive'
}
licenses {
license {
name 'The GNU General Public License (GPL) Version 2, June 1991'
url 'https://www.gnu.org/licenses/gpl-2.0.html'
}
}
developers {
developer {
id 'robgreene'
email 'robgreene@gmail.com'
}
}
}
}
}
}

8
gradle.properties Normal file
View File

@ -0,0 +1,8 @@
# Universal ShrinkItArchive version number. Used for:
# - Naming JAR file.
# - The build will insert this into a file that is read at run time as well.
version=1.2.2
# Maven Central Repository G and A of GAV coordinate. :-)
group=net.sf.applecommander
archivesBaseName=AppleCommander

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

53
gradlew vendored
View File

@ -1,5 +1,21 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@ -66,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@ -109,10 +126,11 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@ -138,19 +156,19 @@ if $cygwin ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@ -159,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@ -16,7 +16,7 @@ import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
* version, and those are documented in the getter methods.
*
* @author robgreene@users.sourceforge.net
* @see http://www.nulib.com/library/FTN.e08002.htm
* @see <a href="http://www.nulib.com/library/FTN.e08002.htm">Apple II File Type Note $E0/$8002</a>
*/
public class HeaderBlock {
private int headerCrc;
@ -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

View File

@ -0,0 +1,14 @@
package com.webcodepro.shrinkit;
/**
* Handy reference for constant values based on header blocks.
* These are likely user interface oriented.
*
* @author rob
*/
public interface HeaderConstants {
public static final String[] FILE_SYS = {
"Reserved", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS", "Macintosh MFS",
"Lisa File System", "Apple CP/M", "Reserved", "MS-DOS", "High Sierra", "ISO 9660", "AppleShare"
};
}

View File

@ -15,7 +15,7 @@ import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
* version, and those are documented in the getter methods.
*
* @author robgreene@users.sourceforge.net
* @see http://www.nulib.com/library/FTN.e08002.htm
* @see <a href="http://www.nulib.com/library/FTN.e08002.htm">Apple II File Type Note $E0/$8002</a>
*/
public class MasterHeaderBlock {
private static final int MASTER_HEADER_LENGTH = 48;
@ -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)) {

View File

@ -13,6 +13,12 @@ import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
* @author robgreene@users.sourceforge.net
*/
public class NuFileArchive {
public static final String VERSION;
static {
VERSION = NuFileArchive.class.getPackage().getImplementationVersion();
}
private MasterHeaderBlock master;
private List<HeaderBlock> headers;
private long totalSize = 0;

View File

@ -1,12 +1,10 @@
package com.webcodepro.shrinkit;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Scan through the directories in NufxScan.txt, looking for
@ -23,26 +21,42 @@ public class NufxScan {
private static long sizeOfSmallestCompressedFile;
public static void main(String[] args) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(NufxScan.class.getResourceAsStream("NufxScan.txt")));
String line = r.readLine();
while (line != null) {
scanDirectory(line);
line = r.readLine();
if (args.length == 0) {
System.out.println("Scan NuFX/Shrinkit archives. Please include at least one path name.");
} else if (args.length == 1 && "-v".equals(args[0])) {
System.out.printf("ShrinkIt Library version %s\n", NuFileArchive.VERSION);
} else {
for (String dir : args) {
scanDirectory(dir);
}
}
}
private static void scanDirectory(String dirName) throws IOException {
File dir = new File(dirName);
if (!dir.isDirectory()) {
throw new IllegalArgumentException("'" + dirName + "' is not a directory");
scanDirectory(dir);
}
private static void scanDirectory(File directory) throws IOException {
System.out.printf("Scanning '%s'...\n", directory.toString());
if (!directory.isDirectory()) {
throw new IllegalArgumentException("'" + directory.toString() + "' is not a directory");
}
File[] files = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".shk") || name.toLowerCase().endsWith(".sdk");
File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File file) {
boolean isSHK = file.getName().toLowerCase().endsWith(".shk");
boolean isSDK = file.getName().toLowerCase().endsWith(".sdk");
boolean isDirectory = file.isDirectory();
boolean keep = isSHK || isSDK || isDirectory;
return keep;
}
});
for (File file : files) {
display(file);
if (file.isDirectory()) {
scanDirectory(file);
} else {
displayArchive(file);
}
}
if (sizeOfSmallestCompressedFile != 0) {
System.out.printf("\n\nSmallest compressed file:\n");
@ -52,51 +66,49 @@ public class NufxScan {
}
}
private static void display(File archive) throws IOException {
private static void displayArchive(File archive) throws IOException {
System.out.printf("Details for %s\n\n", archive.getAbsoluteFile());
InputStream is = new FileInputStream(archive);
if (is == null) {
throw new IOException("Unable to locate '" + archive.getAbsoluteFile() + "'");
}
NuFileArchive a = new NuFileArchive(is);
System.out.println("Ver# Threads FSId FSIn Access FileType ExtraTyp Stor Thread Formats..... OrigSize CompSize Filename");
System.out.println("==== ======== ==== ==== ======== ======== ======== ==== =================== ======== ======== ==============================");
for (HeaderBlock b : a.getHeaderBlocks()) {
System.out.printf("%04x %08x %04x %04x %08x %08x %08x %04x ",
b.getVersionNumber(), b.getTotalThreads(), b.getFileSysId(), b.getFileSysInfo(), b.getAccess(),
b.getFileType(), b.getExtraType(), b.getStorageType());
int threadsPrinted = 0;
String filename = b.getFilename();
long origSize = 0;
long compSize = 0;
boolean compressed = false;
for (ThreadRecord r : b.getThreadRecords()) {
threadsPrinted++;
System.out.printf("%04x ", r.getThreadFormat().getThreadFormat());
compressed |= (r.getThreadFormat() != ThreadFormat.UNCOMPRESSED);
if (r.getThreadKind() == ThreadKind.FILENAME) {
filename = r.getText();
try (InputStream is = new FileInputStream(archive)) {
NuFileArchive a = new NuFileArchive(is);
System.out.println("Ver# Threads FSId FSIn Access FileType ExtraTyp Stor Thread Formats..... OrigSize CompSize Filename");
System.out.println("==== ======== ==== ==== ======== ======== ======== ==== =================== ======== ======== ==============================");
for (HeaderBlock b : a.getHeaderBlocks()) {
System.out.printf("%04x %08x %04x %04x %08x %08x %08x %04x ",
b.getVersionNumber(), b.getTotalThreads(), b.getFileSysId(), b.getFileSysInfo(), b.getAccess(),
b.getFileType(), b.getExtraType(), b.getStorageType());
int threadsPrinted = 0;
String filename = b.getFilename();
long origSize = 0;
long compSize = 0;
boolean compressed = false;
for (ThreadRecord r : b.getThreadRecords()) {
threadsPrinted++;
System.out.printf("%04x ", r.getThreadFormat().getThreadFormat());
compressed |= (r.getThreadFormat() != ThreadFormat.UNCOMPRESSED);
if (r.getThreadKind() == ThreadKind.FILENAME) {
filename = r.getText();
}
if (r.getThreadClass() == ThreadClass.DATA) {
origSize+= r.getThreadEof();
compSize+= r.getCompThreadEof();
}
}
if (r.getThreadClass() == ThreadClass.DATA) {
origSize+= r.getThreadEof();
compSize+= r.getCompThreadEof();
while (threadsPrinted < 4) {
System.out.printf(" ");
threadsPrinted++;
}
System.out.printf("%08x %08x ", origSize, compSize);
if (filename == null || filename.length() == 0) {
filename = "<Unknown>";
}
System.out.println(filename);
if (compressed && (sizeOfSmallestCompressedFile == 0 || compSize < sizeOfSmallestCompressedFile)) {
sizeOfSmallestCompressedFile = compSize;
archiveWithSmallestCompressedFile = archive;
smallestCompressedFilename = filename;
}
}
while (threadsPrinted < 4) {
System.out.printf(" ");
threadsPrinted++;
}
System.out.printf("%08x %08x ", origSize, compSize);
if (filename == null || filename.length() == 0) {
filename = "<Unknown>";
}
System.out.println(filename);
if (compressed && (sizeOfSmallestCompressedFile == 0 || compSize < sizeOfSmallestCompressedFile)) {
sizeOfSmallestCompressedFile = compSize;
archiveWithSmallestCompressedFile = archive;
smallestCompressedFilename = filename;
}
System.out.println();
}
System.out.println();
}
}

View File

@ -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.

View File

@ -75,9 +75,8 @@ public class TimeRec {
/**
* Convert the TimeRec into a Java Date object.
* Note that years 1900-1939 are assumed to be 2000-2039 per the NuFX addendum
* at http://www.nulib.com/library/nufx-addendum.htm.
* @see http://www.nulib.com/library/nufx-addendum.htm
* Note that years 1900-1939 are assumed to be 2000-2039 per the NuFX addendum.
* @see <a href="http://www.nulib.com/library/nufx-addendum.htm">NuFX addendum</a>
*/
public Date getDate() {
int year = data[YEAR]+1900;

View File

@ -6,7 +6,7 @@ package com.webcodepro.shrinkit.io;
*
* @author robgreene@users.sourceforge.net
* @see LittleEndianByteInputStream
* @see ByteTarget
* @see LittleEndianByteOutputStream
*/
public interface ByteConstants {
/** Master Header Block identifier "magic" bytes. */

View File

@ -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");
}
@ -135,9 +136,8 @@ public class LittleEndianByteInputStream extends InputStream implements ByteCons
}
/**
* Read the TimeRec into a Java Date object.
* Note that years 00-39 are assumed to be 2000-2039 per the NuFX addendum
* at http://www.nulib.com/library/nufx-addendum.htm.
* @see http://www.nulib.com/library/nufx-addendum.htm
* Note that years 00-39 are assumed to be 2000-2039 per the NuFX addendum.
* @see <a href="http://www.nulib.com/library/nufx-addendum.htm">NuFX addendum</a>
*/
public Date readDate() throws IOException {
byte[] data = readBytes(TIMEREC_LENGTH);

View File

@ -64,9 +64,8 @@ public class LittleEndianByteOutputStream extends OutputStream implements ByteCo
}
/**
* 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
* Note that years 2000-2039 are assumed to be 00-39 per the NuFX addendum.
* @see <a href="http://www.nulib.com/library/nufx-addendum.htm">NuFX addendum</a>
*/
public void writeDate(Date date) throws IOException {
byte[] data = null;

View File

@ -3,7 +3,6 @@ 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;
@ -49,7 +48,7 @@ public class LzwInputStream extends InputStream {
* 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
* @see <a href="http://en.wikipedia.org/wiki/Lzw">Wikipedia for the general algorithm</a>
*/
public void fillBuffer() throws IOException {
if (dictionary == null) {

View File

@ -72,7 +72,7 @@ public class RleOutputStream extends OutputStream {
}
/**
* Close out the data stream. Makes sure the repeate buffer
* Close out the data stream. Makes sure the repeat buffer
* is flushed.
*/
public void close() throws IOException {

View File

@ -2,13 +2,15 @@ package com.webcodepro.shrinkit;
import java.io.UnsupportedEncodingException;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
public class CRC16Test extends TestCase {
public class CRC16Test {
@Test
public void testTable() {
int[] table = CRC16.getTable();
assertEquals(0, table[0]);
assertEquals(0x1ef0, table[0xff]);
Assert.assertEquals(0, table[0]);
Assert.assertEquals(0x1ef0, table[0xff]);
System.out.println("CRC16 lookup table:");
for (int i = 0; i < 256; i++) {
System.out.print(Integer.toHexString(table[i]) + " ");
@ -16,23 +18,25 @@ public class CRC16Test extends TestCase {
}
}
@Test
public void testUpdate() throws UnsupportedEncodingException {
CRC16 crc16 = new CRC16();
crc16.update("123456789".getBytes("UTF-8"));
assertEquals(0x31c3, crc16.getValue());
Assert.assertEquals(0x31c3, crc16.getValue());
crc16.update("ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes("UTF-8"));
assertEquals(0x92cc, crc16.getValue());
Assert.assertEquals(0x92cc, crc16.getValue());
crc16.update("abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"));
assertEquals(0xfc85, crc16.getValue());
Assert.assertEquals(0xfc85, crc16.getValue());
crc16.reset();
crc16.update("xxx123456789xxx".getBytes("UTF-8"), 3, 9);
assertEquals(0x31c3, crc16.getValue());
Assert.assertEquals(0x31c3, crc16.getValue());
}
@Test
public void testVariousValues() throws UnsupportedEncodingException {
CRC16 crc16 = new CRC16();
byte[] data = new byte[] { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, (byte)0x80 };
crc16.update(data);
assertEquals(0x2299, crc16.getValue());
Assert.assertEquals(0x2299, crc16.getValue());
}
}

View File

@ -1,10 +1,13 @@
package com.webcodepro.shrinkit;
import static com.webcodepro.shrinkit.TestHelper.checkDate;
import java.io.IOException;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
import org.junit.Assert;
import org.junit.Test;
import junit.framework.TestCase;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
/**
* Exercise the Header Block.
@ -12,10 +15,11 @@ import junit.framework.TestCase;
* Documentation Final Revision Three" document.
* @author robgreene@users.sourceforge.net
*/
public class HeaderBlockTest extends TestCase {
public class HeaderBlockTest {
/**
* From "NuFX Documentation Final Revision Three", version 0, "Normal Files" sample.
*/
@Test
public void testNormalFiles() throws IOException {
byte[] data = {
0x4e, (byte)0xf5, 0x46, (byte)0xd8, 0x55, 0x34, 0x3a, 0x00,
@ -29,25 +33,26 @@ public class HeaderBlockTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
HeaderBlock b = new HeaderBlock(bs);
assertEquals(0x3455, b.getHeaderCrc());
assertEquals(0x003a, b.getAttribCount());
assertEquals(0x0000, b.getVersionNumber());
assertEquals(0x00000001, b.getTotalThreads());
assertEquals(0x0001, b.getFileSysId());
assertEquals(0x002f, b.getFileSysInfo());
assertEquals(0x000000c3, b.getAccess());
assertEquals(0x00000004, b.getFileType());
assertEquals(0x00000000, b.getExtraType());
assertEquals(0x0001, b.getStorageType());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getCreateWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}).readDate(), b.getModWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getArchiveWhen());
assertEquals("STUFF", b.getFilename());
Assert.assertEquals(0x3455, b.getHeaderCrc());
Assert.assertEquals(0x003a, b.getAttribCount());
Assert.assertEquals(0x0000, b.getVersionNumber());
Assert.assertEquals(0x00000001, b.getTotalThreads());
Assert.assertEquals(0x0001, b.getFileSysId());
Assert.assertEquals(0x002f, b.getFileSysInfo());
Assert.assertEquals(0x000000c3, b.getAccess());
Assert.assertEquals(0x00000004, b.getFileType());
Assert.assertEquals(0x00000000, b.getExtraType());
Assert.assertEquals(0x0001, b.getStorageType());
checkDate(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getCreateWhen());
checkDate(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}, b.getModWhen());
checkDate(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getArchiveWhen());
Assert.assertEquals("STUFF", b.getFilename());
}
/**
* From "NuFX Documentation Final Revision Three", version 0, "Extended Files" sample.
*/
@Test
public void testExtendedFiles() throws IOException {
byte[] data = {
0x4e, (byte)0xf5, 0x46, (byte)0xd8, 0x65, 0x78, 0x3a, 0x00,
@ -62,25 +67,26 @@ public class HeaderBlockTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
HeaderBlock b = new HeaderBlock(bs);
assertEquals(0x7865, b.getHeaderCrc());
assertEquals(0x003a, b.getAttribCount());
assertEquals(0x0000, b.getVersionNumber());
assertEquals(0x00000002, b.getTotalThreads());
assertEquals(0x0001, b.getFileSysId());
assertEquals(0x002f, b.getFileSysInfo());
assertEquals(0x000000c3, b.getAccess());
assertEquals(0x000000b3, b.getFileType());
assertEquals(0x00000000, b.getExtraType());
assertEquals(0x0005, b.getStorageType());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getCreateWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}).readDate(), b.getModWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getArchiveWhen());
assertEquals("EXT.STUFF", b.getFilename());
Assert.assertEquals(0x7865, b.getHeaderCrc());
Assert.assertEquals(0x003a, b.getAttribCount());
Assert.assertEquals(0x0000, b.getVersionNumber());
Assert.assertEquals(0x00000002, b.getTotalThreads());
Assert.assertEquals(0x0001, b.getFileSysId());
Assert.assertEquals(0x002f, b.getFileSysInfo());
Assert.assertEquals(0x000000c3, b.getAccess());
Assert.assertEquals(0x000000b3, b.getFileType());
Assert.assertEquals(0x00000000, b.getExtraType());
Assert.assertEquals(0x0005, b.getStorageType());
checkDate(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getCreateWhen());
checkDate(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}, b.getModWhen());
checkDate(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getArchiveWhen());
Assert.assertEquals("EXT.STUFF", b.getFilename());
}
/**
* From "NuFX Documentation Final Revision Three", version 0, "Disk" sample.
*/
@Test
public void testDiskImage() throws IOException {
byte[] data = {
0x4e, (byte)0xf5, 0x46, (byte)0xd8, 0x67, 0x05, 0x3a, 0x00,
@ -94,25 +100,26 @@ public class HeaderBlockTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
HeaderBlock b = new HeaderBlock(bs);
assertEquals(0x0567, b.getHeaderCrc());
assertEquals(0x003a, b.getAttribCount());
assertEquals(0x0000, b.getVersionNumber());
assertEquals(0x00000001, b.getTotalThreads());
assertEquals(0x0001, b.getFileSysId());
assertEquals(0x002f, b.getFileSysInfo());
assertEquals(0x00000000, b.getAccess());
assertEquals(0x00000000, b.getFileType());
assertEquals(0x00000640, b.getExtraType());
assertEquals(0x0200, b.getStorageType());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getCreateWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}).readDate(), b.getModWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}).readDate(), b.getArchiveWhen());
assertEquals("DISK", b.getFilename());
Assert.assertEquals(0x0567, b.getHeaderCrc());
Assert.assertEquals(0x003a, b.getAttribCount());
Assert.assertEquals(0x0000, b.getVersionNumber());
Assert.assertEquals(0x00000001, b.getTotalThreads());
Assert.assertEquals(0x0001, b.getFileSysId());
Assert.assertEquals(0x002f, b.getFileSysInfo());
Assert.assertEquals(0x00000000, b.getAccess());
Assert.assertEquals(0x00000000, b.getFileType());
Assert.assertEquals(0x00000640, b.getExtraType());
Assert.assertEquals(0x0200, b.getStorageType());
checkDate(new byte[] {0x00,0x0a,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getCreateWhen());
checkDate(new byte[] {0x00,0x10,0x0b,0x58,0x11,0x0b,0x00,0x05}, b.getModWhen());
checkDate(new byte[] {0x00,0x0c,0x01,0x58,0x16,0x0a,0x00,0x07}, b.getArchiveWhen());
Assert.assertEquals("DISK", b.getFilename());
}
/**
* Sample taking from the SCC.SHK file, first header entry.
*/
@Test
public void testSccShkHeader1() throws IOException {
byte[] data = {
0x4e, (byte)0xf5, 0x46, (byte)0xd8, 0x5e, 0x40, 0x3c, 0x00,
@ -127,20 +134,20 @@ public class HeaderBlockTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
HeaderBlock b = new HeaderBlock(bs);
assertEquals(0x405e, b.getHeaderCrc());
assertEquals(0x003c, b.getAttribCount());
assertEquals(0x0003, b.getVersionNumber());
assertEquals(0x00000003, b.getTotalThreads());
assertEquals(0x0001, b.getFileSysId());
assertEquals(0x003a, b.getFileSysInfo());
assertEquals(0x000000e3, b.getAccess());
assertEquals(0x000000b0, b.getFileType());
assertEquals(0x00000003, b.getExtraType());
assertEquals(0x0002, b.getStorageType());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x1c,0x10,0x5d,0x1c,0x06,0x00,0x05}).readDate(), b.getCreateWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x00,0x11,0x11,0x5e,0x13,0x01,0x00,0x01}).readDate(), b.getModWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x38,0x0c,0x14,0x5f,0x08,0x07,0x00,0x04}).readDate(), b.getArchiveWhen());
assertEquals(0x0000, b.getOptionSize());
assertNull(b.getRawFilename());
Assert.assertEquals(0x405e, b.getHeaderCrc());
Assert.assertEquals(0x003c, b.getAttribCount());
Assert.assertEquals(0x0003, b.getVersionNumber());
Assert.assertEquals(0x00000003, b.getTotalThreads());
Assert.assertEquals(0x0001, b.getFileSysId());
Assert.assertEquals(0x003a, b.getFileSysInfo());
Assert.assertEquals(0x000000e3, b.getAccess());
Assert.assertEquals(0x000000b0, b.getFileType());
Assert.assertEquals(0x00000003, b.getExtraType());
Assert.assertEquals(0x0002, b.getStorageType());
checkDate(new byte[] {0x00,0x1c,0x10,0x5d,0x1c,0x06,0x00,0x05}, b.getCreateWhen());
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.assertEquals("Unknown", b.getRawFilename());
}
}

View File

@ -1,10 +1,13 @@
package com.webcodepro.shrinkit;
import static com.webcodepro.shrinkit.TestHelper.checkDate;
import java.io.IOException;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
import org.junit.Assert;
import org.junit.Test;
import junit.framework.TestCase;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
/**
* Exercise the Master Header Block.
@ -12,7 +15,8 @@ import junit.framework.TestCase;
* and check it against our computed values.
* @author robgreene@users.sourceforge.net
*/
public class MasterHeaderBlockTest extends TestCase {
public class MasterHeaderBlockTest {
@Test
public void testWithValidCrc() throws IOException {
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] {
0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5, (byte)0xdc, 0x1b,
@ -24,15 +28,16 @@ public class MasterHeaderBlockTest extends TestCase {
});
MasterHeaderBlock b = new MasterHeaderBlock(bs);
// Using byte values since it should be a bit more clear where they came from
assertEquals(0x1bdc, b.getMasterCrc());
assertEquals(0x2d, b.getTotalRecords());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x38, 0x0c, 0x14, 0x5f, 0x08, 0x07, 0x30, 0x04}).readDate(), b.getArchiveCreateWhen());
assertEquals(new LittleEndianByteInputStream(new byte[] {0x29, 0x0d, 0x14, 0x5f, 0x08, 0x07, 0x01, 0x04}).readDate(), b.getArchiveModWhen());
assertEquals(0x01, b.getMasterVersion());
assertEquals(0x1acae, b.getMasterEof());
assertTrue(b.isValidCrc());
Assert.assertEquals(0x1bdc, b.getMasterCrc());
Assert.assertEquals(0x2d, b.getTotalRecords());
checkDate(new byte[] {0x38, 0x0c, 0x14, 0x5f, 0x08, 0x07, 0x30, 0x04}, b.getArchiveCreateWhen());
checkDate(new byte[] {0x29, 0x0d, 0x14, 0x5f, 0x08, 0x07, 0x01, 0x04}, b.getArchiveModWhen());
Assert.assertEquals(0x01, b.getMasterVersion());
Assert.assertEquals(0x1acae, b.getMasterEof());
Assert.assertTrue(b.isValidCrc());
}
@Test
public void testWithInvalidCrc() throws IOException {
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] {
0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5, 0x00, 0x00, // <-- Bad CRC!
@ -43,6 +48,6 @@ public class MasterHeaderBlockTest extends TestCase {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
});
MasterHeaderBlock b = new MasterHeaderBlock(bs);
assertFalse(b.isValidCrc());
Assert.assertFalse(b.isValidCrc());
}
}

View File

@ -0,0 +1,21 @@
package com.webcodepro.shrinkit;
import java.io.IOException;
import java.util.Date;
import org.junit.Assert;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
public class TestHelper {
private TestHelper() {
// Prevent construction
}
public static void checkDate(byte[] streamData, Date actual) throws IOException {
try (LittleEndianByteInputStream is = new LittleEndianByteInputStream(streamData)) {
Assert.assertEquals(is.readDate(), actual);
}
}
}

View File

@ -2,9 +2,10 @@ package com.webcodepro.shrinkit;
import java.io.IOException;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
import org.junit.Assert;
import org.junit.Test;
import junit.framework.TestCase;
import com.webcodepro.shrinkit.io.LittleEndianByteInputStream;
/**
* Exercise the Thread Record.
@ -12,10 +13,11 @@ import junit.framework.TestCase;
* Documentation Final Revision Three" document.
* @author robgreene@users.sourceforge.net
*/
public class ThreadRecordTest extends TestCase {
public class ThreadRecordTest {
/**
* From "NuFX Documentation Final Revision Three", version 0, "Normal Files" sample.
*/
@Test
public void testNormalFiles() throws IOException {
byte[] data = {
0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -23,17 +25,18 @@ public class ThreadRecordTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
ThreadRecord r = new ThreadRecord(bs);
assertEquals(ThreadClass.DATA, r.getThreadClass());
assertEquals(ThreadFormat.DYNAMIC_LZW1, r.getThreadFormat());
assertEquals(ThreadKind.DATA_FORK, r.getThreadKind());
assertEquals(0x0000, r.getThreadCrc());
assertEquals(0x00002000, r.getThreadEof());
assertEquals(0x00001000, r.getCompThreadEof());
Assert.assertEquals(ThreadClass.DATA, r.getThreadClass());
Assert.assertEquals(ThreadFormat.DYNAMIC_LZW1, r.getThreadFormat());
Assert.assertEquals(ThreadKind.DATA_FORK, r.getThreadKind());
Assert.assertEquals(0x0000, r.getThreadCrc());
Assert.assertEquals(0x00002000, r.getThreadEof());
Assert.assertEquals(0x00001000, r.getCompThreadEof());
}
/**
* From "NuFX Documentation Final Revision Three", version 0, "Extended Files" sample.
*/
@Test
public void testExtendedFiles() throws IOException {
byte[] data = {
0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -43,24 +46,25 @@ public class ThreadRecordTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
ThreadRecord r1 = new ThreadRecord(bs);
assertEquals(ThreadClass.DATA, r1.getThreadClass());
assertEquals(ThreadFormat.DYNAMIC_LZW1, r1.getThreadFormat());
assertEquals(ThreadKind.DATA_FORK, r1.getThreadKind());
assertEquals(0x0000, r1.getThreadCrc());
assertEquals(0x00002000, r1.getThreadEof());
assertEquals(0x00000800, r1.getCompThreadEof());
Assert.assertEquals(ThreadClass.DATA, r1.getThreadClass());
Assert.assertEquals(ThreadFormat.DYNAMIC_LZW1, r1.getThreadFormat());
Assert.assertEquals(ThreadKind.DATA_FORK, r1.getThreadKind());
Assert.assertEquals(0x0000, r1.getThreadCrc());
Assert.assertEquals(0x00002000, r1.getThreadEof());
Assert.assertEquals(0x00000800, r1.getCompThreadEof());
ThreadRecord r2 = new ThreadRecord(bs);
assertEquals(ThreadClass.DATA, r2.getThreadClass());
assertEquals(ThreadFormat.DYNAMIC_LZW1, r2.getThreadFormat());
assertEquals(ThreadKind.RESOURCE_FORK, r2.getThreadKind());
assertEquals(0x0000, r2.getThreadCrc());
assertEquals(0x00001000, r2.getThreadEof());
assertEquals(0x00000800, r2.getCompThreadEof());
Assert.assertEquals(ThreadClass.DATA, r2.getThreadClass());
Assert.assertEquals(ThreadFormat.DYNAMIC_LZW1, r2.getThreadFormat());
Assert.assertEquals(ThreadKind.RESOURCE_FORK, r2.getThreadKind());
Assert.assertEquals(0x0000, r2.getThreadCrc());
Assert.assertEquals(0x00001000, r2.getThreadEof());
Assert.assertEquals(0x00000800, r2.getCompThreadEof());
}
/**
* From "NuFX Documentation Final Revision Three", version 0, "Disk" sample.
*/
@Test
public void testDiskImage() throws IOException {
byte[] data = {
0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
@ -68,17 +72,18 @@ public class ThreadRecordTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
ThreadRecord r = new ThreadRecord(bs);
assertEquals(ThreadClass.DATA, r.getThreadClass());
assertEquals(ThreadFormat.DYNAMIC_LZW1, r.getThreadFormat());
assertEquals(ThreadKind.DISK_IMAGE, r.getThreadKind());
assertEquals(0x0000, r.getThreadCrc());
assertEquals(0x00000000, r.getThreadEof());
assertEquals(0x00074551, r.getCompThreadEof());
Assert.assertEquals(ThreadClass.DATA, r.getThreadClass());
Assert.assertEquals(ThreadFormat.DYNAMIC_LZW1, r.getThreadFormat());
Assert.assertEquals(ThreadKind.DISK_IMAGE, r.getThreadKind());
Assert.assertEquals(0x0000, r.getThreadCrc());
Assert.assertEquals(0x00000000, r.getThreadEof());
Assert.assertEquals(0x00074551, r.getCompThreadEof());
}
/**
* Sample taken from the SCC.SHK file, first header entry.
*/
@Test
public void testSccShkHeader1() throws IOException {
byte[] data = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -90,31 +95,32 @@ public class ThreadRecordTest extends TestCase {
};
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
ThreadRecord r1 = new ThreadRecord(bs);
assertEquals(ThreadClass.FILENAME, r1.getThreadClass());
assertEquals(ThreadFormat.UNCOMPRESSED, r1.getThreadFormat());
assertEquals(ThreadKind.FILENAME, r1.getThreadKind());
assertEquals(0x0000, r1.getThreadCrc());
assertEquals(0x0000000b, r1.getThreadEof());
assertEquals(0x00000020, r1.getCompThreadEof());
Assert.assertEquals(ThreadClass.FILENAME, r1.getThreadClass());
Assert.assertEquals(ThreadFormat.UNCOMPRESSED, r1.getThreadFormat());
Assert.assertEquals(ThreadKind.FILENAME, r1.getThreadKind());
Assert.assertEquals(0x0000, r1.getThreadCrc());
Assert.assertEquals(0x0000000b, r1.getThreadEof());
Assert.assertEquals(0x00000020, r1.getCompThreadEof());
ThreadRecord r2 = new ThreadRecord(bs);
assertEquals(ThreadClass.MESSAGE, r2.getThreadClass());
assertEquals(ThreadFormat.UNCOMPRESSED, r2.getThreadFormat());
assertEquals(ThreadKind.ALLOCATED_SPACE, r2.getThreadKind());
assertEquals(0x0000, r2.getThreadCrc());
assertEquals(0x00000000, r2.getThreadEof());
assertEquals(0x000000c8, r2.getCompThreadEof());
Assert.assertEquals(ThreadClass.MESSAGE, r2.getThreadClass());
Assert.assertEquals(ThreadFormat.UNCOMPRESSED, r2.getThreadFormat());
Assert.assertEquals(ThreadKind.ALLOCATED_SPACE, r2.getThreadKind());
Assert.assertEquals(0x0000, r2.getThreadCrc());
Assert.assertEquals(0x00000000, r2.getThreadEof());
Assert.assertEquals(0x000000c8, r2.getCompThreadEof());
ThreadRecord r3 = new ThreadRecord(bs);
assertEquals(ThreadClass.DATA, r3.getThreadClass());
assertEquals(ThreadFormat.DYNAMIC_LZW2, r3.getThreadFormat());
assertEquals(ThreadKind.DATA_FORK, r3.getThreadKind());
assertEquals(0x4a58, r3.getThreadCrc());
assertEquals(0x000006d6, r3.getThreadEof());
assertEquals(0x000003d4, r3.getCompThreadEof());
Assert.assertEquals(ThreadClass.DATA, r3.getThreadClass());
Assert.assertEquals(ThreadFormat.DYNAMIC_LZW2, r3.getThreadFormat());
Assert.assertEquals(ThreadKind.DATA_FORK, r3.getThreadKind());
Assert.assertEquals(0x4a58, r3.getThreadCrc());
Assert.assertEquals(0x000006d6, r3.getThreadEof());
Assert.assertEquals(0x000003d4, r3.getCompThreadEof());
}
/**
* Sample taken from the SCC.SHK file, first header entry.
*/
@Test
public void testSccShkHeader1FilenameThread() throws IOException {
byte[] data = {
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -127,7 +133,7 @@ public class ThreadRecordTest extends TestCase {
LittleEndianByteInputStream bs = new LittleEndianByteInputStream(data);
ThreadRecord r = new ThreadRecord(bs);
r.readThreadData(bs);
assertTrue(r.isText());
assertEquals("scc:equates", r.getText());
Assert.assertTrue(r.isText());
Assert.assertEquals("scc:equates", r.getText());
}
}

View File

@ -3,31 +3,35 @@ package com.webcodepro.shrinkit.io;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
/**
* Exercise the BitInputStream.
*
* @author robgreene@users.sourceforge.net
*/
public class BitInputStreamTest extends TestCase {
public class BitInputStreamTest extends TestBase {
@Test
public void test1() throws IOException {
byte[] data = new byte[] {
0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01
};
BitInputStream is = new BitInputStream(new ByteArrayInputStream(data), 9);
// 8-bit groups: 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
// 9-bit groups: 100000001 010000000 001000000 000100000 000010000 000001000 000000100 0
assertEquals(0x101, is.read());
assertEquals(0x080, is.read());
assertEquals(0x040, is.read());
assertEquals(0x020, is.read());
assertEquals(0x010, is.read());
assertEquals(0x008, is.read());
assertEquals(0x004, is.read());
try (BitInputStream is = new BitInputStream(new ByteArrayInputStream(data), 9)) {
// 8-bit groups: 00000001 00000001 00000001 00000001 00000001 00000001 00000001 00000001
// 9-bit groups: 100000001 010000000 001000000 000100000 000010000 000001000 000000100 0
Assert.assertEquals(0x101, is.read());
Assert.assertEquals(0x080, is.read());
Assert.assertEquals(0x040, is.read());
Assert.assertEquals(0x020, is.read());
Assert.assertEquals(0x010, is.read());
Assert.assertEquals(0x008, is.read());
Assert.assertEquals(0x004, is.read());
}
}
@Test
public void testCheatin1() throws IOException {
byte[] data = new byte[] {
(byte)0x54, (byte)0x90, (byte)0x24, (byte)0x99, (byte)0x02, (byte)0x62, (byte)0x20, (byte)0x88,
@ -46,11 +50,12 @@ public class BitInputStreamTest extends TestCase {
(byte)0x15, (byte)0xAB, (byte)0xD7, (byte)0xAD, (byte)0x5F, (byte)0xBB, (byte)0x52, (byte)0xC5,
(byte)0x03, (byte)0x00
};
BitInputStream is = new BitInputStream(new ByteArrayInputStream(data), 9);
int b = 0;
while (b != -1) {
b = is.read();
System.out.printf("%04x ", b);
try (BitInputStream is = new BitInputStream(new ByteArrayInputStream(data), 9)) {
int b = 0;
while (b != -1) {
b = is.read();
System.out.printf("%04x ", b);
}
}
}
@ -58,21 +63,13 @@ public class BitInputStreamTest extends TestCase {
* Simply ensure that we read the right bit codes from the LZW stream. This starts with 9 bits and
* ultimately might work up to a 12 bit code.
*/
@Test
public void testBitDecoder() throws IOException {
BitInputStream is = new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9);
int[] expected = new int[] { 0x0db, 0x000, 0x007, 0x0db, 0x055, 0x103, 0x02a, 0x103, 0x000, 0x06f, 0x0db };
for (int i=0; i<expected.length; i++) {
assertEquals("Testing value #" + i, expected[i], is.read());
try (BitInputStream is = new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9)) {
int[] expected = new int[] { 0x0db, 0x000, 0x007, 0x0db, 0x055, 0x103, 0x02a, 0x103, 0x000, 0x06f, 0x0db };
for (int i=0; i<expected.length; i++) {
Assert.assertEquals("Testing value #" + i, expected[i], is.read());
}
}
}
protected byte[] getHgrColorsLzw1() {
return new byte[] {
(byte)0xdb, 0x00, 0x1c, (byte)0xd8, 0x56, 0x65, (byte)0xa0, (byte)0x8a,
(byte)0x81, 0x00, (byte)0xde, 0x6c, 0x3b, 0x48, 0x10, (byte)0xa1,
(byte)0xc2, 0x3f, 0x0f, 0x02, (byte)0xfe, (byte)0x93, 0x48, 0x11,
(byte)0xc0, 0x44, (byte)0x8b, 0x15, 0x2f, 0x6a, (byte)0xcc, (byte)0xc8,
0x11, 0x23, (byte)0x80, 0x73, 0x00
};
}
}

View File

@ -3,12 +3,15 @@ package com.webcodepro.shrinkit.io;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.junit.Test;
/**
* Exercise the BitOutputStream.
*
* @author robgreene@users.sourceforge.net
*/
public class BitOutputStreamTest extends TestCaseHelper {
public class BitOutputStreamTest extends TestBase {
@Test
public void test1() throws IOException {
byte[] expected = new byte[] {
0x01, 0x01, 0x01, 0x01,

View File

@ -4,94 +4,106 @@ import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.Test;
import com.webcodepro.shrinkit.NuFileArchive;
/**
* Exercise the LittleEndianByteInputStream class.
* @author robgreene@users.sourceforge.net
*/
public class LittleEndianByteInputStreamTest extends TestCase {
public class LittleEndianByteInputStreamTest {
@Test
public void testReadA() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream("a".getBytes())) {
assertEquals('a', bs.read());
assertEquals(-1, bs.read());
assertEquals(1, bs.getTotalBytesRead());
Assert.assertEquals('a', bs.read());
Assert.assertEquals(-1, bs.read());
Assert.assertEquals(1, bs.getTotalBytesRead());
}
}
@Test
public void testReadB() throws IOException {
// Just to ensure we can get more than one byte...
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream("hello".getBytes())) {
assertEquals('h', bs.read());
assertEquals('e', bs.read());
assertEquals('l', bs.read());
assertEquals('l', bs.read());
assertEquals('o', bs.read());
assertEquals(-1, bs.read());
assertEquals(5, bs.getTotalBytesRead());
Assert.assertEquals('h', bs.read());
Assert.assertEquals('e', bs.read());
Assert.assertEquals('l', bs.read());
Assert.assertEquals('l', bs.read());
Assert.assertEquals('o', bs.read());
Assert.assertEquals(-1, bs.read());
Assert.assertEquals(5, bs.getTotalBytesRead());
}
}
@Test
public void testReadBytesInt() throws IOException {
// Ensure we read the requested data.
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream("HelloWorld".getBytes())) {
assertEquals("Hello", new String(bs.readBytes(5)));
assertEquals("World", new String(bs.readBytes(5)));
assertEquals(-1, bs.read());
assertEquals(10, bs.getTotalBytesRead());
Assert.assertEquals("Hello", new String(bs.readBytes(5)));
Assert.assertEquals("World", new String(bs.readBytes(5)));
Assert.assertEquals(-1, bs.read());
Assert.assertEquals(10, bs.getTotalBytesRead());
}
}
public void textReadBytesIntError() throws IOException {
@Test
public void testReadBytesIntError() throws IOException {
// Ensure that we fail appropriately
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream("Hi".getBytes())) {
try {
bs.readBytes(3);
fail();
Assert.fail();
} catch (IOException ex) {
assertTrue(true); // Expected
assertEquals(2, bs.getTotalBytesRead());
Assert.assertTrue(true); // Expected
Assert.assertEquals(2, bs.getTotalBytesRead());
}
}
}
// This methods got removed at some point but nobody updated the unit tests. Bad developer!
// public void testCheckNuFileId() throws IOException {
// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 });
// assertTrue(NuFileArchive.bs.checkNuFileId());
// assertEquals(6, bs.getTotalBytesRead());
// bs = new LittleEndianByteInputStream("NotNuFile".getBytes());
// assertFalse(bs.checkNuFileId());
// }
// This methods got removed at some point but nobody updated the unit tests. Bad developer!
// public void testCheckNuFxId() throws IOException {
// LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 });
// assertTrue(bs.checkNuFxId());
// assertEquals(4, bs.getTotalBytesRead());
// bs = new LittleEndianByteInputStream("NotNuFx".getBytes());
// 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 })) {
assertEquals(0x0201, bs.readWord());
assertEquals(0x0403, bs.readWord());
assertEquals(4, bs.getTotalBytesRead());
Assert.assertEquals(0x0201, bs.readWord());
Assert.assertEquals(0x0403, bs.readWord());
Assert.assertEquals(4, bs.getTotalBytesRead());
}
}
@Test
public void testReadWordHighBitSet() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { (byte)0xff, (byte)0xff })) {
assertEquals(0xffff, bs.readWord());
assertEquals(2, bs.getTotalBytesRead());
Assert.assertEquals(0xffff, bs.readWord());
Assert.assertEquals(2, bs.getTotalBytesRead());
}
}
@Test
public void testReadLong() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 })) {
assertEquals(0x04030201, bs.readLong());
assertEquals(4, bs.getTotalBytesRead());
Assert.assertEquals(0x04030201, bs.readLong());
Assert.assertEquals(4, bs.getTotalBytesRead());
}
}
@Test
public void testReadLongHighBitSet() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff })) {
assertEquals(0xffffffffL, bs.readLong());
assertEquals(4, bs.getTotalBytesRead());
Assert.assertEquals(0xffffffffL, bs.readLong());
Assert.assertEquals(4, bs.getTotalBytesRead());
}
}
@Test
public void testReadDate() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] {
// From NuFX documentation, final revision 3
@ -99,18 +111,19 @@ public class LittleEndianByteInputStreamTest extends TestCase {
0x00, 0x10, 0x0b, 0x58, 0x11, 0x0b, 0x00, 0x05, // 11:16:00am 11/17/1988 Thursday
0x00, 0x0c, 0x0d, 0x58, 0x16, 0x0a, 0x00, 0x07, // 01:12:00pm 10/22/1988 Saturday
})) {
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());
Assert.assertEquals(new GregorianCalendar(1988, Calendar.OCTOBER, 22, 1, 10, 0).getTime(), bs.readDate());
Assert.assertEquals(new GregorianCalendar(1988, Calendar.NOVEMBER, 17, 11, 16, 0).getTime(), bs.readDate());
Assert.assertEquals(new GregorianCalendar(1988, Calendar.OCTOBER, 22, 13, 12, 0).getTime(), bs.readDate());
Assert.assertEquals(24, bs.getTotalBytesRead());
}
}
@Test
public void testReadNullDate() throws IOException {
try (LittleEndianByteInputStream bs = new LittleEndianByteInputStream(new byte[] {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // null date
})) {
assertNull(bs.readDate());
assertEquals(8, bs.getTotalBytesRead());
Assert.assertNull(bs.readDate());
Assert.assertEquals(8, bs.getTotalBytesRead());
}
}
}

View File

@ -5,11 +5,14 @@ import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.junit.Test;
/**
* Exercise the LittleEndianByteOutputStream class.
* @author robgreene@users.sourceforge.net
*/
public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
public class LittleEndianByteOutputStreamTest extends TestBase {
@Test
public void testWriteA() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -17,6 +20,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals("a".getBytes(), os.toByteArray());
}
@Test
public void testWriteB() throws IOException {
// Just to ensure we can write chunks of bytes...
ByteArrayOutputStream os = new ByteArrayOutputStream();
@ -25,6 +29,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals("hello".getBytes(), os.toByteArray());
}
@Test
public void testWriteNuFileId() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -32,6 +37,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xe9, 0x6c, (byte)0xe5 }, os.toByteArray());
}
@Test
public void testCheckNuFxId() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -39,6 +45,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { 0x4e, (byte)0xf5, 0x46, (byte)0xd8 }, os.toByteArray());
}
@Test
public void testWriteWord() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -47,6 +54,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { 0x01, 0x02, 0x03, 0x04 }, os.toByteArray());
}
@Test
public void testWriteWordHighBitSet() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -54,6 +62,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { (byte)0xff, (byte)0xff }, os.toByteArray());
}
@Test
public void testWriteLong() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -61,6 +70,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { 0x01, 0x02, 0x03, 0x04 }, os.toByteArray());
}
@Test
public void testWriteLongHighBitSet() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -68,6 +78,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
bs.close();
assertEquals(new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }, os.toByteArray());
}
@Test
public void testWriteDate() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);
@ -83,6 +94,7 @@ public class LittleEndianByteOutputStreamTest extends TestCaseHelper {
};
assertEquals(expected, os.toByteArray());
}
@Test
public void testWriteNullDate() throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
LittleEndianByteOutputStream bs = new LittleEndianByteOutputStream(os);

View File

@ -4,22 +4,28 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
/**
* Exercise the LZW encoder and decoders.
*
* @author robgreene@users.sourceforge.net
*/
public class LzwTest extends TestCaseHelper {
public class LzwTest extends TestBase {
@Test
public void testLzwDecoder() throws IOException {
LzwInputStream is = new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9));
int[] expected = getHgrColorsUncompressed();
int[] actual = new int[expected.length];
for (int i=0; i<actual.length; i++) actual[i] = is.read();
assertEquals("Expecting end of stream", -1, is.read());
assertEquals(expected, actual);
try (LzwInputStream is = new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9))) {
int[] expected = getHgrColorsUncompressed();
int[] actual = new int[expected.length];
for (int i=0; i<actual.length; i++) actual[i] = is.read();
Assert.assertEquals("Expecting end of stream", -1, is.read());
assertEquals(expected, actual);
}
}
@Test
public void testLzwEncoder() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
LzwOutputStream os = new LzwOutputStream(new BitOutputStream(baos, 9));
@ -32,31 +38,34 @@ public class LzwTest extends TestCaseHelper {
assertEquals(expected, actual);
}
@Test
public void testLzwDecoder2() throws IOException {
RleInputStream is = new RleInputStream(new LittleEndianByteInputStream(new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9))));
int bytes = 0;
int b;
while ( (b = is.read()) != -1) {
if (bytes % 16 == 0) {
if (bytes > 0) System.out.println();
System.out.printf("%08x: ", bytes);
try (RleInputStream is = new RleInputStream(new LittleEndianByteInputStream(new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getHgrColorsLzw1()), 9))))) {
int bytes = 0;
int b;
while ( (b = is.read()) != -1) {
if (bytes % 16 == 0) {
if (bytes > 0) System.out.println();
System.out.printf("%08x: ", bytes);
}
System.out.printf("%02x ", b);
bytes++;
}
System.out.printf("%02x ", b);
bytes++;
}
}
@Test
public void testLzwDecoder3() throws IOException {
LzwInputStream is = new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getTextFileLzw1()), 9));
System.out.printf("\n\nText File decoded...\n\n");
int i = 0;
int b = 0;
while (b != -1) {
b = is.read();
if (b != -1) System.out.printf("$%04x: %02x (%c)\n", i++, b, b);
try (LzwInputStream is = new LzwInputStream(new BitInputStream(new ByteArrayInputStream(getTextFileLzw1()), 9))) {
System.out.printf("\n\nText File decoded...\n\n");
int i = 0;
int b = 0;
while (b != -1) {
b = is.read();
if (b != -1) System.out.printf("$%04x: %02x (%c)\n", i++, b, b);
}
System.out.printf("** END **");
}
System.out.printf("** END **");
}
protected byte[] asBytes(int[] source) {
@ -69,47 +78,4 @@ public class LzwTest extends TestCaseHelper {
for (int i=0; i<source.length; i++) array[i] = source[i] & 0xff;
return array;
}
protected byte[] getHgrColorsLzw1() {
return new byte[] {
(byte)0xdb, 0x00, 0x1c, (byte)0xd8, 0x56, 0x65, (byte)0xa0, (byte)0x8a,
(byte)0x81, 0x00, (byte)0xde, 0x6c, 0x3b, 0x48, 0x10, (byte)0xa1,
(byte)0xc2, 0x3f, 0x0f, 0x02, (byte)0xfe, (byte)0x93, 0x48, 0x11,
(byte)0xc0, 0x44, (byte)0x8b, 0x15, 0x2f, 0x6a, (byte)0xcc, (byte)0xc8,
0x11, 0x23, (byte)0x80, 0x73
};
}
protected int[] getHgrColorsUncompressed() {
return new int[] {
0xdb, 0x00, 0x07, 0xdb, 0x55, 0x07, 0xdb, 0x2a,
0x07, 0xdb, 0x00, 0x6f, 0xdb, 0x2a, 0x07, 0xdb,
0x55, 0x07, 0xdb, 0x00, 0x6f, 0xdb, 0x7f, 0x0f,
0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00,
0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb,
0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff,
0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00,
0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb,
0x00, 0xff, 0xdb, 0x00, 0xe7
};
}
protected byte[] getTextFileLzw1() {
return new byte[] {
0x54, (byte)0x90, 0x24, (byte)0x99, 0x02, 0x62, 0x20, (byte)0x88,
(byte)0x80, 0x45, 0x40, 0x5C, 0x09, (byte)0x92, 0x45, 0x61,
(byte)0xC2, (byte)0x85, 0x53, (byte)0x90, (byte)0x80, 0x78, 0x52, 0x45,
0x0A, (byte)0x88, 0x21, 0x4C, (byte)0x9E, 0x20, (byte)0x9C, (byte)0xC2,
0x42, 0x61, (byte)0x90, (byte)0x88, 0x13, 0x2B, 0x5E, (byte)0xCC,
(byte)0xB8, (byte)0xB1, 0x23, 0x44, (byte)0x89, 0x14, 0x2D, 0x62,
(byte)0xD4, (byte)0x88, (byte)0xA4, (byte)0xC8, 0x14, 0x17, 0x20, 0x0E,
0x0A, 0x24, 0x68, 0x10, (byte)0xA1, (byte)0xC7, (byte)0x86, 0x57,
0x1E, 0x7E, 0x44, 0x29, 0x72, 0x65, 0x49, 0x10,
0x53, (byte)0x9E, (byte)0x80, 0x28, 0x12, 0x44, 0x0A, (byte)0x93,
(byte)0x86, 0x49, (byte)0x9C, (byte)0xC8, 0x4C, (byte)0xD8, (byte)0xE4, (byte)0x89,
0x14, 0x27, 0x49, (byte)0x8F, (byte)0xB8, (byte)0xD8, 0x06, (byte)0xE0,
0x1F, 0x55, (byte)0xAB, 0x55, (byte)0xAF, 0x6A, (byte)0xCD, (byte)0xCA,
0x15, (byte)0xAB, (byte)0xD7, (byte)0xAD, 0x5F, (byte)0xBB, 0x52, (byte)0xC5,
0x03, 0x00
};
}
}

View File

@ -1,23 +1,28 @@
package com.webcodepro.shrinkit.io;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.junit.Test;
/**
* Test some LZW/1 format streams.
*
* @author robgreene@users.sourceforge.net
*/
public class NufxLzw1Test extends TestCaseHelper {
public class NufxLzw1Test extends TestBase {
@Test
public void testTextFile() throws IOException {
NufxLzw1InputStream is = new NufxLzw1InputStream(new LittleEndianByteInputStream(getTextFileLzw1StreamData()));
byte[] expected = getTextFileData();
byte[] actual = new byte[expected.length];
is.read(actual);
assertEquals(expected, actual);
assertTrue(is.isCrcValid());
try (NufxLzw1InputStream is = new NufxLzw1InputStream(new LittleEndianByteInputStream(getTextFileLzw1StreamData()))) {
byte[] expected = getTextFileData();
byte[] actual = new byte[expected.length];
is.read(actual);
assertEquals(expected, actual);
assertTrue(is.isCrcValid());
}
}
private byte[] getTextFileLzw1StreamData() {
return new byte[] {
(byte)0xCA, 0x42, 0x00, (byte)0xDB, (byte)0xB7, 0x00, 0x01, 0x54,

View File

@ -5,6 +5,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.junit.Test;
import com.webcodepro.shrinkit.HeaderBlock;
import com.webcodepro.shrinkit.NuFileArchive;
import com.webcodepro.shrinkit.ThreadRecord;
@ -15,20 +17,24 @@ import com.webcodepro.shrinkit.ThreadRecord;
*
* @author robgreene@users.sourceforge.net
*/
public class NufxLzwTest extends TestCaseHelper {
public class NufxLzwTest extends TestBase {
@Test
public void testNufxLzw1() throws IOException {
check("/APPLE.II-LZW1.SHK", "APPLE.II", "/APPLE.II.txt");
}
@Test
public void testNufxLzw2() throws IOException {
check("/APPLE.II-LZW2.SHK", "APPLE.II", "/APPLE.II.txt");
}
@Test
public void testLargerFilesNufxLzw1() throws IOException {
check("/PRODOS.MSTR-LZW1.SHK", "SYSUTIL.SYSTEM", "/SYSUTIL.SYSTEM.bin");
check("/PRODOS.MSTR-LZW1.SHK", "UTIL.0", "/UTIL.0.bin");
check("/PRODOS.MSTR-LZW1.SHK", "UTIL.1", "/UTIL.1.bin");
check("/PRODOS.MSTR-LZW1.SHK", "UTIL.2", "/UTIL.2.bin");
}
@Test
public void testLargerFilesNufxLzw2() throws IOException {
check("/PRODOS.MSTR-LZW2.SHK", "SYSUTIL.SYSTEM", "/SYSUTIL.SYSTEM.bin");
check("/PRODOS.MSTR-LZW2.SHK", "UTIL.0", "/UTIL.0.bin");
@ -36,6 +42,7 @@ public class NufxLzwTest extends TestCaseHelper {
check("/PRODOS.MSTR-LZW2.SHK", "UTIL.2", "/UTIL.2.bin");
}
@Test
public void testUncompressedFiles() throws IOException {
check("/UNCOMPRESSED.SHK", "APPLE.II-LZW1.SHK", "/APPLE.II-LZW1.SHK");
check("/UNCOMPRESSED.SHK", "APPLE.II-LZW2.SHK", "/APPLE.II-LZW2.SHK");
@ -53,7 +60,7 @@ public class NufxLzwTest extends TestCaseHelper {
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();

View File

@ -6,15 +6,18 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.junit.Test;
/**
* Exercise the RLE encoder and decoders.
*
* @author robgreene@users.sourceforge.net
*/
public class RleTest extends TestCaseHelper {
public class RleTest extends TestBase {
/**
* Test the RleInputStream to verify decoding.
*/
@Test
public void testInputStream() throws IOException {
InputStream is = new RleInputStream(new ByteArrayInputStream(getPatternFileRle()));
ByteArrayOutputStream os = new ByteArrayOutputStream();
@ -26,6 +29,7 @@ public class RleTest extends TestCaseHelper {
/**
* Test the RleOutputStream to verify compression.
*/
@Test
public void testOutputStream() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
RleOutputStream os = new RleOutputStream(baos);
@ -39,6 +43,7 @@ public class RleTest extends TestCaseHelper {
* Test the RleOutputStream with the escape character to ensure it <em>always</em> is encoded.
* Note that a file with lots of 0xdb codes will grow.
*/
@Test
public void testOutputStreamEscapeCharacter() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
RleOutputStream os = new RleOutputStream(baos);

View File

@ -0,0 +1,89 @@
package com.webcodepro.shrinkit.io;
import org.junit.Assert;
import junit.framework.AssertionFailedError;
/**
* Some common testing methods.
*
* @author robgreene@users.sourceforge.net
*/
public abstract class TestBase {
/**
* Compare two byte arrays.
*/
public void assertEquals(byte[] expected, byte[] actual) {
try {
Assert.assertEquals("Length mismatch", expected.length, actual.length);
for (int i=0; i<expected.length; i++) {
Assert.assertEquals("Byte mismatch at offset " + i, expected[i], actual[i]);
}
} catch (AssertionFailedError err) {
int minvalue = Math.min(expected.length, actual.length);
for (int i=0; i<minvalue; i++) {
Assert.assertEquals(err.getMessage() + " -- Byte mismatch at offset " + i, expected[i], actual[i]);
}
Assert.fail(err.getMessage() + " -- all bytes that could be compared match");
}
}
/**
* Compare two int arrays.
*/
public void assertEquals(int[] expected, int[] actual) {
try {
Assert.assertEquals("Length mismatch", expected.length, actual.length);
for (int i=0; i<expected.length; i++) {
Assert.assertEquals("int mismatch at offset " + i, expected[i], actual[i]);
}
} catch (AssertionFailedError err) {
int minvalue = Math.min(expected.length, actual.length);
for (int i=0; i<minvalue; i++) {
Assert.assertEquals(err.getMessage() + " -- Byte mismatch at offset " + i, expected[i], actual[i]);
}
Assert.fail(err.getMessage() + " -- all bytes that could be compared match");
}
}
public byte[] getHgrColorsLzw1() {
return new byte[] {
(byte)0xdb, 0x00, 0x1c, (byte)0xd8, 0x56, 0x65, (byte)0xa0, (byte)0x8a,
(byte)0x81, 0x00, (byte)0xde, 0x6c, 0x3b, 0x48, 0x10, (byte)0xa1,
(byte)0xc2, 0x3f, 0x0f, 0x02, (byte)0xfe, (byte)0x93, 0x48, 0x11,
(byte)0xc0, 0x44, (byte)0x8b, 0x15, 0x2f, 0x6a, (byte)0xcc, (byte)0xc8,
0x11, 0x23, (byte)0x80, 0x73
};
}
public int[] getHgrColorsUncompressed() {
return new int[] {
0xdb, 0x00, 0x07, 0xdb, 0x55, 0x07, 0xdb, 0x2a,
0x07, 0xdb, 0x00, 0x6f, 0xdb, 0x2a, 0x07, 0xdb,
0x55, 0x07, 0xdb, 0x00, 0x6f, 0xdb, 0x7f, 0x0f,
0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00,
0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb,
0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff,
0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00,
0xff, 0xdb, 0x00, 0xff, 0xdb, 0x00, 0xff, 0xdb,
0x00, 0xff, 0xdb, 0x00, 0xe7
};
}
public byte[] getTextFileLzw1() {
return new byte[] {
0x54, (byte)0x90, 0x24, (byte)0x99, 0x02, 0x62, 0x20, (byte)0x88,
(byte)0x80, 0x45, 0x40, 0x5C, 0x09, (byte)0x92, 0x45, 0x61,
(byte)0xC2, (byte)0x85, 0x53, (byte)0x90, (byte)0x80, 0x78, 0x52, 0x45,
0x0A, (byte)0x88, 0x21, 0x4C, (byte)0x9E, 0x20, (byte)0x9C, (byte)0xC2,
0x42, 0x61, (byte)0x90, (byte)0x88, 0x13, 0x2B, 0x5E, (byte)0xCC,
(byte)0xB8, (byte)0xB1, 0x23, 0x44, (byte)0x89, 0x14, 0x2D, 0x62,
(byte)0xD4, (byte)0x88, (byte)0xA4, (byte)0xC8, 0x14, 0x17, 0x20, 0x0E,
0x0A, 0x24, 0x68, 0x10, (byte)0xA1, (byte)0xC7, (byte)0x86, 0x57,
0x1E, 0x7E, 0x44, 0x29, 0x72, 0x65, 0x49, 0x10,
0x53, (byte)0x9E, (byte)0x80, 0x28, 0x12, 0x44, 0x0A, (byte)0x93,
(byte)0x86, 0x49, (byte)0x9C, (byte)0xC8, 0x4C, (byte)0xD8, (byte)0xE4, (byte)0x89,
0x14, 0x27, 0x49, (byte)0x8F, (byte)0xB8, (byte)0xD8, 0x06, (byte)0xE0,
0x1F, 0x55, (byte)0xAB, 0x55, (byte)0xAF, 0x6A, (byte)0xCD, (byte)0xCA,
0x15, (byte)0xAB, (byte)0xD7, (byte)0xAD, 0x5F, (byte)0xBB, 0x52, (byte)0xC5,
0x03, 0x00
};
}
}

View File

@ -1,46 +0,0 @@
package com.webcodepro.shrinkit.io;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Some commmon testing methods.
*
* @author robgreene@users.sourceforge.net
*/
public abstract class TestCaseHelper extends TestCase {
/**
* Compare two byte arrays.
*/
public void assertEquals(byte[] expected, byte[] actual) {
try {
assertEquals("Length mismatch", expected.length, actual.length);
for (int i=0; i<expected.length; i++) {
assertEquals("Byte mismatch at offset " + i, expected[i], actual[i]);
}
} catch (AssertionFailedError err) {
int minvalue = Math.min(expected.length, actual.length);
for (int i=0; i<minvalue; i++) {
assertEquals(err.getMessage() + " -- Byte mismatch at offset " + i, expected[i], actual[i]);
}
fail(err.getMessage() + " -- all bytes that could be compared match");
}
}
/**
* Compare two int arrays.
*/
public void assertEquals(int[] expected, int[] actual) {
try {
assertEquals("Length mismatch", expected.length, actual.length);
for (int i=0; i<expected.length; i++) {
assertEquals("int mismatch at offset " + i, expected[i], actual[i]);
}
} catch (AssertionFailedError err) {
int minvalue = Math.min(expected.length, actual.length);
for (int i=0; i<minvalue; i++) {
assertEquals(err.getMessage() + " -- Byte mismatch at offset " + i, expected[i], actual[i]);
}
fail(err.getMessage() + " -- all bytes that could be compared match");
}
}
}