diff options
author | mihaylov <mihaylov@epfl.ch> | 2006-04-11 15:36:05 +0000 |
---|---|---|
committer | mihaylov <mihaylov@epfl.ch> | 2006-04-11 15:36:05 +0000 |
commit | 8b6c8a3c0709bc13c74f11ffb660c1c764564915 (patch) | |
tree | ce7d0966fa603eb983e99056688fad83d22c3ee0 /src/compiler/scala/tools/util/ZipArchive.scala | |
parent | 0f46fe4ca5ac451a05f5d5ddb7e6cdca646c4979 (diff) | |
download | scala-8b6c8a3c0709bc13c74f11ffb660c1c764564915.tar.gz scala-8b6c8a3c0709bc13c74f11ffb660c1c764564915.tar.bz2 scala-8b6c8a3c0709bc13c74f11ffb660c1c764564915.zip |
Rewrote the files in scala/tools/util/ in Scala
Diffstat (limited to 'src/compiler/scala/tools/util/ZipArchive.scala')
-rw-r--r-- | src/compiler/scala/tools/util/ZipArchive.scala | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/util/ZipArchive.scala b/src/compiler/scala/tools/util/ZipArchive.scala new file mode 100644 index 0000000000..c15b432e4b --- /dev/null +++ b/src/compiler/scala/tools/util/ZipArchive.scala @@ -0,0 +1,190 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + + +package scala.tools.util; + + +import java.io.{File, IOException, InputStream}; +import java.util.Enumeration; +import java.util.zip.{ZipEntry, ZipFile}; +import scala.collection.mutable.{Map, HashMap} + +object ZipArchive { + + //######################################################################## + + /** Returns "fromFile(new File(path))". */ + def fromPath(path: String): AbstractFile = fromFile(new File(path)); + + /** + * If the specified File exists and is a readable zip archive, + * returns an abstract file backed by it. Otherwise, returns null. + */ + def fromFile(file: File): AbstractFile = + try { new ZipArchive(file, new ZipFile(file)) } + catch { case _: IOException => null } + + /** + * Returns an abstract directory backed by the specified archive. + */ + def fromArchive(archive: ZipFile): AbstractFile = + new ZipArchive(new File(archive.getName()), archive); +} + +/** + * This class implements an abstract directory backed by a zip + * archive. + */ +final class ZipArchive(file: File, val archive: ZipFile) extends PlainFile(file) { + + assert(archive != null) + //######################################################################## + // Private Fields + + /** The root directory or null if not yet initialized */ + private var root: DirEntry = _; + + //######################################################################## + // Public Methods + + /** Returns true. */ + override def isDirectory = true; + + /** Returns all abstract subfiles of this abstract directory. */ + override def elements: Iterator[AbstractFile] = { + if (root == null) load(); + root.elements; + } + + /** + * Returns the abstract file in this abstract directory with the + * specified name. If there is no such file, returns null. The + * argument "directory" tells whether to look for a directory or + * or a regular file. + */ + override def lookupName(name: String, directory: Boolean): AbstractFile = { + if (root == null) load(); + root.lookupName(name, directory); + } + + //######################################################################## + // Private Methods + + /** Loads the archive and creates the root directory. */ + private def load(): Unit = { + this.root = new DirEntry("<root>", "/"); + // A path to DirEntry map + val dirs: Map[String,DirEntry] = new HashMap(); + dirs.update("/", root); + val entries = archive.entries(); + while (entries.hasMoreElements()) { + val entry = entries.nextElement().asInstanceOf[ZipEntry]; + val path = entry.getName(); + assert(entry.isDirectory() == path.endsWith("/"), + this.toString() + " - " + path); + if (entry.isDirectory()) { + val dir: DirEntry = getDir(dirs, path); + assert(dir.entry == null, this.toString() + " - " + path); + dir.entry = entry; + } else { + val index = path.lastIndexOf('/'); + val name = if (index < 0) path else path.substring(index + 1); + val home = if (index < 0) "/" else path.substring(0, index + 1); + val parent: DirEntry = getDir(dirs, home); + assert(!parent.entries.contains(path), this.toString() + " - " + path); + parent.entries.update(name, new FileEntry(name, path, entry)); + } + } + } + + /** + * Lookups the specified table for a DirEntry with the specified + * path. If successful, returns the found DirEntry. Otherwise + * creates a new DirEntry, enters it into the table and in the + * table of its parent ZipDir and returns it. + */ + private def getDir(dirs: Map[String,DirEntry], path: String): DirEntry = + dirs.get(path) match { + case Some(dir) => dir + case None => { + val index = path.lastIndexOf('/', path.length() - 2); + val name = if (index < 0) path else path.substring(index + 1); + val home = if (index < 0) "/" else path.substring(0, index + 1); + val parent: DirEntry = getDir(dirs, home); + val dir = new DirEntry(name.substring(0, name.length() - 1), path); + parent.entries.update(name, dir); + dirs.update(path, dir); + dir + } + } + + //######################################################################## + // Private Class - Entry + + /** Superclass of archive entries */ + abstract class Entry(name: String, path: String) + extends VirtualFile(name, path) + { + + final override def path = ZipArchive.this.toString() + "(" + super.path + ")"; + + } + + //######################################################################## + // Private Class - DirEntry + + /** A directory archive entry */ + private final class DirEntry(name: String, path: String) + extends Entry(name, path) + { + + val entries: Map[String,Entry] = new HashMap(); + + var entry: ZipEntry = _; + + override def isDirectory = true; + + override def lastModified: Long = + if (entry != null) entry.getTime() else super.lastModified; + + override def elements: Iterator[AbstractFile] = entries.values; + + override def lookupName(name: String, directory: Boolean): AbstractFile = + entries.get(if (directory) name + "/" else name) match { + case Some(dir) => dir + case None => null + } + } + + //######################################################################## + // Private Class - FileEntry + + /** A regular file archive entry */ + final class FileEntry(name: String, path: String, val entry: ZipEntry) + extends Entry(name, path) + { + + override def lastModified: Long = entry.getTime(); + + override def read: Array[Byte] = { + val in: InputStream = archive.getInputStream(entry); + var rest: Int = entry.getSize().toInt; + val buf = new Array[Byte](rest); + while (rest > 0) { + val res = in.read(buf, buf.length - rest, rest); + if (res == -1) + throw new IOException("read error"); + rest = rest - res; + } + in.close(); + buf + } + } + +} |