Updating documentation and tests a bit.

This commit is contained in:
Rob Greene 2018-06-03 17:27:42 -05:00
parent 4627e08f9f
commit aae02d7323
7 changed files with 117 additions and 8 deletions

View File

@ -10,7 +10,7 @@ To include in a Maven project:
<dependency>
<groupId>net.sf.applecommander</groupId>
<artifactId>applesingle-api</artifactId>
<version>1.0.0</version>
<version>1.2.0</version>
</dependency>
```
@ -19,7 +19,7 @@ To include in a Gradle project:
```groovy
dependencies {
// ...
compile "net.sf.applecommander:applesingle-api:1.0.0"
compile "net.sf.applecommander:applesingle-api:1.2.0"
// ...
}
```
@ -58,3 +58,31 @@ as.save(file);
```
The `save(...)` method can save to a `File`, `Path`, or an `OutputStream`.
## Entries
If the higher-level API is insufficient, the lower-level API does allow either tracking of the processing
(see code for the `analyze` subcommand) or alternate processing of `Entry` objects (see the `filter`
subcommand).
To tap into the `AppleSingleReader` events, add as many reporters as required. For example, the `analyze`
command uses these to display the details of the AppleSingle file as it is read:
```java
AppleSingleReader reader = AppleSingleReader.builder(fileData)
.readAtReporter((start,chunk,desc) -> used.add(IntRange.of(start, start + chunk.length)))
.readAtReporter((start,chunk,desc) -> dumper.dump(start, chunk, desc))
.versionReporter(this::reportVersion)
.numberOfEntriesReporter(this::reportNumberOfEntries)
.entryReporter(this::reportEntry)
.build();
```
To work with the raw `Entry` objects, use the various `AppleSingle#asEntries` methods. For instance, the
`filter` subcommand bypasses the `AppleSingle` object altogether to implement the filter:
```java
List<Entry> entries = stdinFlag ? AppleSingle.asEntries(System.in) : AppleSingle.asEntries(inputFile);
// ...
AppleSingle.write(outputStream, newEntries);
```

View File

