1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-07-01 01:23:30 +00:00

Make Mount.openForRead always return a SeekableByteChannel

I want to make some further changes to Mount here, but this helps
simplify BinaryReadableHandle a little.
This commit is contained in:
Jonathan Coates 2022-12-03 18:20:50 +00:00
parent c96172e78d
commit fc5f296eeb
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
8 changed files with 53 additions and 68 deletions

View File

@ -8,7 +8,7 @@
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
@ -60,15 +60,13 @@ public interface Mount {
long getSize(String path) throws IOException; long getSize(String path) throws IOException;
/** /**
* Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. * Opens a file with a given path, and returns a {@link SeekableByteChannel} representing its contents.
* *
* @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram".
* @return A channel representing the contents of the file. If the channel implements * @return A channel representing the contents of the file.
* {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary positions when using binary
* mode.
* @throws IOException If the file does not exist, or could not be opened. * @throws IOException If the file does not exist, or could not be opened.
*/ */
ReadableByteChannel openForRead(String path) throws IOException; SeekableByteChannel openForRead(String path) throws IOException;
/** /**
* Get attributes about the given file. * Get attributes about the given file.

View File

@ -8,13 +8,11 @@
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.core.filesystem.TrackingCloseable; import dan200.computercraft.core.filesystem.TrackingCloseable;
import dan200.computercraft.core.util.Nullability;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SeekableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -29,22 +27,19 @@
public class BinaryReadableHandle extends HandleGeneric { public class BinaryReadableHandle extends HandleGeneric {
private static final int BUFFER_SIZE = 8192; private static final int BUFFER_SIZE = 8192;
private final ReadableByteChannel reader; private final SeekableByteChannel channel;
final @Nullable SeekableByteChannel seekable;
private final ByteBuffer single = ByteBuffer.allocate(1); private final ByteBuffer single = ByteBuffer.allocate(1);
BinaryReadableHandle(ReadableByteChannel reader, @Nullable SeekableByteChannel seekable, TrackingCloseable closeable) { BinaryReadableHandle(SeekableByteChannel channel, TrackingCloseable closeable) {
super(closeable); super(closeable);
this.reader = reader; this.channel = channel;
this.seekable = seekable;
} }
public static BinaryReadableHandle of(ReadableByteChannel channel, TrackingCloseable closeable) { public static BinaryReadableHandle of(SeekableByteChannel channel, TrackingCloseable closeable) {
var seekable = asSeekable(channel); return new BinaryReadableHandle(channel, closeable);
return seekable == null ? new BinaryReadableHandle(channel, null, closeable) : new Seekable(seekable, closeable);
} }
public static BinaryReadableHandle of(ReadableByteChannel channel) { public static BinaryReadableHandle of(SeekableByteChannel channel) {
return of(channel, new TrackingCloseable.Impl(channel)); return of(channel, new TrackingCloseable.Impl(channel));
} }
@ -69,21 +64,19 @@ public final Object[] read(Optional<Integer> countArg) throws LuaException {
if (countArg.isPresent()) { if (countArg.isPresent()) {
int count = countArg.get(); int count = countArg.get();
if (count < 0) throw new LuaException("Cannot read a negative number of bytes"); if (count < 0) throw new LuaException("Cannot read a negative number of bytes");
if (count == 0 && seekable != null) { if (count == 0) return channel.position() >= channel.size() ? null : new Object[]{ "" };
return seekable.position() >= seekable.size() ? null : new Object[]{ "" };
}
if (count <= BUFFER_SIZE) { if (count <= BUFFER_SIZE) {
var buffer = ByteBuffer.allocate(count); var buffer = ByteBuffer.allocate(count);
var read = reader.read(buffer); var read = channel.read(buffer);
if (read < 0) return null; if (read < 0) return null;
buffer.flip(); buffer.flip();
return new Object[]{ buffer }; return new Object[]{ buffer };
} else { } else {
// Read the initial set of characters, failing if none are read. // Read the initial set of characters, failing if none are read.
var buffer = ByteBuffer.allocate(BUFFER_SIZE); var buffer = ByteBuffer.allocate(BUFFER_SIZE);
var read = reader.read(buffer); var read = channel.read(buffer);
if (read < 0) return null; if (read < 0) return null;
// If we failed to read "enough" here, let's just abort // If we failed to read "enough" here, let's just abort
@ -99,7 +92,7 @@ public final Object[] read(Optional<Integer> countArg) throws LuaException {
parts.add(buffer); parts.add(buffer);
while (read >= BUFFER_SIZE && totalRead < count) { while (read >= BUFFER_SIZE && totalRead < count) {
buffer = ByteBuffer.allocate(Math.min(BUFFER_SIZE, count - totalRead)); buffer = ByteBuffer.allocate(Math.min(BUFFER_SIZE, count - totalRead));
read = reader.read(buffer); read = channel.read(buffer);
if (read < 0) break; if (read < 0) break;
totalRead += read; totalRead += read;
@ -117,7 +110,7 @@ public final Object[] read(Optional<Integer> countArg) throws LuaException {
} }
} else { } else {
single.clear(); single.clear();
var b = reader.read(single); var b = channel.read(single);
return b == -1 ? null : new Object[]{ single.get(0) & 0xFF }; return b == -1 ? null : new Object[]{ single.get(0) & 0xFF };
} }
} catch (IOException e) { } catch (IOException e) {
@ -139,14 +132,14 @@ public final Object[] readAll() throws LuaException {
checkOpen(); checkOpen();
try { try {
var expected = 32; var expected = 32;
if (seekable != null) expected = Math.max(expected, (int) (seekable.size() - seekable.position())); expected = Math.max(expected, (int) (channel.size() - channel.position()));
var stream = new ByteArrayOutputStream(expected); var stream = new ByteArrayOutputStream(expected);
var buf = ByteBuffer.allocate(8192); var buf = ByteBuffer.allocate(8192);
var readAnything = false; var readAnything = false;
while (true) { while (true) {
buf.clear(); buf.clear();
var r = reader.read(buf); var r = channel.read(buf);
if (r == -1) break; if (r == -1) break;
readAnything = true; readAnything = true;
@ -179,7 +172,7 @@ public final Object[] readLine(Optional<Boolean> withTrailingArg) throws LuaExce
boolean readAnything = false, readRc = false; boolean readAnything = false, readRc = false;
while (true) { while (true) {
single.clear(); single.clear();
var read = reader.read(single); var read = channel.read(single);
if (read <= 0) { if (read <= 0) {
// Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it // Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it
// back. // back.
@ -211,11 +204,6 @@ public final Object[] readLine(Optional<Boolean> withTrailingArg) throws LuaExce
} }
} }
public static class Seekable extends BinaryReadableHandle {
Seekable(SeekableByteChannel seekable, TrackingCloseable closeable) {
super(seekable, seekable, closeable);
}
/** /**
* Seek to a new position within the file, changing where bytes are written to. The new position is an offset * Seek to a new position within the file, changing where bytes are written to. The new position is an offset
* given by {@code offset}, relative to a start position determined by {@code whence}: * given by {@code offset}, relative to a start position determined by {@code whence}:
@ -239,7 +227,6 @@ public static class Seekable extends BinaryReadableHandle {
@LuaFunction @LuaFunction
public final Object[] seek(Optional<String> whence, Optional<Long> offset) throws LuaException { public final Object[] seek(Optional<String> whence, Optional<Long> offset) throws LuaException {
checkOpen(); checkOpen();
return handleSeek(Nullability.assertNonNull(seekable), whence, offset); return handleSeek(channel, whence, offset);
}
} }
} }

View File

@ -14,7 +14,7 @@
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -110,7 +110,7 @@ private long getCachedSize(T file) throws IOException {
protected abstract long getSize(T file) throws IOException; protected abstract long getSize(T file) throws IOException;
@Override @Override
public ReadableByteChannel openForRead(String path) throws IOException { public SeekableByteChannel openForRead(String path) throws IOException {
var file = get(path); var file = get(path);
if (file == null || file.isDirectory()) throw new FileOperationException(path, NO_SUCH_FILE); if (file == null || file.isDirectory()) throw new FileOperationException(path, NO_SUCH_FILE);

View File

@ -182,7 +182,7 @@ public long getSize(String path) throws IOException {
} }
@Override @Override
public ReadableByteChannel openForRead(String path) throws IOException { public SeekableByteChannel openForRead(String path) throws IOException {
if (created()) { if (created()) {
var file = getRealPath(path); var file = getRealPath(path);
if (file.exists() && !file.isDirectory()) return FileChannel.open(file.toPath(), READ_OPTIONS); if (file.exists() && !file.isDirectory()) return FileChannel.open(file.toPath(), READ_OPTIONS);

View File

@ -18,7 +18,7 @@
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.nio.channels.Channel; import java.nio.channels.Channel;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.nio.file.AccessDeniedException; import java.nio.file.AccessDeniedException;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
@ -346,7 +346,7 @@ void removeFile(FileSystemWrapper<?> handle) {
} }
} }
public synchronized <T extends Closeable> FileSystemWrapper<T> openForRead(String path, Function<ReadableByteChannel, T> open) throws FileSystemException { public synchronized <T extends Closeable> FileSystemWrapper<T> openForRead(String path, Function<SeekableByteChannel, T> open) throws FileSystemException {
cleanup(); cleanup();
path = sanitizePath(path); path = sanitizePath(path);

View File

@ -11,7 +11,7 @@
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.nio.file.AccessDeniedException; import java.nio.file.AccessDeniedException;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
@ -120,7 +120,7 @@ public BasicFileAttributes getAttributes(String path) throws FileSystemException
} }
} }
public ReadableByteChannel openForRead(String path) throws FileSystemException { public SeekableByteChannel openForRead(String path) throws FileSystemException {
path = toLocal(path); path = toLocal(path);
try { try {
if (mount.exists(path) && !mount.isDirectory(path)) { if (mount.exists(path) && !mount.isDirectory(path)) {

View File

@ -8,7 +8,7 @@
import dan200.computercraft.api.filesystem.Mount; import dan200.computercraft.api.filesystem.Mount;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
@ -42,7 +42,7 @@ public long getSize(String path) throws IOException {
} }
@Override @Override
public ReadableByteChannel openForRead(String path) throws IOException { public SeekableByteChannel openForRead(String path) throws IOException {
return parent.openForRead(getFullPath(path)); return parent.openForRead(getFullPath(path));
} }

View File

@ -13,7 +13,7 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
@ -111,7 +111,7 @@ public long getSize(String path) {
} }
@Override @Override
public ReadableByteChannel openForRead(String path) throws FileOperationException { public SeekableByteChannel openForRead(String path) throws FileOperationException {
var file = files.get(path); var file = files.get(path);
if (file == null) throw new FileOperationException(path, "File not found"); if (file == null) throw new FileOperationException(path, "File not found");
return new ArrayByteChannel(file); return new ArrayByteChannel(file);