Giving FileStore a 'flush' method to push out changes. (The alternative was some sort of provider that Source utilized, but that seems overly complicated.) This added a 'Source#replaceAllBytes'.

This commit is contained in:
a2geek committed 2026-10-12 16:12:00 -05:00
1 parent d32c27bde9
commit 58fe61d324
13 files changed
+124 -6

No files matched your search

@@ -34,7 +34,7 @@ import java.util.stream.Collectors;
public class FileEntrySource implements Source {
private final FileEntry fileEntry;
private final DataBuffer buffer;
private DataBuffer buffer;
private boolean changed;
private final Set<Hint> hints;
@@ -98,6 +98,12 @@ public class FileEntrySource implements Source {
changed = true;
}
@Override
public void replaceAllBytes(DataBuffer data) {
buffer = data;
changed = true;
}
@Override
public boolean hasChanged() {
return changed;
@@ -31,7 +31,6 @@ import org.applecommander.util.FileMagic;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.attribute.FileTime;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;
import java.util.zip.ZipEntry;
@@ -83,6 +82,10 @@ public class ZipFileEntry implements FileEntry {
return entry.getLastModifiedTime();
}
public FileTime getLastAccessTime() {
return entry.getLastAccessTime();
}
public long getCrc() {
return entry.getCrc();
}
@@ -91,6 +94,10 @@ public class ZipFileEntry implements FileEntry {
return entry.getCompressedSize();
}
public String getComment() {
return entry.getComment();
}
public int getMethod() {
return entry.getMethod();
}
@@ -130,8 +137,8 @@ public class ZipFileEntry implements FileEntry {
.unlocked()
.size(getSize())
.BIN(0x0000)
.creation(new Date(getCreationTime().toMillis()))
.modification(new Date(getLastModifiedTime().toMillis()))
.creation(getCreationTime())
.modification(getLastModifiedTime())
.get();
}
@@ -26,9 +26,11 @@ import org.applecommander.filestore.FileEntry;
import org.applecommander.filestore.FileStore;
import org.applecommander.source.Source;
import org.applecommander.util.Container;
import org.applecommander.util.DataBuffer;
import org.applecommander.util.InformationGroup;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
@@ -39,6 +41,9 @@ import java.util.Objects;
import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import static org.applecommander.util.Shorthand.copy;
public class ZipFileStore implements FileStore {
private final Source source;
@@ -93,12 +98,33 @@ public class ZipFileStore implements FileStore {
.addLongField("Size", ZipFileEntry::getCompressedSize, Mode.DETAIL)
.addPercentField("Ratio", ZipFileEntry::getCompressedSize, ZipFileEntry::getSize, "%2.0f%%", Mode.DETAIL)
.addFileTimeField("Creation", ZipFileEntry::getCreationTime)
.addFileTimeField("Last Access", ZipFileEntry::getLastAccessTime, Mode.DETAIL)
.addFileTimeField("Last Modified", ZipFileEntry::getLastModifiedTime)
.addLongField("CRC-32", ZipFileEntry::getCrc, "%08x", Mode.DETAIL)
.addStringField("Name", FileEntry::getName)
.toList();
}
@Override
public void flush() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zip = new ZipOutputStream(baos)) {
for (FileEntry fileEntry : entries) {
ZipFileEntry zipFileEntry = (ZipFileEntry) fileEntry;
ZipEntry zipEntry = new ZipEntry(zipFileEntry.getName());
copy(zipFileEntry::getCreationTime, zipEntry::setCreationTime);
copy(zipFileEntry::getLastAccessTime, zipEntry::setLastAccessTime);
copy(zipFileEntry::getLastModifiedTime, zipEntry::setLastModifiedTime);
copy(zipFileEntry::getComment, zipEntry::setComment);
zip.putNextEntry(zipEntry);
zip.write(fileEntry.getDataFork().asBytes());
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
source.replaceAllBytes(DataBuffer.wrap(baos.toByteArray()));
}
@Override
public boolean can(Capability capability) {
return false;
@@ -20,6 +20,7 @@
package org.applecommander.archive.zip;
import org.applecommander.filestore.FileStoreFactory;
import org.applecommander.source.Source;
import org.applecommander.util.DataBuffer;
public class ZipFileStoreFactory implements FileStoreFactory {
@@ -32,4 +33,8 @@ public class ZipFileStoreFactory implements FileStoreFactory {
ctx.fileStores.add(new ZipFileStore(ctx.source));
}
}
public static ZipFileStore create(Source source) {
return new ZipFileStore(source);
}
}
@@ -42,4 +42,20 @@ public interface FileStore extends CapabilityProvider, Container, InformationPro
/// Yields a list of columns to be used in this display mode.
List<DisplayColumn> getDisplayColumns();
/// Flush any pending writes back to the source. This is intended to handle archives
/// as they do not have a fixed structure to write changes. `flush` should be invoked
/// before a save.
///
/// Example usage:
///
/// ```java
/// FileStore fileStore = fileStoreSelection.getSelectedItem();
/// fileStore.flush();
/// Source source = fileStore.get(Source.class).orElseThrow();
/// source.save();
/// ```
default void flush() {
// Do Nothing
}
}
@@ -125,6 +125,11 @@ public class DiskCopyImage implements Source {
this.source.writeBytes(HEADER_SIZE+offset, data);
}
@Override
public void replaceAllBytes(DataBuffer data) {
this.source.replaceAllBytes(data);
}
@Override
public boolean hasChanged() {
return source.hasChanged();
@@ -126,6 +126,11 @@ public class UniversalDiskImage implements Source {
source.writeBytes(this.info.dataOffset + offset, data);
}
@Override
public void replaceAllBytes(DataBuffer data) {
source.replaceAllBytes(data);
}
@Override
public boolean hasChanged() {
return source.hasChanged();
@@ -31,7 +31,7 @@ import java.util.Optional;
import java.util.Set;
public class DataBufferSource implements Source {
private final DataBuffer dataBuffer;
private DataBuffer dataBuffer;
private final String name;
private final Set<Capability> capabilities;
private final Set<Hint> hints;
@@ -74,6 +74,12 @@ public class DataBufferSource implements Source {
changed = true;
}
@Override
public void replaceAllBytes(DataBuffer data) {
dataBuffer = data;
changed = true;
}
@Override
public boolean hasChanged() {
return changed;
@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
public class FileEntrySource implements Source {
private final FileEntry fileEntry;
private final DataBuffer buffer;
private DataBuffer buffer;
private boolean changed;
private final Set<Hint> hints;
@@ -85,6 +85,12 @@ public class FileEntrySource implements Source {
changed = true;
}
@Override
public void replaceAllBytes(DataBuffer data) {
buffer = data;
changed = true;
}
@Override
public boolean hasChanged() {
return changed;
@@ -111,6 +111,12 @@ public class FileSource implements Source {
changed = true;
}
@Override
public void replaceAllBytes(DataBuffer data) {
buffer = data;
changed = true;
}
@Override
public boolean hasChanged() {
return changed;
@@ -74,6 +74,9 @@ public interface Source extends CapabilityProvider, HintProvider, Container, Inf
/// Write bytes to this source. Updates the changed status.
void writeBytes(int offset, DataBuffer data);
/// Replace ALL bytes in this Source.
void replaceAllBytes(DataBuffer data);
/// Indicates if this source has changed.
boolean hasChanged();
@@ -22,6 +22,7 @@ package org.applecommander.transfer;
import org.applecommander.util.DataBuffer;
import org.applecommander.util.FileMagic;
import java.nio.file.attribute.FileTime;
import java.util.Date;
import java.util.Optional;
@@ -102,10 +103,22 @@ public record ProdosAttributes(String name, int access, int fileType, int auxTyp
this.size = size;
return this;
}
public Builder creation(FileTime creation) {
if (creation != null) {
this.creation = new Date(creation.toMillis());
}
return this;
}
public Builder creation(Date creation) {
this.creation = creation;
return this;
}
public Builder modification(FileTime modified) {
if (modified != null) {
this.modified = new Date(modified.toMillis());
}
return this;
}
public Builder modification(Date modified) {
this.modified = modified;
return this;
@@ -0,0 +1,14 @@
package org.applecommander.util;
import java.util.function.Consumer;
import java.util.function.Supplier;
public abstract class Shorthand {
/// This is a shorthand method to only set non-null values.
public static <T> void copy(Supplier<T> supplier, Consumer<T> consumer) {
T value = supplier.get();
if (value != null) {
consumer.accept(value);
}
}
}