@ -111,6 +111,10 @@ public class AppleSingle {
}
}
/**
* Common write capability for an AppleSingle. Also can be used by external entities to
* write a properly formatted AppleSingle file without the ProDOS assumptions of AppleSingle.
*/
public static void write(OutputStream outputStream, List<Entry> entries) throws IOException {
final byte[] filler = new byte[16];
ByteBuffer buf = ByteBuffer.allocate(26).order(ByteOrder.BIG_ENDIAN);

View File

@ -6,6 +6,9 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
/**
* Represents an AppleSingle entry.
*/
public class Entry {
public static final int BYTES = 12;
private int entryId;

View File

@ -6,7 +6,7 @@ import java.time.Instant;
import java.util.function.IntSupplier;
public class FileDatesInfo {
/** The number of seconds at the begining of the AppleSingle date epoch since the Unix epoch began. */
/** The number of seconds at the beginning of the AppleSingle date epoch since the Unix epoch began. */
public static final Instant EPOCH_INSTANT = Instant.parse("2000-01-01T00:00:00.00Z");
/** Per the AppleSingle technical notes. */
public static final int UNKNOWN_DATE = 0x80000000;

View File

@ -0,0 +1,72 @@
package io.github.applecommander.applesingle;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.IOException;
public class AppleSingleReaderTest {
@Test(expected = NullPointerException.class)
public void testDoesNotAcceptNull() {
AppleSingleReader.builder(null);
}
@Test
public void testReporters() throws IOException {
Ticker versionCalled = new Ticker();
Ticker numberOfEntriesCalled = new Ticker();
Ticker entryReporterCalled = new Ticker();
Ticker readAtCalled = new Ticker();
// Intentionally calling ticker 2x to ensure events do get chained
AppleSingleReader r = AppleSingleReader.builder(SAMPLE_FILE)
.versionReporter(v -> versionCalled.tick())
.versionReporter(v -> assertEquals(AppleSingle.VERSION_NUMBER2, v.intValue()))
.versionReporter(v -> versionCalled.tick())
.numberOfEntriesReporter(n -> numberOfEntriesCalled.tick())
.numberOfEntriesReporter(n -> assertEquals(1, n.intValue()))
.numberOfEntriesReporter(n -> numberOfEntriesCalled.tick())
.readAtReporter((o,b,d) -> readAtCalled.tick())
.readAtReporter((o,b,d) -> readAtCalled.tick())
.entryReporter(e -> entryReporterCalled.tick())
.entryReporter(e -> assertEquals("Hello, World!\n", new String(e.getData())))
.entryReporter(e -> assertEquals(e.getEntryId(), EntryType.DATA_FORK.entryId))
.entryReporter(e -> entryReporterCalled.tick())
.build();
// Executes on the reader
AppleSingle.asEntries(r);
// Validate
assertEquals(2, versionCalled.count());
assertEquals(2, numberOfEntriesCalled.count());
assertEquals(2, entryReporterCalled.count());
assertTrue(readAtCalled.count() >= 2);
}
/**
* AppleSingle file with a simple Data Fork and nothing else.
* <br/>
* <code>
* $ echo "Hello, World!" | asu create --stdin-fork=data --filetype=txt --stdout | asu filter --include=1 --stdin --stdout | hexdump -C
* 00000000 00 05 16 00 00 02 00 00 00 00 00 00 00 00 00 00 |................|
* 00000010 00 00 00 00 00 00 00 00 00 01 00 00 00 01 00 00 |................|
* 00000020 00 26 00 00 00 0e 48 65 6c 6c 6f 2c 20 57 6f 72 |.&....Hello, Wor|
* 00000030 6c 64 21 0a |ld!.|
* </code>
*/
public static final byte[] SAMPLE_FILE = {
0x00, 0x05, 0x16, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x26, 0x00, 0x00, 0x00, 0x0e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f, 0x72,
0x6c, 0x64, 0x21, 0x0a
};
public static class Ticker {
private int count;
public void tick() {
this.count++;
}
public int count() {
return this.count;
}
}
}

View File

@ -4,13 +4,13 @@ For the included command-line utility, we are using `asu` for the name.
`as` is the GNU Assembler while `applesingle` is already on Macintoshes.
Hopefully that will prevent some confusion!
Note that all runs are with the `asu` alias defined as `alias asu='java -jar build/libs/applesingle-1.0.0.jar'`
Note that all runs are with the `asu` alias defined as `alias asu='java -jar build/libs/applesingle-1.2.0.jar'`
(adjust as necessary).
## Basic usage
```shell
$ asu
$ asu --help
Usage: asu [-hV] [--debug] [COMMAND]
AppleSingle utility
@ -21,10 +21,12 @@ Options:
-V, --version Print version information and exit.
Commands:
help Displays help information about the specified command
info Display information about an AppleSingle file
analyze Perform an analysis on an AppleSingle file
create Create an AppleSingle file
extract Extract contents of an AppleSingle file
filter Filter an AppleSingle file
help Displays help information about the specified command
info Display information about an AppleSingle file
```
## Subcommand help

View File

@ -54,7 +54,7 @@ public class AnalyzeCommand implements Callable<Void> {
List<IntRange> used = new ArrayList<>();
HexDumper dumper = HexDumper.standard();
AppleSingleReader reader = AppleSingleReader.builder(fileData)
.readAtReporter((start,b,d) -> used.add(IntRange.of(start, start + b.length)))
.readAtReporter((start,chunk,desc) -> used.add(IntRange.of(start, start + chunk.length)))
.readAtReporter((start,chunk,desc) -> dumper.dump(start, chunk, desc))
.versionReporter(this::reportVersion)
.numberOfEntriesReporter(this::reportNumberOfEntries)