Adding some file testing capabilities; tweaked comments.
This commit is contained in:
parent
153e0aa220
commit
05ab07e323
|
@ -20,7 +20,7 @@ import java.util.function.Consumer;
|
|||
|
||||
/**
|
||||
* Support reading of data from and AppleSingle source.
|
||||
* Does not implement all components at this time, extend as required.
|
||||
* Does not implement all components at this time, extend as required and/or understood.
|
||||
* All construction has been deferred to the <code>read(...)</code> or {@link #builder()} methods.
|
||||
* <p>
|
||||
* Currently supports entries:<br/>
|
||||
|
@ -85,11 +85,12 @@ public class AppleSingle {
|
|||
return fileDatesInfo;
|
||||
}
|
||||
|
||||
/** Write this AppleSingle to the given output stream. Note that it only supports the "understood" components. */
|
||||
public void save(OutputStream outputStream) throws IOException {
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
Optional.ofNullable(this.realName)
|
||||
.map(String::getBytes)
|
||||
.map(b -> Entry.create(EntryType.REAL_NAME, b))
|
||||
.map(Entry::realName)
|
||||
.ifPresent(entries::add);
|
||||
Optional.ofNullable(this.prodosFileInfo)
|
||||
.map(ProdosFileInfo::toEntry)
|
||||
|
@ -98,18 +99,20 @@ public class AppleSingle {
|
|||
.map(FileDatesInfo::toEntry)
|
||||
.ifPresent(entries::add);
|
||||
Optional.ofNullable(this.resourceFork)
|
||||
.map(b -> Entry.create(EntryType.RESOURCE_FORK, b))
|
||||
.map(Entry::resourceFork)
|
||||
.ifPresent(entries::add);
|
||||
Optional.ofNullable(this.dataFork)
|
||||
.map(b -> Entry.create(EntryType.DATA_FORK, b))
|
||||
.map(Entry::dataFork)
|
||||
.ifPresent(entries::add);
|
||||
write(outputStream, entries);
|
||||
}
|
||||
/** Save this AppleSingle to a File. */
|
||||
public void save(File file) throws IOException {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||
save(outputStream);
|
||||
}
|
||||
}
|
||||
/** Save this AppleSingle to a Path. */
|
||||
public void save(Path path) throws IOException {
|
||||
try (OutputStream outputStream = Files.newOutputStream(path)) {
|
||||
save(outputStream);
|
||||
|
@ -117,8 +120,8 @@ 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.
|
||||
* Common write capability for an AppleSingle based on entries. 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];
|
||||
|
@ -199,6 +202,44 @@ public class AppleSingle {
|
|||
message, String.join(",", versions), actual));
|
||||
}
|
||||
|
||||
/** Perform a quick test against a File to see if it is an AppleSingle file. */
|
||||
public static boolean test(File file) throws IOException {
|
||||
Objects.requireNonNull(file);
|
||||
return test(file.toPath());
|
||||
}
|
||||
/** Perform a quick test against a Path to see if it is an AppleSingle file. */
|
||||
public static boolean test(Path path) throws IOException {
|
||||
Objects.requireNonNull(path);
|
||||
return test(Files.readAllBytes(path));
|
||||
}
|
||||
/** Perform a quick test against an InputStream to see if it is an AppleSingle file. */
|
||||
public static boolean test(InputStream inputStream) throws IOException {
|
||||
Objects.requireNonNull(inputStream);
|
||||
return test(Utilities.toByteArray(inputStream));
|
||||
}
|
||||
/** Perform a quick test against a byte array to see if it is an AppleSingle file. */
|
||||
public static boolean test(byte[] data) {
|
||||
Objects.requireNonNull(data);
|
||||
return test(AppleSingleReader.builder(data).build());
|
||||
}
|
||||
/** Perform a quick test against a reader to see if it is an AppleSingle file. */
|
||||
public static boolean test(AppleSingleReader reader) {
|
||||
Objects.requireNonNull(reader);
|
||||
return check(reader, MAGIC_NUMBER) && check(reader, VERSION_NUMBER1, VERSION_NUMBER2);
|
||||
}
|
||||
private static boolean check(AppleSingleReader reader, int... expecteds) {
|
||||
try {
|
||||
final String message = ""; // Just needed for read.
|
||||
int actual = reader.read(Integer.BYTES, message).getInt();
|
||||
for (int expected : expecteds) {
|
||||
if (actual == expected) return true;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException ignored) {
|
||||
// Bad file! Fall through.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ public class Entry {
|
|||
private int offset;
|
||||
private int length;
|
||||
private byte[] data;
|
||||
|
||||
|
||||
/** Create an Entry and read it's data from the reader. */
|
||||
public static Entry create(AppleSingleReader reader) {
|
||||
Objects.requireNonNull(reader);
|
||||
|
||||
|
@ -28,6 +29,7 @@ public class Entry {
|
|||
entry.data = reader.readAt(entry.offset, entry.length, EntryType.findNameOrUnknown(entry)).array();
|
||||
return entry;
|
||||
}
|
||||
/** Create an Entry. */
|
||||
public static Entry create(EntryType type, byte[] data) {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(data);
|
||||
|
@ -38,6 +40,18 @@ public class Entry {
|
|||
entry.data = data;
|
||||
return entry;
|
||||
}
|
||||
/** Create a REAL_NAME entry. Primarily used for Java 8 streams. */
|
||||
public static Entry realName(byte[] data) {
|
||||
return create(EntryType.REAL_NAME, data);
|
||||
}
|
||||
/** Create a DATA_FORK entry. Primarily used for Java 8 streams. */
|
||||
public static Entry dataFork(byte[] data) {
|
||||
return create(EntryType.DATA_FORK, data);
|
||||
}
|
||||
/** Create a RESOURCE_FORK entry. Primarily used for Java 8 streams. */
|
||||
public static Entry resourceFork(byte[] data) {
|
||||
return create(EntryType.RESOURCE_FORK, data);
|
||||
}
|
||||
|
||||
public int getEntryId() {
|
||||
return entryId;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.github.applecommander.applesingle;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
@ -80,6 +80,17 @@ public class AppleSingleTest {
|
|||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testProdosFileNameFirstCharacter() {
|
||||
// Fails due to the first character being a digit.
|
||||
AppleSingle.builder().realName("1st-file").build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTest() throws IOException {
|
||||
// Known valid
|
||||
assertTrue(AppleSingle.test(getClass().getResourceAsStream(AS_HELLO_BIN)));
|
||||
// Known invalid
|
||||
assertFalse(AppleSingle.test(new byte[200]));
|
||||
// Could/should generate error due to truncated data, but this method should just give us a false.
|
||||
assertFalse(AppleSingle.test(new byte[3]));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue