summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authormihaylov <mihaylov@epfl.ch>2006-04-12 06:27:51 +0000
committermihaylov <mihaylov@epfl.ch>2006-04-12 06:27:51 +0000
commit99a85272928ab170351fa1f36b5684ae6a6b4755 (patch)
treefa19a1c6188dd66a200bf8dff09750a14f460ea4 /src/compiler/scala/tools/nsc
parent73ff6fcfc2eea1875356d4e1b26d615053ab9130 (diff)
downloadscala-99a85272928ab170351fa1f36b5684ae6a6b4755.tar.gz
scala-99a85272928ab170351fa1f36b5684ae6a6b4755.tar.bz2
scala-99a85272928ab170351fa1f36b5684ae6a6b4755.zip
Moved some files from scala/tools/util/ to scal...
Moved some files from scala/tools/util/ to scala/tools/nsc/io/
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala3
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala123
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFileReader.scala83
-rw-r--r--src/compiler/scala/tools/nsc/io/CharArrayFile.scala29
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala105
-rw-r--r--src/compiler/scala/tools/nsc/io/SourceReader.scala137
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala67
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala190
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala5
-rw-r--r--src/compiler/scala/tools/nsc/util/ClassPath.scala3
-rw-r--r--src/compiler/scala/tools/nsc/util/SourceFile.scala5
17 files changed, 754 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index a593538852..60799c3c37 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -3,11 +3,12 @@
* @author Martin Odersky
*/
// $Id$
+
package scala.tools.nsc;
import scala.tools.nsc.util.{SourceFile, Position};
import scala.tools.nsc.util.FreshNameCreator;
-import scala.tools.util.AbstractFile;
+import scala.tools.nsc.io.AbstractFile;
import scala.collection.mutable.HashSet;
trait CompilationUnits requires Global {
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 7e0e81357a..6c9f0affb0 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -7,7 +7,7 @@ package scala.tools.nsc;
import java.io._;
import java.nio.charset._;
-import scala.tools.util.{SourceReader,AbstractFile};
+import scala.tools.nsc.io.{SourceReader,AbstractFile};
import scala.tools.nsc.util.ClassPath;
import scala.tools.nsc.util.{Position,SourceFile};
import scala.tools.nsc.reporters._;
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index fd77e89c0d..d805b8fc95 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -8,7 +8,7 @@ package scala.tools.nsc
import reporters._
import nsc.util.SourceFile
-import scala.tools.util.PlainFile
+import scala.tools.nsc.io.PlainFile
import java.io._
import nsc.ast.parser.SyntaxAnalyzer
import scala.collection.mutable.{ListBuffer, HashSet, ArrayBuffer}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 1a4611d1fd..3bff265aff 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -98,7 +98,7 @@ abstract class GenJVM extends SubComponent {
addScalaAttr(if (isTopLevelModule(sym)) sym.sourceModule else sym);
val outfile = getFile(jclass, ".class");
jclass.writeTo(outfile);
- val file = scala.tools.util.AbstractFile.getFile(outfile);
+ val file = scala.tools.nsc.io.AbstractFile.getFile(outfile);
informProgress("wrote " + outfile + " " +
(if (file != null) "" + file.file + " " + file.file.exists()
else "no file"));
diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
new file mode 100644
index 0000000000..521596350b
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
@@ -0,0 +1,123 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+import java.io.File;
+
+object AbstractFile {
+
+ /** Returns "getFile(new File(path))". */
+ def getFile(path: String): AbstractFile = getFile(new File(path));
+
+ /**
+ * If the specified File exists and is a regular file, returns an
+ * abstract regular file backed by it. Otherwise, returns null.
+ */
+ def getFile(file: File): AbstractFile =
+ if (file.isFile() && file.exists()) new PlainFile(file) else null;
+
+
+ /** Returns "getDirectory(new File(path))". */
+ def getDirectory(path: String): AbstractFile = getDirectory(new File(path));
+
+ /**
+ * if the specified File exists and is either a directory or a
+ * readable zip or jar archive, returns an abstract directory
+ * backed by it. Otherwise, returns null.
+ */
+ def getDirectory(file: File): AbstractFile = {
+ if (file.isDirectory() && file.exists()) return new PlainFile(file);
+ if (file.isFile() && file.exists()) {
+ val path = file.getPath();
+ if (path.endsWith(".jar") || path.endsWith(".zip"))
+ return ZipArchive.fromFile(file);
+ }
+ null
+ }
+
+}
+
+/**
+ * This class implements an abstract representation of files and
+ * directories. These files and directories may have some real counter
+ * part within the file system but that is not necessarily true. For
+ * example, there exist abstract files that represent files within a
+ * zip archive or files that exist only in memory.
+ *
+ * Every abstract file has a path (i.e. a full name) and a name
+ * (i.e. a short name) and may be backed by some real File. There are
+ * two different kinds of abstract files: regular files and
+ * directories. Regular files may be read and have a last modification
+ * time. Directories may list their content and look for subfiles with
+ * a specified name or path and of a specified kind.
+ */
+abstract class AbstractFile extends Object with Iterable[AbstractFile] {
+
+ //########################################################################
+ // Public Methods
+
+ /** Returns the name of this abstract file. */
+ def name: String;
+
+ /** Returns the path of this abstract file. */
+ def path: String;
+
+ /** Returns the underlying File if any and null otherwise. */
+ def file: File;
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean;
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long;
+
+ /** Reads the content of this abstract file into a byte array. */
+ def read: Array[Byte];
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def elements: Iterator[AbstractFile];
+
+ /**
+ * 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.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile;
+
+ /**
+ * Returns the abstract file in this abstract directory with the
+ * specified path relative to it, If there is no such file,
+ * returns null. The argument "directory" tells whether to look
+ * for a directory or a regular file.
+ */
+ def lookupPath(path: String, directory: Boolean): AbstractFile = {
+ val length = path.length();
+ val separator = File.separatorChar;
+ assert(0 < length && path.lastIndexOf(separator) < length - 1, path);
+ var file = this;
+ var start = 0;
+ while (true) {
+ val index = path.indexOf(separator, start);
+ assert(index < 0 || start < index, path+" - "+start+" - "+index);
+ val name = path.substring(start, if (index < 0) length else index);
+ file = file.lookupName(name, if (index < 0) directory else true);
+ if (file == null || index < 0) return file;
+ start = index + 1;
+ }
+ file
+ }
+
+ /** Returns the path of this abstract file. */
+ override def toString() = path;
+
+ //########################################################################
+}
diff --git a/src/compiler/scala/tools/nsc/io/AbstractFileReader.scala b/src/compiler/scala/tools/nsc/io/AbstractFileReader.scala
new file mode 100644
index 0000000000..0f0a65f54b
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/AbstractFileReader.scala
@@ -0,0 +1,83 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+class AbstractFileReader(val file: AbstractFile) {
+
+ /** the buffer containing the file
+ */
+ val buf: Array[Byte] = file.read;
+
+ /** the current input pointer
+ */
+ var bp: Int = 0;
+
+ /** return byte at offset 'pos'
+ */
+ def byteAt(pos: Int): Byte = return buf(pos);
+
+ /** read a byte
+ */
+ def nextByte: Byte = {
+ val b = buf(bp);
+ bp = bp + 1;
+ b
+ }
+
+ /** read some bytes
+ */
+ def nextBytes(len: Int): Array[Byte] = {
+ bp = bp + len;
+ buf.subArray(bp - len, bp);
+ }
+
+ /** read a character
+ */
+ def nextChar: Char = {
+ (((nextByte & 0xff) << 8) + (nextByte & 0xff)).toChar;
+ }
+
+ /** read an integer
+ */
+ def nextInt: Int =
+ ((nextByte & 0xff) << 24) + ((nextByte & 0xff) << 16) +
+ ((nextByte & 0xff) << 8) + (nextByte & 0xff);
+
+
+ /** extract a character at position bp from buf
+ */
+ def getChar(mybp: Int): Char =
+ (((buf(mybp) & 0xff) << 8) + (buf(mybp+1) & 0xff)).toChar;
+
+ /** extract an integer at position bp from buf
+ */
+ def getInt(mybp: Int): Int =
+ ((buf(mybp ) & 0xff) << 24) + ((buf(mybp+1) & 0xff) << 16) +
+ ((buf(mybp+2) & 0xff) << 8) + (buf(mybp+3) & 0xff);
+
+ /** extract a long integer at position bp from buf
+ */
+ def getLong(mybp: Int): Long =
+ (getInt(mybp).toLong << 32) + (getInt(mybp + 4) & 0xffffffffL);
+
+ /** extract a float at position bp from buf
+ */
+ def getFloat(mybp: Int): Float = Float.intBitsToFloat(getInt(mybp));
+
+ /** extract a double at position bp from buf
+ */
+ def getDouble(mybp: Int): Double = Double.longBitsToDouble(getLong(mybp));
+
+ /** skip next 'n' bytes
+ */
+ def skip(n: Int): Unit = bp = bp + n;
+
+}
diff --git a/src/compiler/scala/tools/nsc/io/CharArrayFile.scala b/src/compiler/scala/tools/nsc/io/CharArrayFile.scala
new file mode 100644
index 0000000000..9288a44451
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/CharArrayFile.scala
@@ -0,0 +1,29 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+/**
+ * This class implements an abstract regular file backed by a
+ * character array.
+ */
+class CharArrayFile(name: String, path: String, chars: Array[Char])
+ extends VirtualFile(name, path)
+{
+
+ def this(name: String, chars: Array[Char]) = this(name, name, chars);
+
+ /** Reads the content of this abstract file into a byte array. */
+ override def read: Array[Byte] = {
+ Predef.error("!!! not yet implemented");
+ new String(chars).getBytes(); // !!!
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala
new file mode 100644
index 0000000000..5ab83c447f
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/PlainFile.scala
@@ -0,0 +1,105 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+import java.io.{File, FileInputStream, IOException};
+
+object PlainFile {
+
+ /** Returns "fromFile(new File(path))". */
+ def fromPath(path: String): AbstractFile = fromFile(new File(path));
+
+ /**
+ * If the specified File exists, returns an abstract file backed
+ * by it. Otherwise, returns null.
+ */
+ def fromFile(file: File): AbstractFile =
+ if (file.exists()) new PlainFile(file) else null;
+
+}
+
+/** This class implements an abstract file backed by a File. */
+class PlainFile(val file: File) extends AbstractFile {
+
+ assert(file != null);
+ assert(file.exists(), "non-existent file: " + file);
+
+ //########################################################################
+ // Public Methods
+
+ /** Returns the name of this abstract file. */
+ def name = file.getName();
+
+ /** Returns the path of this abstract file. */
+ def path = file.getPath();
+
+
+ override def hashCode(): Int =
+ try { file.getCanonicalPath().hashCode() }
+ catch { case _: IOException => 0 }
+
+ override def equals(that: Any): Boolean =
+ try {
+ that.isInstanceOf[PlainFile] &&
+ file.getCanonicalPath().equals(that.asInstanceOf[PlainFile].file.getCanonicalPath());
+ } catch {
+ case _: IOException =>
+ that.isInstanceOf[PlainFile] &&
+ file.getAbsolutePath().equals(that.asInstanceOf[PlainFile].file.getAbsolutePath());
+ }
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = file.isDirectory();
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = file.lastModified();
+
+ /** Reads the content of this abstract file into a byte array. */
+ def read: Array[Byte] = {
+ assert(!isDirectory, "cannot read directory '" + this + "'");
+ val in = new FileInputStream(file);
+ var rest: Int = file.length().toInt;
+ val buf: Array[Byte] = 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();
+ return buf;
+ }
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def elements: Iterator[AbstractFile] = {
+ assert(isDirectory, "not a directory '" + this + "'");
+ val names: Array[String] = file.list();
+ if (names == null || names.length == 0) Iterator.empty;
+ else Iterator.fromArray(names).map(name: String => new File(file, name))
+ .filter(.exists()).map(file => new PlainFile(file))
+ }
+
+ /**
+ * 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.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ //assert(isDirectory, "not a directory '" + this + "'");
+ val child = new File(file, name);
+ if (!child.exists() || (directory != child.isDirectory) ||
+ directory == child.isFile()) null;
+ else new PlainFile(child);
+ }
+
+ //########################################################################
+}
diff --git a/src/compiler/scala/tools/nsc/io/SourceReader.scala b/src/compiler/scala/tools/nsc/io/SourceReader.scala
new file mode 100644
index 0000000000..f5be1da58a
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/SourceReader.scala
@@ -0,0 +1,137 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+import java.io.{File, FileInputStream, IOException};
+import java.nio.{ByteBuffer, CharBuffer};
+import java.nio.channels.{FileChannel, ReadableByteChannel};
+import java.nio.charset.{CharsetDecoder, CoderResult};
+
+/** This class implements methods to read and decode source files. */
+class SourceReader(decoder: CharsetDecoder) {
+
+ import SourceReader.{decode, flush}
+
+ //########################################################################
+ // Private Fields
+
+ /** The input byte buffer (small enough to fit in cache) */
+ private val bytes: ByteBuffer = ByteBuffer.allocate(0x4000);
+
+ /** The output character buffer */
+ private var chars: CharBuffer = CharBuffer.allocate(0x4000);
+
+ //########################################################################
+ // Public Methods
+
+ /** Reads the file with the specified name. */
+ def read(filename: String): Array[Char]= read(new File(filename));
+
+ /** Reads the specified file. */
+ def read(file: File): Array[Char] = {
+ val channel: FileChannel = new FileInputStream(file).getChannel();
+ try {
+ read(channel);
+ } finally {
+ channel.close();
+ }
+ }
+
+ /** Reads the specified file. */
+ def read(file: AbstractFile): Array[Char] = {
+ val decoder: CharsetDecoder = this.decoder.reset();
+ val bytes: ByteBuffer = ByteBuffer.wrap(file.read);
+ val chars: CharBuffer = this.chars; chars.clear();
+ terminate(flush(decoder, decode(decoder, bytes, chars, true)));
+ }
+
+ /** Reads the specified byte channel. */
+ def read(input: ReadableByteChannel): Array[Char] = {
+ val decoder: CharsetDecoder = this.decoder.reset();
+ val bytes: ByteBuffer = this.bytes; bytes.clear();
+ var chars: CharBuffer = this.chars; chars.clear();
+ var endOfInput: Boolean = false
+ while (!endOfInput ) {
+ endOfInput = input.read(bytes) < 0;
+ bytes.flip();
+ chars = decode(decoder, bytes, chars, endOfInput);
+ }
+ terminate(flush(decoder, chars));
+ }
+
+ //########################################################################
+ // Private Methods
+
+ /**
+ * Sets the specified char buffer as the new output buffer and
+ * reads and returns its content.
+ */
+ private def terminate(chars: CharBuffer): Array[Char] = {
+ val result = new Array[Char](chars.length());
+ chars.get(result);
+ this.chars = chars;
+ result;
+ }
+
+}
+
+object SourceReader {
+
+ /**
+ * Decodes the content of the specified byte buffer with the
+ * specified decoder into the specified char buffer, allocating
+ * bigger ones if necessary, then compacts the byte buffer and
+ * returns the last allocated char buffer. The "endOfInput"
+ * argument indicates whether the byte buffer contains the last
+ * chunk of the input file.
+ */
+ def decode(decoder: CharsetDecoder, bytes: ByteBuffer, chars: CharBuffer,
+ endOfInput: boolean): CharBuffer =
+ {
+ val result: CoderResult = decoder.decode(bytes, chars, endOfInput);
+ if (result.isUnderflow()) {
+ bytes.compact();
+ chars;
+ } else {
+ if (result.isError()) throw new IOException(result.toString());
+ assert(result.isOverflow());
+ decode(decoder, bytes, increaseCapacity(chars), endOfInput);
+ }
+ }
+
+ /**
+ * Flushes the specified decoder into the specified char buffer,
+ * allocating bigger ones if necessary and then flips and returns
+ * the last allocated char buffer.
+ */
+ def flush(decoder: CharsetDecoder, chars: CharBuffer): CharBuffer = {
+ val result: CoderResult = decoder.flush(chars);
+ if (result.isUnderflow()) {
+ chars.flip();
+ chars;
+ } else {
+ if (result.isError()) throw new IOException(result.toString());
+ assert(result.isOverflow());
+ flush(decoder, increaseCapacity(chars));
+ }
+ }
+
+ /**
+ * Flips the specified buffer and returns a new one with the same
+ * content but with an increased capacity.
+ */
+ private def increaseCapacity(buffer: CharBuffer): CharBuffer = {
+ buffer.flip();
+ val capacity = 2 * buffer.capacity();
+ CharBuffer.allocate(capacity).put(buffer);
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
new file mode 100644
index 0000000000..02ce3b0f81
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
@@ -0,0 +1,67 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002-2006, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+import java.io.{File,IOException};
+
+/** This class implements an empty abstract regular file. */
+class VirtualFile(val name: String, _path: String) extends AbstractFile {
+
+ assert(name != null && path != null, name + " - " + path);
+
+ //########################################################################
+ // Public Constructors
+
+ /**
+ * Initializes this instance with the specified name and an
+ * identical path.
+ */
+ def this(name: String) = this(name, name);
+
+ //########################################################################
+ // Public Methods
+
+ def path = _path;
+
+ /** Returns null. */
+ final def file: File = null;
+
+ /** Is this abstract file a directory? */
+ def isDirectory: Boolean = false;
+
+ /** Returns the time that this abstract file was last modified. */
+ def lastModified: Long = Long.MIN_VALUE;
+
+ /** Reads the content of this abstract file into a byte array. */
+ def read: Array[Byte] = {
+ assert(!isDirectory, "cannot read directory '" + this + "'");
+ new Array[Byte](0);
+ }
+
+ /** Returns all abstract subfiles of this abstract directory. */
+ def elements: Iterator[AbstractFile] = {
+ assert(isDirectory, "not a directory '" + this + "'");
+ Iterator.empty;
+ }
+
+ /**
+ * 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.
+ */
+ def lookupName(name: String, directory: Boolean): AbstractFile = {
+ assert(isDirectory, "not a directory '" + this + "'");
+ null;
+ }
+
+ //########################################################################
+}
diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
new file mode 100644
index 0000000000..84bc7752f8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
@@ -0,0 +1,190 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+
+package scala.tools.nsc.io;
+
+
+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
+ }
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index bce1e2e202..0df3271bb8 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -3,13 +3,12 @@
* @author Martin Odersky
*/
// $Id$
+
package scala.tools.nsc.symtab;
-import java.io.IOException;
-import java.io.File;
-import scala.tools.nsc.util.Position;
-import scala.tools.nsc.util.ClassPath;
-import scala.tools.util.{AbstractFile};
+import java.io.{File, IOException};
+import scala.tools.nsc.util.{Position, ClassPath};
+import scala.tools.nsc.io.AbstractFile;
import scala.tools.nsc.util.NameTransformer;
import scala.collection.mutable.HashMap;
import classfile.{ClassfileParser, SymblfileParser};
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index e21ac25ff1..08df424779 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -6,7 +6,7 @@
package scala.tools.nsc.symtab;
-import scala.tools.util.AbstractFile;
+import scala.tools.nsc.io.AbstractFile;
import scala.tools.nsc.util.{Position, SourceFile};
import Flags._;
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 8e8cadd21d..489502910c 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -2,7 +2,9 @@
* Copyright 2005 LAMP/EPFL
* @author Martin Odersky
*/
+
// $Id$
+
/* Ideas to extend this to an icode reader:
1. Parse classfile a second time, creating a hashmap `code' that associates method symbols with code.
@@ -12,12 +14,11 @@
code(new) = code(meth)
*/
+
package scala.tools.nsc.symtab.classfile;
import scala.tools.nsc.util.Position;
-import scala.tools.util.AbstractFile;
-import scala.tools.util.AbstractFileReader;
-
+import scala.tools.nsc.io.{AbstractFile, AbstractFileReader};
import scala.collection.mutable.ListBuffer;
import scala.collection.immutable.{Map, ListMap};
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
index 587940e6b8..83f296125f 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/SymblfileParser.scala
@@ -3,11 +3,10 @@
* @author Martin Odersky
*/
// $Id$
-package scala.tools.nsc.symtab.classfile;
-import scala.tools.util.{AbstractFile, AbstractFileReader};
+package scala.tools.nsc.symtab.classfile;
-import java.io.IOException;
+import scala.tools.nsc.io.{AbstractFile, AbstractFileReader};
abstract class SymblfileParser {
diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala
index 88e5050cbb..5b140f2411 100644
--- a/src/compiler/scala/tools/nsc/util/ClassPath.scala
+++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala
@@ -11,10 +11,9 @@
package scala.tools.nsc.util
import scala.collection.mutable.ArrayBuffer
-import scala.tools.util.AbstractFile
+import scala.tools.nsc.io.AbstractFile
import java.io.File
-import java.io.FileNotFoundException
import java.util.StringTokenizer
/** Richer classpath abstraction than files.
diff --git a/src/compiler/scala/tools/nsc/util/SourceFile.scala b/src/compiler/scala/tools/nsc/util/SourceFile.scala
index 0c1bd9758c..cf0e71adfe 100644
--- a/src/compiler/scala/tools/nsc/util/SourceFile.scala
+++ b/src/compiler/scala/tools/nsc/util/SourceFile.scala
@@ -9,8 +9,9 @@
package scala.tools.nsc.util;
-import scala.tools.util.AbstractFile;
-import scala.tools.util.CharArrayFile;
+
+
+import scala.tools.nsc.io.{AbstractFile, CharArrayFile};
/** Uses positions that are offsets rather than line/column pairs.
*