summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/util/ZipArchive.scala
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2006-04-11 15:36:05 +0000
committermihaylov <mihaylov@epfl.ch>2006-04-11 15:36:05 +0000
commit8b6c8a3c0709bc13c74f11ffb660c1c764564915 (patch)
treece7d0966fa603eb983e99056688fad83d22c3ee0 /src/compiler/scala/tools/util/ZipArchive.scala
parent0f46fe4ca5ac451a05f5d5ddb7e6cdca646c4979 (diff)
downloadscala-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.scala190
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
+ }
+ }
+
+}