diff --git a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala index 3d8708c8b..e8440451a 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC15FileSystem.scala @@ -26,7 +26,7 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // protected def openInputChannel(path: String) = try { - Some(new InputFileChannel(mount.openForRead(path))) + Some(new InputStreamChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala index e412dd54b..0ea017cc3 100644 --- a/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CC16FileSystem.scala @@ -26,7 +26,7 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem { // ----------------------------------------------------------------------- // protected def openInputChannel(path: String) = try { - Some(new InputFileChannel(mount.openForRead(path))) + Some(new InputStreamChannel(mount.openForRead(path))) } catch { case _: Throwable => None } diff --git a/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala index 12cf6ad55..86840765e 100644 --- a/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/CompositeReadOnlyFileSystem.scala @@ -35,16 +35,26 @@ class CompositeReadOnlyFileSystem(factories: mutable.LinkedHashMap[String, Calla override def lastModified(path: String) = findFileSystem(path).fold(0L)(_.lastModified(path)) - override def list(path: String) = parts.values.foldLeft(Array.empty[String])((acc, fs) => { - if (fs.exists(path)) try { - val l = fs.list(path) - if (l != null) acc ++ l else acc - } - catch { - case _: Throwable => acc - } - else acc - }) + override def list(path: String) = if (isDirectory(path)) { + parts.values.foldLeft(mutable.Set.empty[String])((acc, fs) => { + if (fs.exists(path)) try { + val l = fs.list(path) + if (l != null) for (e <- l) { + val f = e.stripSuffix("/") + val d = f + "/" + // Avoid duplicates and always only use the latest entry. + acc -= f + acc -= d + acc += e + } + } + catch { + case _: Throwable => + } + acc + }).toArray + } + else null // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala index 33dfa1988..56322c7d4 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileInputStreamFileSystem.scala @@ -1,7 +1,6 @@ package li.cil.oc.server.fs import java.io -import java.nio.channels.SeekableByteChannel trait FileInputStreamFileSystem extends InputStreamFileSystem { protected val root: io.File @@ -44,6 +43,23 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem { // ----------------------------------------------------------------------- // - override protected def openInputChannel(path: String): Option[SeekableByteChannel] = - Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel) + override protected def openInputChannel(path: String) = Some(new FileChannel(new io.File(root, path))) + + protected class FileChannel(file: io.File) extends InputChannel { + val channel = new io.RandomAccessFile(file, "r").getChannel + + override def position(newPosition: Long) = { + channel.position(newPosition) + channel.position + } + + override def position = channel.position + + override def close() = channel.close() + + override def isOpen = channel.isOpen + + override def read(dst: Array[Byte]) = channel.read(java.nio.ByteBuffer.wrap(dst)) + } + } diff --git a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala index fe06064c1..f9fa39c5f 100644 --- a/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/InputStreamFileSystem.scala @@ -5,7 +5,7 @@ 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.channels.ReadableByteChannel import java.nio.ByteBuffer trait InputStreamFileSystem extends api.fs.FileSystem { @@ -76,49 +76,61 @@ trait InputStreamFileSystem extends api.fs.FileSystem { // ----------------------------------------------------------------------- // - protected def openInputChannel(path: String): Option[SeekableByteChannel] + protected def openInputChannel(path: String): Option[InputChannel] - protected class InputFileChannel(val inputStream: java.io.InputStream) extends SeekableByteChannel { + protected trait InputChannel extends ReadableByteChannel { + def isOpen: Boolean + + def close() + + def position: Long + + def position(newPosition: Long): Long + + def read(dst: Array[Byte]): Int + + override def read(dst: ByteBuffer) = { + if (dst.hasArray) { + read(dst.array()) + } + else { + val count = dst.limit - dst.position + val buffer = new Array[Byte](count) + val n = read(buffer) + dst.put(buffer, 0, n) + n + } + } + } + + protected class InputStreamChannel(val inputStream: java.io.InputStream) extends InputChannel { 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 close() = if (isOpen) { + isOpen = false + inputStream.close() } override def position = position_ - override def write(src: ByteBuffer) = throw new java.io.IOException() + override def position(newPosition: Long) = { + inputStream.reset() + position_ = inputStream.skip(newPosition) + position_ + } - 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 - } + override def read(dst: Array[Byte]) = { + val read = inputStream.read(dst) + position_ += read + read } } // ----------------------------------------------------------------------- // - private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: SeekableByteChannel) extends api.fs.Handle { + private class Handle(val owner: InputStreamFileSystem, val handle: Int, val path: String, val channel: InputChannel) extends api.fs.Handle { override def position = channel.position override def length = owner.size(path) @@ -128,14 +140,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem { channel.close() } - override def read(into: Array[Byte]) = { - channel.read(ByteBuffer.wrap(into)) - } + override def read(into: Array[Byte]) = channel.read(into) - override def seek(to: Long) = { - channel.position(to) - channel.position - } + override def seek(to: Long) = channel.position(to) override def write(value: Array[Byte]) = throw new IOException("bad file descriptor") } diff --git a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala index 9692a67e9..4ed8e0864 100644 --- a/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/VirtualFileSystem.scala @@ -99,7 +99,7 @@ trait VirtualFileSystem extends OutputStreamFileSystem { protected def openInputChannel(path: String) = root.get(segments(path)) match { - case Some(obj: VirtualFile) => obj.openInputStream().map(new InputFileChannel(_)) + case Some(obj: VirtualFile) => obj.openInputStream().map(new InputStreamChannel(_)) case _ => None } diff --git a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala index 9467d6128..790cd5761 100644 --- a/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/ZipFileInputStreamFileSystem.scala @@ -59,7 +59,7 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend // ----------------------------------------------------------------------- // override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized { - entry(path).map(entry => new InputFileChannel(entry.openStream())) + entry(path).map(entry => new InputStreamChannel(entry.openStream())) } // ----------------------------------------------------------------------- //