Got rid of the Java 1.7 interface.

Avoid duplicate listing of file system entries in compound file systems if one is a file and the other a directory, closes #219.
This commit is contained in:
Florian Nücke 2014-04-21 13:39:59 +02:00
parent 59d7c75428
commit fc96037ed9
7 changed files with 86 additions and 53 deletions

View File

@ -26,7 +26,7 @@ class CC15FileSystem(val mount: IMount) extends InputStreamFileSystem {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def openInputChannel(path: String) = try { protected def openInputChannel(path: String) = try {
Some(new InputFileChannel(mount.openForRead(path))) Some(new InputStreamChannel(mount.openForRead(path)))
} catch { } catch {
case _: Throwable => None case _: Throwable => None
} }

View File

@ -26,7 +26,7 @@ class CC16FileSystem(val mount: IMount) extends InputStreamFileSystem {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
protected def openInputChannel(path: String) = try { protected def openInputChannel(path: String) = try {
Some(new InputFileChannel(mount.openForRead(path))) Some(new InputStreamChannel(mount.openForRead(path)))
} catch { } catch {
case _: Throwable => None case _: Throwable => None
} }

View File

@ -35,16 +35,26 @@ class CompositeReadOnlyFileSystem(factories: mutable.LinkedHashMap[String, Calla
override def lastModified(path: String) = findFileSystem(path).fold(0L)(_.lastModified(path)) override def lastModified(path: String) = findFileSystem(path).fold(0L)(_.lastModified(path))
override def list(path: String) = parts.values.foldLeft(Array.empty[String])((acc, fs) => { override def list(path: String) = if (isDirectory(path)) {
parts.values.foldLeft(mutable.Set.empty[String])((acc, fs) => {
if (fs.exists(path)) try { if (fs.exists(path)) try {
val l = fs.list(path) val l = fs.list(path)
if (l != null) acc ++ l else acc 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 { catch {
case _: Throwable => acc case _: Throwable =>
} }
else acc acc
}) }).toArray
}
else null
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -1,7 +1,6 @@
package li.cil.oc.server.fs package li.cil.oc.server.fs
import java.io import java.io
import java.nio.channels.SeekableByteChannel
trait FileInputStreamFileSystem extends InputStreamFileSystem { trait FileInputStreamFileSystem extends InputStreamFileSystem {
protected val root: io.File protected val root: io.File
@ -44,6 +43,23 @@ trait FileInputStreamFileSystem extends InputStreamFileSystem {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override protected def openInputChannel(path: String): Option[SeekableByteChannel] = override protected def openInputChannel(path: String) = Some(new FileChannel(new io.File(root, path)))
Some(new io.RandomAccessFile(new io.File(root, path), "r").getChannel)
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))
}
} }

View File

@ -5,7 +5,7 @@ import li.cil.oc.api
import li.cil.oc.api.fs.Mode import li.cil.oc.api.fs.Mode
import net.minecraft.nbt.{NBTTagList, NBTTagCompound} import net.minecraft.nbt.{NBTTagList, NBTTagCompound}
import scala.collection.mutable import scala.collection.mutable
import java.nio.channels.SeekableByteChannel import java.nio.channels.ReadableByteChannel
import java.nio.ByteBuffer import java.nio.ByteBuffer
trait InputStreamFileSystem extends api.fs.FileSystem { 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 var isOpen = true
private var position_ = 0L private var position_ = 0L
override def close() = inputStream.close() override def close() = if (isOpen) {
isOpen = false
override def truncate(size: Long) = throw new java.io.IOException() inputStream.close()
override def size() = inputStream.available()
override def position(newPosition: Long) = {
inputStream.reset()
position_ = inputStream.skip(newPosition)
this
} }
override def position = position_ 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 = { override def read(dst: Array[Byte]) = {
if (dst.hasArray) { val read = inputStream.read(dst)
inputStream.read(dst.array()) position_ += read
} read
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 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 position = channel.position
override def length = owner.size(path) override def length = owner.size(path)
@ -128,14 +140,9 @@ trait InputStreamFileSystem extends api.fs.FileSystem {
channel.close() channel.close()
} }
override def read(into: Array[Byte]) = { override def read(into: Array[Byte]) = channel.read(into)
channel.read(ByteBuffer.wrap(into))
}
override def seek(to: Long) = { override def seek(to: Long) = channel.position(to)
channel.position(to)
channel.position
}
override def write(value: Array[Byte]) = throw new IOException("bad file descriptor") override def write(value: Array[Byte]) = throw new IOException("bad file descriptor")
} }

View File

@ -99,7 +99,7 @@ trait VirtualFileSystem extends OutputStreamFileSystem {
protected def openInputChannel(path: String) = protected def openInputChannel(path: String) =
root.get(segments(path)) match { 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 case _ => None
} }

View File

@ -59,7 +59,7 @@ class ZipFileInputStreamFileSystem(private val archive: ArchiveDirectory) extend
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized { override protected def openInputChannel(path: String) = ZipFileInputStreamFileSystem.synchronized {
entry(path).map(entry => new InputFileChannel(entry.openStream())) entry(path).map(entry => new InputStreamChannel(entry.openStream()))
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //