scala/ScalaBook/chapter-09/src/main/scala/scalabook/file/ZipFS.scala
package scalabook.file
import java.util.zip.{
ZipEntry => JavaZipEntry,
ZipInputStream => JavaInStream,
ZipFile => JavaZipFile}
import scala.collection.mutable
import path.Path
import Path._
import VFS.AnyFile
object ZipFS {
val RootPath = Path.UnixPath("/")
def apply(path: Path): ZipFS = new ZipFS(NativeFile(path))
def apply(path: String): ZipFS = new ZipFS(NativeFile(path))
def apply(vfile: AnyFile): ZipFS = new ZipFS(vfile)
}
class ZipFS(source: AnyFile) extends VFS[ZipFile] {
protected[file] val (nativeZip, path2file) = loadEntries
private[this] def loadEntries() = {
val tmpJavaNative = FileUtil.materializeToNative(source).nativeJavaFile
val nativeZip = new JavaZipFile(tmpJavaNative)
val path2vfile = new mutable.HashMap[Path, ZipFile]
var entriesEnum = nativeZip.entries
while(entriesEnum.hasMoreElements) {
val nextEntry = entriesEnum.nextElement
val entryPath = mkpath(nextEntry.getName)
val zipFile = new ZipFile(this, entryPath, nextEntry)
path2vfile(entryPath) = zipFile
}
// add non-existent folder entries
val missingPaths = new mutable.HashSet[Path]
path2vfile.foreach { case (path, _) =>
def mkAllPaths(path: Path, all: List[Path]): List[Path] = {
val parent = path.parent
if(parent.isEmpty)
path :: all
else
mkAllPaths(parent, path :: all)
}
mkAllPaths(path, List()).foreach(path => if(!path2vfile.contains(path)) missingPaths(path) = true)
}
missingPaths.foreach(path => path2vfile(path) = new SyntheticZipFolder(this, path))
// add root
val rootFile = new SyntheticZipFolder(this, ZipFS.RootPath)
path2vfile(ZipFS.RootPath) = rootFile
(nativeZip, path2vfile)
}
def newTempFile(prefix: String, suffix: String) =
error("Unsupported operation")
def name = toString // take advantage of case-class toString
override def toString = "ZipFS(" + source + ")"
def mkpath(name: String) = "/".p / name
def newFile(path: Path) =
resolve(path).getOrElse(NoFile.as[ZipFile])
override def resolve(path: Path) = path2file.get(path)
lazy val container = Some(source)
override def isContained = true
def roots = List(path2file(ZipFS.RootPath))
}