mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 03:05:30 -04:00
Made files opened in read mode seekable more reliably.
This commit is contained in:
parent
bbe80bc5de
commit
d0d4f502ba
@ -94,7 +94,7 @@ trait Buffered extends OutputStreamFileSystem {
|
||||
FileUtils.deleteQuietly(childFile)
|
||||
childFile.createNewFile()
|
||||
val out = new io.FileOutputStream(childFile).getChannel
|
||||
val in = java.nio.channels.Channels.newChannel(openInputStream(childPath).get)
|
||||
val in = openInputChannel(childPath).get
|
||||
out.transferFrom(in, 0, Long.MaxValue)
|
||||
out.close()
|
||||
in.close()
|
||||
|
@ -25,8 +25,8 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def openInputStream(path: String) = try {
|
||||
Some(mount.openForRead(path))
|
||||
protected def openInputChannel(path: String) = try {
|
||||
Some(new InputFileChannel(mount.openForRead(path)))
|
||||
} catch {
|
||||
case _: Throwable => None
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def openInputStream(path: String) = try {
|
||||
Some(mount.openForRead(path))
|
||||
protected def openInputChannel(path: String) = try {
|
||||
Some(new InputFileChannel(mount.openForRead(path)))
|
||||
} catch {
|
||||
case _: Throwable => None
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package li.cil.oc.server.fs
|
||||
|
||||
import java.io
|
||||
import java.nio.channels.SeekableByteChannel
|
||||
|
||||
trait FileInputStreamFileSystem extends InputStreamFileSystem {
|
||||
protected val root: io.File
|
||||
@ -43,6 +44,6 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def openInputStream(path: String): Option[io.InputStream] =
|
||||
Some(new io.FileInputStream(new io.File(root, path)))
|
||||
override protected def openInputChannel(path: String): Option[SeekableByteChannel] =
|
||||
Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel)
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package li.cil.oc.server.fs
|
||||
|
||||
import java.io.{FileNotFoundException, IOException, InputStream}
|
||||
import java.io.{FileNotFoundException, IOException}
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.fs.Mode
|
||||
import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
|
||||
import scala.collection.mutable
|
||||
import java.nio.channels.SeekableByteChannel
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||
private val handles = mutable.Map.empty[Int, Handle]
|
||||
@ -25,9 +27,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||
|
||||
override def open(path: String, mode: Mode) = this.synchronized(if (mode == Mode.Read && exists(path) && !isDirectory(path)) {
|
||||
val handle = Iterator.continually((Math.random() * Int.MaxValue).toInt + 1).filterNot(handles.contains).next()
|
||||
openInputStream(path) match {
|
||||
case Some(stream) =>
|
||||
handles += handle -> new Handle(this, handle, path, stream)
|
||||
openInputChannel(path) match {
|
||||
case Some(channel) =>
|
||||
handles += handle -> new Handle(this, handle, path, channel)
|
||||
handle
|
||||
case _ => throw new FileNotFoundException()
|
||||
}
|
||||
@ -49,10 +51,10 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||
val handle = handleNbt.getInteger("handle")
|
||||
val path = handleNbt.getString("path")
|
||||
val position = handleNbt.getLong("position")
|
||||
openInputStream(path) match {
|
||||
case Some(stream) =>
|
||||
val fileHandle = new Handle(this, handle, path, stream)
|
||||
fileHandle.position = stream.skip(position) // May be != position if the file changed since we saved.
|
||||
openInputChannel(path) match {
|
||||
case Some(channel) =>
|
||||
val fileHandle = new Handle(this, handle, path, channel)
|
||||
channel.position(position)
|
||||
handles += handle -> fileHandle
|
||||
case _ => // The source file seems to have disappeared since last time.
|
||||
}
|
||||
@ -62,7 +64,7 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||
override def save(nbt: NBTTagCompound) = this.synchronized {
|
||||
val handlesNbt = new NBTTagList()
|
||||
for (file <- handles.values) {
|
||||
assert(!file.isClosed)
|
||||
assert(file.channel.isOpen)
|
||||
val handleNbt = new NBTTagCompound()
|
||||
handleNbt.setInteger("handle", file.handle)
|
||||
handleNbt.setString("path", file.path)
|
||||
@ -74,33 +76,65 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def openInputStream(path: String): Option[InputStream]
|
||||
protected def openInputChannel(path: String): Option[SeekableByteChannel]
|
||||
|
||||
protected class InputFileChannel(val inputStream: java.io.InputStream) extends SeekableByteChannel {
|
||||
var isOpen = true
|
||||
|
||||
private var position_ = 0L
|
||||
|
||||
override def close() = inputStream.close()
|
||||
|
||||
override def truncate(size: Long) = throw new java.io.IOException()
|
||||
|
||||
override def size() = inputStream.available()
|
||||
|
||||
override def position(newPosition: Long) = {
|
||||
inputStream.reset()
|
||||
position_ = inputStream.skip(newPosition)
|
||||
this
|
||||
}
|
||||
|
||||
override def position = position_
|
||||
|
||||
override def write(src: ByteBuffer) = throw new java.io.IOException()
|
||||
|
||||
override def read(dst: ByteBuffer): Int = {
|
||||
if (dst.hasArray) {
|
||||
inputStream.read(dst.array())
|
||||
}
|
||||
else {
|
||||
val count = dst.limit - dst.position
|
||||
for (i <- 0 until count) {
|
||||
inputStream.read match {
|
||||
case -1 => return i
|
||||
case b => dst.put(b.toByte)
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val stream: InputStream) extends api.fs.Handle {
|
||||
var isClosed = false
|
||||
var position = 0L
|
||||
private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: SeekableByteChannel) extends api.fs.Handle {
|
||||
override def position = channel.position
|
||||
|
||||
override def length = owner.size(path)
|
||||
|
||||
override def close() = if (!isClosed) {
|
||||
isClosed = true
|
||||
override def close() = if (channel.isOpen) {
|
||||
owner.handles -= handle
|
||||
stream.close()
|
||||
channel.close()
|
||||
}
|
||||
|
||||
override def read(into: Array[Byte]) = {
|
||||
val read = stream.read(into)
|
||||
if (read >= 0)
|
||||
position += read
|
||||
read
|
||||
channel.read(ByteBuffer.wrap(into))
|
||||
}
|
||||
|
||||
override def seek(to: Long) = {
|
||||
stream.reset()
|
||||
position = stream.skip(to)
|
||||
position
|
||||
channel.position(to)
|
||||
channel.position
|
||||
}
|
||||
|
||||
override def write(value: Array[Byte]) = throw new IOException("bad file descriptor")
|
||||
|
@ -97,9 +97,9 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
protected def openInputStream(path: String) =
|
||||
protected def openInputChannel(path: String) =
|
||||
root.get(segments(path)) match {
|
||||
case Some(obj: VirtualFile) => obj.openInputStream()
|
||||
case Some(obj: VirtualFile) => obj.openInputStream().map(new InputFileChannel(_))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,8 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override protected def openInputStream(path: String) = ZipFileInputStreamFileSystem.synchronized {
|
||||
entry(path).map(_.openStream())
|
||||
override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized {
|
||||
entry(path).map(entry => new InputFileChannel(entry.openStream()))
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
Loading…
x
Reference in New Issue
Block a user