summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/io
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-06-08 02:36:10 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-06-08 15:32:28 +0200
commit0b2f1bcf75d31c59b25e19eebcb80f39c155365b (patch)
tree8d9dfc50ef01ca48c068b232af7e67a723325388 /src/compiler/scala/tools/nsc/io
parent13213e3df0384b1fd815c0798758a22284572cdb (diff)
downloadscala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.tar.gz
scala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.tar.bz2
scala-0b2f1bcf75d31c59b25e19eebcb80f39c155365b.zip
Introduces scala-reflect.jar
Diffstat (limited to 'src/compiler/scala/tools/nsc/io')
-rw-r--r--src/compiler/scala/tools/nsc/io/AbstractFile.scala259
-rw-r--r--src/compiler/scala/tools/nsc/io/Directory.scala76
-rw-r--r--src/compiler/scala/tools/nsc/io/File.scala194
-rw-r--r--src/compiler/scala/tools/nsc/io/FileOperationException.scala13
-rw-r--r--src/compiler/scala/tools/nsc/io/NoAbstractFile.scala32
-rw-r--r--src/compiler/scala/tools/nsc/io/Path.scala289
-rw-r--r--src/compiler/scala/tools/nsc/io/PlainFile.scala102
-rw-r--r--src/compiler/scala/tools/nsc/io/Streamable.scala122
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualDirectory.scala70
-rw-r--r--src/compiler/scala/tools/nsc/io/VirtualFile.scala102
-rw-r--r--src/compiler/scala/tools/nsc/io/ZipArchive.scala221
11 files changed, 0 insertions, 1480 deletions
diff --git a/src/compiler/scala/tools/nsc/io/AbstractFile.scala b/src/compiler/scala/tools/nsc/io/AbstractFile.scala
deleted file mode 100644
index 3faaeaeaec..0000000000
--- a/src/compiler/scala/tools/nsc/io/AbstractFile.scala
+++ /dev/null
@@ -1,259 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-
-package scala.tools.nsc
-package io
-
-import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream }
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-import java.net.URL
-import scala.collection.mutable.ArrayBuffer
-
-/**
- * @author Philippe Altherr
- * @version 1.0, 23/03/2004
- */
-object AbstractFile {
- /** Returns "getFile(new File(path))". */
- def getFile(path: String): AbstractFile = getFile(File(path))
- def getFile(path: Path): AbstractFile = getFile(path.toFile)
-
- /**
- * If the specified File exists and is a regular file, returns an
- * abstract regular file backed by it. Otherwise, returns <code>null</code>.
- */
- def getFile(file: File): AbstractFile =
- if (file.isFile) new PlainFile(file) else null
-
- /** Returns "getDirectory(new File(path))". */
- def getDirectory(path: Path): AbstractFile = getDirectory(path.toFile)
-
- /**
- * 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 <code>null</code>.
- *
- * @param file ...
- * @return ...
- */
- def getDirectory(file: File): AbstractFile =
- if (file.isDirectory) new PlainFile(file)
- else if (file.isFile && Path.isExtensionJarOrZip(file.jfile)) ZipArchive fromFile file
- else null
-
- /**
- * If the specified URL exists and is a readable zip or jar archive,
- * returns an abstract directory backed by it. Otherwise, returns
- * <code>null</code>.
- *
- * @param file ...
- * @return ...
- */
- def getURL(url: URL): AbstractFile = {
- if (url == null || !Path.isExtensionJarOrZip(url.getPath)) null
- else ZipArchive fromURL url
- }
-}
-
-/**
- * <p>
- * This class and its children serve to unify handling of files and
- * directories. These files and directories may or may not have some
- * real counter part within the file system. For example, some file
- * handles reference files within a zip archive or virtual ones
- * that exist only in memory.
- * </p>
- * <p>
- * 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.
- * </p>
- * <p>
- * The interface does <b>not</b> allow to access the content.
- * The class <code>symtab.classfile.AbstractFileReader</code> accesses
- * bytes, knowing that the character set of classfiles is UTF-8. For
- * all other cases, the class <code>SourceFile</code> is used, which honors
- * <code>global.settings.encoding.value</code>.
- * </p>
- */
-abstract class AbstractFile extends reflect.internal.AbstractFileApi with Iterable[AbstractFile] {
-
- /** Returns the name of this abstract file. */
- def name: String
-
- /** Returns the path of this abstract file. */
- def path: String
-
- /** Returns the path of this abstract file in a canonical form. */
- def canonicalPath: String = if (file == null) path else file.getCanonicalPath
-
- /** Checks extension case insensitively. */
- def hasExtension(other: String) = extension == other.toLowerCase
- private lazy val extension: String = Path.extension(name)
-
- /** The absolute file, if this is a relative file. */
- def absolute: AbstractFile
-
- /** Returns the containing directory of this abstract file */
- def container : AbstractFile
-
- /** Returns the underlying File if any and null otherwise. */
- def file: JFile
-
- /** An underlying source, if known. Mostly, a zip/jar file. */
- def underlyingSource: Option[AbstractFile] = None
-
- /** Does this abstract file denote an existing file? */
- def exists: Boolean = (file eq null) || file.exists
-
- /** Does this abstract file represent something which can contain classfiles? */
- def isClassContainer = isDirectory || (file != null && (extension == "jar" || extension == "zip"))
-
- /** Create a file on disk, if one does not exist already. */
- def create(): Unit
-
- /** Delete the underlying file or directory (recursively). */
- def delete(): Unit
-
- /** Is this abstract file a directory? */
- def isDirectory: Boolean
-
- /** Returns the time that this abstract file was last modified. */
- def lastModified: Long
-
- /** returns an input stream so the file can be read */
- def input: InputStream
-
- /** Returns an output stream for writing the file */
- def output: OutputStream
-
- /** Returns a buffered output stream for writing the file - defaults to out */
- def bufferedOutput: BufferedOutputStream = new BufferedOutputStream(output)
-
- /** size of this file if it is a concrete file. */
- def sizeOption: Option[Int] = None
-
- def toURL: URL = if (file == null) null else file.toURI.toURL
-
- /** Returns contents of file (if applicable) in a Char array.
- * warning: use <code>Global.getSourceFile()</code> to use the proper
- * encoding when converting to the char array.
- */
- @throws(classOf[IOException])
- def toCharArray = new String(toByteArray).toCharArray
-
- /** Returns contents of file (if applicable) in a byte array.
- */
- @throws(classOf[IOException])
- def toByteArray: Array[Byte] = {
- val in = input
- var rest = sizeOption.getOrElse(0)
- val arr = new Array[Byte](rest)
- while (rest > 0) {
- val res = in.read(arr, arr.length - rest, rest)
- if (res == -1)
- throw new IOException("read error")
- rest -= res
- }
- in.close()
- arr
- }
-
- /** Returns all abstract subfiles of this abstract directory. */
- def iterator: Iterator[AbstractFile]
-
- /** Returns the abstract file in this abstract directory with the specified
- * name. If there is no such file, returns <code>null</code>. The argument
- * <code>directory</code> tells whether to look for a directory or
- * a regular file.
- */
- def lookupName(name: String, directory: Boolean): AbstractFile
-
- /** Returns an abstract file with the given name. It does not
- * check that it exists.
- */
- def lookupNameUnchecked(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
- * <code>directory</code> tells whether to look for a directory or a regular
- * file.
- *
- * @param path ...
- * @param directory ...
- * @return ...
- */
- def lookupPath(path: String, directory: Boolean): AbstractFile = {
- lookup((f, p, dir) => f.lookupName(p, dir), path, directory)
- }
-
- /** Return an abstract file that does not check that `path` denotes
- * an existing file.
- */
- def lookupPathUnchecked(path: String, directory: Boolean): AbstractFile = {
- lookup((f, p, dir) => f.lookupNameUnchecked(p, dir), path, directory)
- }
-
- private def lookup(getFile: (AbstractFile, String, Boolean) => AbstractFile,
- path0: String,
- directory: Boolean): AbstractFile = {
- val separator = java.io.File.separatorChar
- // trim trailing '/'s
- val path: String = if (path0.last == separator) path0 dropRight 1 else path0
- val length = path.length()
- assert(length > 0 && !(path.last == separator), path)
- var file = this
- var start = 0
- while (true) {
- val index = path.indexOf(separator, start)
- assert(index < 0 || start < index, ((path, directory, start, index)))
- val name = path.substring(start, if (index < 0) length else index)
- file = getFile(file, name, if (index < 0) directory else true)
- if ((file eq null) || index < 0) return file
- start = index + 1
- }
- file
- }
-
- private def fileOrSubdirectoryNamed(name: String, isDir: Boolean): AbstractFile = {
- val lookup = lookupName(name, isDir)
- if (lookup != null) lookup
- else {
- val jfile = new JFile(file, name)
- if (isDir) jfile.mkdirs() else jfile.createNewFile()
- new PlainFile(jfile)
- }
- }
-
- /**
- * Get the file in this directory with the given name,
- * creating an empty file if it does not already existing.
- */
- def fileNamed(name: String): AbstractFile = {
- assert(isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path))
- fileOrSubdirectoryNamed(name, false)
- }
-
- /**
- * Get the subdirectory with a given name, creating it if it
- * does not already exist.
- */
- def subdirectoryNamed(name: String): AbstractFile = {
- assert (isDirectory, "Tried to find '%s' in '%s' but it is not a directory".format(name, path))
- fileOrSubdirectoryNamed(name, true)
- }
-
- protected def unsupported(): Nothing = unsupported(null)
- protected def unsupported(msg: String): Nothing = throw new UnsupportedOperationException(msg)
-
- /** Returns the path of this abstract file. */
- override def toString() = path
-
-}
diff --git a/src/compiler/scala/tools/nsc/io/Directory.scala b/src/compiler/scala/tools/nsc/io/Directory.scala
deleted file mode 100644
index 0eecd9a6e2..0000000000
--- a/src/compiler/scala/tools/nsc/io/Directory.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala.tools.nsc
-package io
-
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-
-object Directory {
- import scala.util.Properties.{ tmpDir, userHome, userDir }
-
- private def normalizePath(s: String) = Some(apply(Path(s).normalize))
- def Current: Option[Directory] = if (userDir == "") None else normalizePath(userDir)
- def Home: Option[Directory] = if (userHome == "") None else normalizePath(userHome)
- def TmpDir: Option[Directory] = if (tmpDir == "") None else normalizePath(tmpDir)
-
- def apply(path: Path): Directory = path.toDirectory
-
- // Like File.makeTemp but creates a directory instead
- def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null): Directory = {
- val path = File.makeTemp(prefix, suffix, dir)
- path.delete()
- path.createDirectory()
- }
-}
-import Path._
-
-/** An abstraction for directories.
- *
- * @author Paul Phillips
- * @since 2.8
- */
-class Directory(jfile: JFile) extends Path(jfile) {
- override def toAbsolute: Directory = if (isAbsolute) this else super.toAbsolute.toDirectory
- override def toDirectory: Directory = this
- override def toFile: File = new File(jfile)
- override def isValid = jfile.isDirectory() || !jfile.exists()
- override def normalize: Directory = super.normalize.toDirectory
-
- /** An iterator over the contents of this directory.
- */
- def list: Iterator[Path] =
- jfile.listFiles match {
- case null => Iterator.empty
- case xs => xs.iterator map Path.apply
- }
-
- def dirs: Iterator[Directory] = list collect { case x: Directory => x }
- def files: Iterator[File] = list collect { case x: File => x }
-
- override def walkFilter(cond: Path => Boolean): Iterator[Path] =
- list filter cond flatMap (_ walkFilter cond)
-
- def deepDirs: Iterator[Directory] = Path.onlyDirs(deepList())
- def deepFiles: Iterator[File] = Path.onlyFiles(deepList())
-
- /** If optional depth argument is not given, will recurse
- * until it runs out of contents.
- */
- def deepList(depth: Int = -1): Iterator[Path] =
- if (depth < 0) list ++ (dirs flatMap (_ deepList (depth)))
- else if (depth == 0) Iterator.empty
- else list ++ (dirs flatMap (_ deepList (depth - 1)))
-
- /** An iterator over the directories underneath this directory,
- * to the (optionally) given depth.
- */
- def subdirs(depth: Int = 1): Iterator[Directory] =
- deepList(depth) collect { case x: Directory => x }
-}
diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala
deleted file mode 100644
index 4cea8439b1..0000000000
--- a/src/compiler/scala/tools/nsc/io/File.scala
+++ /dev/null
@@ -1,194 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-package scala.tools.nsc
-package io
-
-import java.io.{
- FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
- BufferedInputStream, BufferedOutputStream, IOException, PrintStream, PrintWriter, Closeable => JCloseable }
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-import java.nio.channels.{ Channel, FileChannel }
-import scala.io.Codec
-import language.{reflectiveCalls, implicitConversions}
-
-object File {
- def pathSeparator = java.io.File.pathSeparator
- def separator = java.io.File.separator
-
- def apply(path: Path)(implicit codec: Codec) = new File(path.jfile)(codec)
-
- // Create a temporary file, which will be deleted upon jvm exit.
- def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) = {
- val jfile = java.io.File.createTempFile(prefix, suffix, dir)
- jfile.deleteOnExit()
- apply(jfile)
- }
-
- type HasClose = { def close(): Unit }
-
- def closeQuietly(target: HasClose) {
- try target.close() catch { case e: IOException => }
- }
- def closeQuietly(target: JCloseable) {
- try target.close() catch { case e: IOException => }
- }
-
- // this is a workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6503430
- // we are using a static initializer to statically initialize a java class so we don't
- // trigger java.lang.InternalErrors later when using it concurrently. We ignore all
- // the exceptions so as not to cause spurious failures when no write access is available,
- // e.g. google app engine.
- //
- // XXX need to put this behind a setting.
- //
- // try {
- // import Streamable.closing
- // val tmp = java.io.File.createTempFile("bug6503430", null, null)
- // try closing(new FileInputStream(tmp)) { in =>
- // val inc = in.getChannel()
- // closing(new FileOutputStream(tmp, true)) { out =>
- // out.getChannel().transferFrom(inc, 0, 0)
- // }
- // }
- // finally tmp.delete()
- // }
- // catch {
- // case _: IllegalArgumentException | _: IllegalStateException | _: IOException | _: SecurityException => ()
- // }
-}
-import File._
-import Path._
-
-/** An abstraction for files. For character data, a Codec
- * can be supplied at either creation time or when a method
- * involving character data is called (with the latter taking
- * precedence if supplied.) If neither is available, the value
- * of scala.io.Codec.default is used.
- *
- * @author Paul Phillips
- * @since 2.8
- */
-class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars {
- override val creationCodec = constructorCodec
- def withCodec(codec: Codec): File = new File(jfile)(codec)
-
- override def addExtension(ext: String): File = super.addExtension(ext).toFile
- override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile
- override def toDirectory: Directory = new Directory(jfile)
- override def toFile: File = this
- override def normalize: File = super.normalize.toFile
- override def isValid = jfile.isFile() || !jfile.exists()
- override def length = super[Path].length
- override def walkFilter(cond: Path => Boolean): Iterator[Path] =
- if (cond(this)) Iterator.single(this) else Iterator.empty
-
- /** Obtains an InputStream. */
- def inputStream() = new FileInputStream(jfile)
-
- /** Obtains a OutputStream. */
- def outputStream(append: Boolean = false) = new FileOutputStream(jfile, append)
- def bufferedOutput(append: Boolean = false) = new BufferedOutputStream(outputStream(append))
- def printStream(append: Boolean = false) = new PrintStream(outputStream(append), true)
-
- /** Obtains an OutputStreamWriter wrapped around a FileOutputStream.
- * This should behave like a less broken version of java.io.FileWriter,
- * in that unlike the java version you can specify the encoding.
- */
- def writer(): OutputStreamWriter = writer(false)
- def writer(append: Boolean): OutputStreamWriter = writer(append, creationCodec)
- def writer(append: Boolean, codec: Codec): OutputStreamWriter =
- new OutputStreamWriter(outputStream(append), codec.charSet)
-
- /** Wraps a BufferedWriter around the result of writer().
- */
- def bufferedWriter(): BufferedWriter = bufferedWriter(false)
- def bufferedWriter(append: Boolean): BufferedWriter = bufferedWriter(append, creationCodec)
- def bufferedWriter(append: Boolean, codec: Codec): BufferedWriter =
- new BufferedWriter(writer(append, codec))
-
- def printWriter(): PrintWriter = new PrintWriter(bufferedWriter(), true)
- def printWriter(append: Boolean): PrintWriter = new PrintWriter(bufferedWriter(append), true)
-
- /** Creates a new file and writes all the Strings to it. */
- def writeAll(strings: String*): Unit = {
- val out = bufferedWriter()
- try strings foreach (out write _)
- finally out close
- }
-
- def writeBytes(bytes: Array[Byte]): Unit = {
- val out = bufferedOutput()
- try out write bytes
- finally out close
- }
-
- def appendAll(strings: String*): Unit = {
- val out = bufferedWriter(append = true)
- try strings foreach (out write _)
- finally out.close()
- }
-
- /** Calls println on each string (so it adds a newline in the PrintWriter fashion.) */
- def printlnAll(strings: String*): Unit = {
- val out = printWriter()
- try strings foreach (out println _)
- finally out close
- }
-
- def safeSlurp(): Option[String] =
- try Some(slurp())
- catch { case _: IOException => None }
-
- def copyTo(destPath: Path, preserveFileDate: Boolean = false): Boolean = {
- val CHUNK = 1024 * 1024 * 16 // 16 MB
- val dest = destPath.toFile
- if (!isValid) fail("Source %s is not a valid file." format name)
- if (this.normalize == dest.normalize) fail("Source and destination are the same.")
- if (!dest.parent.exists) fail("Destination cannot be created.")
- if (dest.exists && !dest.canWrite) fail("Destination exists but is not writable.")
- if (dest.isDirectory) fail("Destination exists but is a directory.")
-
- lazy val in_s = inputStream()
- lazy val out_s = dest.outputStream()
- lazy val in = in_s.getChannel()
- lazy val out = out_s.getChannel()
-
- try {
- val size = in.size()
- var pos, count = 0L
- while (pos < size) {
- count = (size - pos) min CHUNK
- pos += out.transferFrom(in, pos, count)
- }
- }
- finally List[HasClose](out, out_s, in, in_s) foreach closeQuietly
-
- if (this.length != dest.length)
- fail("Failed to completely copy %s to %s".format(name, dest.name))
-
- if (preserveFileDate)
- dest.lastModified = this.lastModified
-
- true
- }
-
- /** Reflection since we're into the java 6+ API.
- */
- def setExecutable(executable: Boolean, ownerOnly: Boolean = true): Boolean = {
- type JBoolean = java.lang.Boolean
- val method =
- try classOf[JFile].getMethod("setExecutable", classOf[Boolean], classOf[Boolean])
- catch { case _: NoSuchMethodException => return false }
-
- try method.invoke(jfile, executable: JBoolean, ownerOnly: JBoolean).asInstanceOf[JBoolean].booleanValue
- catch { case _: Exception => false }
- }
-}
diff --git a/src/compiler/scala/tools/nsc/io/FileOperationException.scala b/src/compiler/scala/tools/nsc/io/FileOperationException.scala
deleted file mode 100644
index f23658efbc..0000000000
--- a/src/compiler/scala/tools/nsc/io/FileOperationException.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2011, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-package scala.tools.nsc
-package io
-
-case class FileOperationException(msg: String) extends RuntimeException(msg)
diff --git a/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala b/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala
deleted file mode 100644
index e468356722..0000000000
--- a/src/compiler/scala/tools/nsc/io/NoAbstractFile.scala
+++ /dev/null
@@ -1,32 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package io
-
-import java.io.InputStream
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-
-/** A distinguished object so you can avoid both null
- * and Option.
- */
-object NoAbstractFile extends AbstractFile {
- def absolute: AbstractFile = this
- def container: AbstractFile = this
- def create(): Unit = ???
- def delete(): Unit = ???
- def file: JFile = null
- def input: InputStream = null
- def isDirectory: Boolean = false
- def iterator: Iterator[AbstractFile] = Iterator.empty
- def lastModified: Long = 0L
- def lookupName(name: String, directory: Boolean): AbstractFile = null
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = null
- def name: String = ""
- def output: java.io.OutputStream = null
- def path: String = ""
- override def toByteArray = Array[Byte]()
-}
diff --git a/src/compiler/scala/tools/nsc/io/Path.scala b/src/compiler/scala/tools/nsc/io/Path.scala
deleted file mode 100644
index 1db015e2f5..0000000000
--- a/src/compiler/scala/tools/nsc/io/Path.scala
+++ /dev/null
@@ -1,289 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package io
-
-import java.io.{
- FileInputStream, FileOutputStream, BufferedReader, BufferedWriter, InputStreamReader, OutputStreamWriter,
- BufferedInputStream, BufferedOutputStream, RandomAccessFile }
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-import java.net.{ URI, URL }
-import scala.util.Random.alphanumeric
-import language.implicitConversions
-
-/** An abstraction for filesystem paths. The differences between
- * Path, File, and Directory are primarily to communicate intent.
- * Since the filesystem can change at any time, there is no way to
- * reliably associate Files only with files and so on. Any Path
- * can be converted to a File or Directory (and thus gain access to
- * the additional entity specific methods) by calling toFile or
- * toDirectory, which has no effect on the filesystem.
- *
- * Also available are createFile and createDirectory, which attempt
- * to create the path in question.
- *
- * @author Paul Phillips
- * @since 2.8
- */
-
-object Path {
- def isExtensionJarOrZip(jfile: JFile): Boolean = isExtensionJarOrZip(jfile.getName)
- def isExtensionJarOrZip(name: String): Boolean = {
- val ext = extension(name)
- ext == "jar" || ext == "zip"
- }
- def extension(name: String): String = {
- var i = name.length - 1
- while (i >= 0 && name.charAt(i) != '.')
- i -= 1
-
- if (i < 0) ""
- else name.substring(i + 1).toLowerCase
- }
- // [Eugene++] I hope that noone relied on this method
-// def isJarOrZip(f: Path, examineFile: Boolean = true) = Jar.isJarOrZip(f, examineFile)
-
- // not certain these won't be problematic, but looks good so far
- implicit def string2path(s: String): Path = apply(s)
- implicit def jfile2path(jfile: JFile): Path = apply(jfile)
-
- // java 7 style, we don't use it yet
- // object AccessMode extends Enumeration {
- // val EXECUTE, READ, WRITE = Value
- // }
- // def checkAccess(modes: AccessMode*): Boolean = {
- // modes foreach {
- // case EXECUTE => throw new Exception("Unsupported") // can't check in java 5
- // case READ => if (!jfile.canRead()) return false
- // case WRITE => if (!jfile.canWrite()) return false
- // }
- // true
- // }
-
- def onlyDirs(xs: Iterator[Path]): Iterator[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
- def onlyDirs(xs: List[Path]): List[Directory] = xs filter (_.isDirectory) map (_.toDirectory)
- def onlyFiles(xs: Iterator[Path]): Iterator[File] = xs filter (_.isFile) map (_.toFile)
- def onlyFiles(xs: List[Path]): List[File] = xs filter (_.isFile) map (_.toFile)
-
- def roots: List[Path] = java.io.File.listRoots().toList map Path.apply
-
- def apply(segments: Seq[String]): Path = apply(segments mkString java.io.File.separator)
- def apply(path: String): Path = apply(new JFile(path))
- def apply(jfile: JFile): Path =
- if (jfile.isFile) new File(jfile)
- else if (jfile.isDirectory) new Directory(jfile)
- else new Path(jfile)
-
- /** Avoiding any shell/path issues by only using alphanumerics. */
- private[io] def randomPrefix = alphanumeric take 6 mkString
- private[io] def fail(msg: String) = throw FileOperationException(msg)
-}
-import Path._
-
-/** The Path constructor is private so we can enforce some
- * semantics regarding how a Path might relate to the world.
- */
-class Path private[io] (val jfile: JFile) {
- val separator = java.io.File.separatorChar
- val separatorStr = java.io.File.separator
-
- // Validation: this verifies that the type of this object and the
- // contents of the filesystem are in agreement. All objects are
- // valid except File objects whose path points to a directory and
- // Directory objects whose path points to a file.
- def isValid: Boolean = true
-
- // conversions
- def toFile: File = new File(jfile)
- def toDirectory: Directory = new Directory(jfile)
- def toAbsolute: Path = if (isAbsolute) this else Path(jfile.getAbsolutePath())
- def toCanonical: Path = Path(jfile.getCanonicalPath())
- def toURI: URI = jfile.toURI()
- def toURL: URL = toURI.toURL()
- /** If this path is absolute, returns it: otherwise, returns an absolute
- * path made up of root / this.
- */
- def toAbsoluteWithRoot(root: Path) = if (isAbsolute) this else root.toAbsolute / this
-
- /** Creates a new Path with the specified path appended. Assumes
- * the type of the new component implies the type of the result.
- */
- def /(child: Path): Path = if (isEmpty) child else new Path(new JFile(jfile, child.path))
- def /(child: Directory): Directory = /(child: Path).toDirectory
- def /(child: File): File = /(child: Path).toFile
-
- /** If this path is a container, recursively iterate over its contents.
- * The supplied condition is a filter which is applied to each element,
- * with that branch of the tree being closed off if it is true. So for
- * example if the condition is true for some subdirectory, nothing
- * under that directory will be in the Iterator; but otherwise each
- * file and subdirectory underneath it will appear.
- */
- def walkFilter(cond: Path => Boolean): Iterator[Path] =
- if (isFile) toFile walkFilter cond
- else if (isDirectory) toDirectory walkFilter cond
- else Iterator.empty
-
- /** Equivalent to walkFilter(_ => false).
- */
- def walk: Iterator[Path] = walkFilter(_ => true)
-
- // identity
- def name: String = jfile.getName()
- def path: String = jfile.getPath()
- def normalize: Path = Path(jfile.getAbsolutePath())
- def isRootPath: Boolean = roots exists (_ isSame this)
-
- def resolve(other: Path) = if (other.isAbsolute || isEmpty) other else /(other)
- def relativize(other: Path) = {
- assert(isAbsolute == other.isAbsolute, "Paths not of same type: "+this+", "+other)
-
- def createRelativePath(baseSegs: List[String], otherSegs: List[String]) : String = {
- (baseSegs, otherSegs) match {
- case (b :: bs, o :: os) if b == o => createRelativePath(bs, os)
- case (bs, os) => ((".."+separator)*bs.length)+os.mkString(separatorStr)
- }
- }
-
- Path(createRelativePath(segments, other.segments))
- }
-
- // derived from identity
- def root: Option[Path] = roots find (this startsWith _)
- def segments: List[String] = (path split separator).toList filterNot (_.length == 0)
- /**
- * @return The path of the parent directory, or root if path is already root
- */
- def parent: Directory = path match {
- case "" | "." => Directory("..")
- case _ =>
- // the only solution <-- a comment which could have used elaboration
- if (segments.nonEmpty && segments.last == "..")
- (path / "..").toDirectory
- else jfile.getParent match {
- case null =>
- if (isAbsolute) toDirectory // it should be a root. BTW, don't need to worry about relative pathed root
- else Directory(".") // a dir under pwd
- case x =>
- Directory(x)
- }
- }
- def parents: List[Directory] = {
- val p = parent
- if (p isSame this) Nil else p :: p.parents
- }
- // if name ends with an extension (e.g. "foo.jpg") returns the extension ("jpg"), otherwise ""
- def extension: String = {
- var i = name.length - 1
- while (i >= 0 && name.charAt(i) != '.')
- i -= 1
-
- if (i < 0) ""
- else name.substring(i + 1)
- }
- // def extension: String = (name lastIndexOf '.') match {
- // case -1 => ""
- // case idx => name drop (idx + 1)
- // }
- // compares against extensions in a CASE INSENSITIVE way.
- def hasExtension(ext: String, exts: String*) = {
- val lower = extension.toLowerCase
- ext.toLowerCase == lower || exts.exists(_.toLowerCase == lower)
- }
- // returns the filename without the extension.
- def stripExtension: String = name stripSuffix ("." + extension)
- // returns the Path with the extension.
- def addExtension(ext: String): Path = Path(path + "." + ext)
- // changes the existing extension out for a new one, or adds it
- // if the current path has none.
- def changeExtension(ext: String): Path = (
- if (extension == "") addExtension(ext)
- else Path(path.stripSuffix(extension) + ext)
- )
-
- // conditionally execute
- def ifFile[T](f: File => T): Option[T] = if (isFile) Some(f(toFile)) else None
- def ifDirectory[T](f: Directory => T): Option[T] = if (isDirectory) Some(f(toDirectory)) else None
-
- // Boolean tests
- def canRead = jfile.canRead()
- def canWrite = jfile.canWrite()
- def exists = jfile.exists()
- def notExists = try !jfile.exists() catch { case ex: SecurityException => false }
-
- def isFile = jfile.isFile()
- def isDirectory = jfile.isDirectory()
- def isAbsolute = jfile.isAbsolute()
- def isHidden = jfile.isHidden()
- def isEmpty = path.length == 0
-
- // Information
- def lastModified = jfile.lastModified()
- def lastModified_=(time: Long) = jfile setLastModified time // should use setXXX function?
- def length = jfile.length()
-
- // Boolean path comparisons
- def endsWith(other: Path) = segments endsWith other.segments
- def startsWith(other: Path) = segments startsWith other.segments
- def isSame(other: Path) = toCanonical == other.toCanonical
- def isFresher(other: Path) = lastModified > other.lastModified
-
- // creations
- def createDirectory(force: Boolean = true, failIfExists: Boolean = false): Directory = {
- val res = if (force) jfile.mkdirs() else jfile.mkdir()
- if (!res && failIfExists && exists) fail("Directory '%s' already exists." format name)
- else if (isDirectory) toDirectory
- else new Directory(jfile)
- }
- def createFile(failIfExists: Boolean = false): File = {
- val res = jfile.createNewFile()
- if (!res && failIfExists && exists) fail("File '%s' already exists." format name)
- else if (isFile) toFile
- else new File(jfile)
- }
-
- // deletions
- def delete() = jfile.delete()
- def deleteIfExists() = if (jfile.exists()) delete() else false
-
- /** Deletes the path recursively. Returns false on failure.
- * Use with caution!
- */
- def deleteRecursively(): Boolean = deleteRecursively(jfile)
- private def deleteRecursively(f: JFile): Boolean = {
- if (f.isDirectory) f.listFiles match {
- case null =>
- case xs => xs foreach deleteRecursively
- }
- f.delete()
- }
-
- def truncate() =
- isFile && {
- val raf = new RandomAccessFile(jfile, "rw")
- raf setLength 0
- raf.close()
- length == 0
- }
-
- def touch(modTime: Long = System.currentTimeMillis) = {
- createFile()
- if (isFile)
- lastModified = modTime
- }
-
- // todo
- // def copyTo(target: Path, options ...): Boolean
- // def moveTo(target: Path, options ...): Boolean
-
- override def toString() = path
- override def equals(other: Any) = other match {
- case x: Path => path == x.path
- case _ => false
- }
- override def hashCode() = path.hashCode()
-}
diff --git a/src/compiler/scala/tools/nsc/io/PlainFile.scala b/src/compiler/scala/tools/nsc/io/PlainFile.scala
deleted file mode 100644
index 21276e8740..0000000000
--- a/src/compiler/scala/tools/nsc/io/PlainFile.scala
+++ /dev/null
@@ -1,102 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-
-package scala.tools.nsc
-package io
-
-import java.io.{ FileInputStream, FileOutputStream, IOException }
-import PartialFunction._
-
-object PlainFile {
- /**
- * If the specified File exists, returns an abstract file backed
- * by it. Otherwise, returns null.
- */
- def fromPath(file: Path): PlainFile =
- if (file.isDirectory) new PlainDirectory(file.toDirectory)
- else if (file.isFile) new PlainFile(file)
- else null
-}
-
-class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) {
- override def isDirectory = true
- override def iterator = givenPath.list filter (_.exists) map (x => new PlainFile(x))
- override def delete(): Unit = givenPath.deleteRecursively()
-}
-
-/** This class implements an abstract file backed by a File.
- */
-class PlainFile(val givenPath: Path) extends AbstractFile {
- assert(path ne null)
-
- val file = givenPath.jfile
- override def underlyingSource = Some(this)
-
- private val fpath = givenPath.toAbsolute
-
- /** Returns the name of this abstract file. */
- def name = givenPath.name
-
- /** Returns the path of this abstract file. */
- def path = givenPath.path
-
- /** The absolute file. */
- def absolute = new PlainFile(givenPath.toAbsolute)
-
- override def container: AbstractFile = new PlainFile(givenPath.parent)
- override def input = givenPath.toFile.inputStream()
- override def output = givenPath.toFile.outputStream()
- override def sizeOption = Some(givenPath.length.toInt)
-
- override def toString = path
- override def hashCode(): Int = fpath.hashCode
- override def equals(that: Any): Boolean = that match {
- case x: PlainFile => fpath == x.fpath
- case _ => false
- }
-
- /** Is this abstract file a directory? */
- def isDirectory: Boolean = givenPath.isDirectory
-
- /** Returns the time that this abstract file was last modified. */
- def lastModified: Long = givenPath.lastModified
-
- /** Returns all abstract subfiles of this abstract directory. */
- def iterator: Iterator[AbstractFile] = {
- if (!isDirectory) Iterator.empty
- else givenPath.toDirectory.list filter (_.exists) map (new PlainFile(_))
- }
-
- /**
- * 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.
- *
- * @param name ...
- * @param directory ...
- * @return ...
- */
- def lookupName(name: String, directory: Boolean): AbstractFile = {
- val child = givenPath / name
- if ((child.isDirectory && directory) || (child.isFile && !directory)) new PlainFile(child)
- else null
- }
-
- /** Does this abstract file denote an existing file? */
- def create(): Unit = if (!exists) givenPath.createFile()
-
- /** Delete the underlying file or directory (recursively). */
- def delete(): Unit =
- if (givenPath.isFile) givenPath.delete()
- else if (givenPath.isDirectory) givenPath.toDirectory.deleteRecursively()
-
- /** Returns a plain file with the given name. It does not
- * check that it exists.
- */
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile =
- new PlainFile(givenPath / name)
-}
diff --git a/src/compiler/scala/tools/nsc/io/Streamable.scala b/src/compiler/scala/tools/nsc/io/Streamable.scala
deleted file mode 100644
index 03318674ee..0000000000
--- a/src/compiler/scala/tools/nsc/io/Streamable.scala
+++ /dev/null
@@ -1,122 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package io
-
-import java.net.{ URI, URL }
-import java.io.{ BufferedInputStream, InputStream, PrintStream }
-import java.io.{ BufferedReader, InputStreamReader, Closeable => JCloseable }
-import scala.io.{ Codec, BufferedSource, Source }
-import collection.mutable.ArrayBuffer
-import Path.fail
-
-/** Traits for objects which can be represented as Streams.
- *
- * @author Paul Phillips
- * @since 2.8
- */
-
-object Streamable {
- /** Traits which can be viewed as a sequence of bytes. Source types
- * which know their length should override def length: Long for more
- * efficient method implementations.
- */
- trait Bytes {
- def inputStream(): InputStream
- def length: Long = -1
-
- def bufferedInput() = new BufferedInputStream(inputStream())
- def bytes(): Iterator[Byte] = bytesAsInts() map (_.toByte)
- def bytesAsInts(): Iterator[Int] = {
- val in = bufferedInput()
- Iterator continually in.read() takeWhile (_ != -1)
- }
-
- /** This method aspires to be the fastest way to read
- * a stream of known length into memory.
- */
- def toByteArray(): Array[Byte] = {
- // if we don't know the length, fall back on relative inefficiency
- if (length == -1L)
- return (new ArrayBuffer[Byte]() ++= bytes()).toArray
-
- val arr = new Array[Byte](length.toInt)
- val len = arr.length
- lazy val in = bufferedInput()
- var offset = 0
-
- def loop() {
- if (offset < len) {
- val read = in.read(arr, offset, len - offset)
- if (read >= 0) {
- offset += read
- loop()
- }
- }
- }
- try loop()
- finally in.close()
-
- if (offset == arr.length) arr
- else fail("Could not read entire source (%d of %d bytes)".format(offset, len))
- }
- }
-
- /** For objects which can be viewed as Chars.
- */
- trait Chars extends Bytes {
- /** Calls to methods requiring byte<->char transformations should be offered
- * in a form which allows specifying the codec. When it is not specified,
- * the one discovered at creation time will be used, which will always find the
- * one in scala.io.Codec if no other is available. This can be overridden
- * to use a different default.
- */
- def creationCodec: Codec = implicitly[Codec]
-
- def chars(): BufferedSource = chars(creationCodec)
- def chars(codec: Codec): BufferedSource = Source.fromInputStream(inputStream())(codec)
-
- def lines(): Iterator[String] = lines(creationCodec)
- def lines(codec: Codec): Iterator[String] = chars(codec).getLines()
-
- /** Obtains an InputStreamReader wrapped around a FileInputStream.
- */
- def reader(): InputStreamReader = reader(creationCodec)
- def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream, codec.charSet)
-
- /** Wraps a BufferedReader around the result of reader().
- */
- def bufferedReader(): BufferedReader = bufferedReader(creationCodec)
- def bufferedReader(codec: Codec) = new BufferedReader(reader(codec))
-
- /** Creates a BufferedReader and applies the closure, automatically closing it on completion.
- */
- def applyReader[T](f: BufferedReader => T): T = {
- val in = bufferedReader()
- try f(in)
- finally in.close()
- }
-
- /** Convenience function to import entire file into a String.
- */
- def slurp(): String = slurp(creationCodec)
- def slurp(codec: Codec) = chars(codec).mkString
- }
-
- /** Call a function on something Closeable, finally closing it. */
- def closing[T <: JCloseable, U](stream: T)(f: T => U): U =
- try f(stream)
- finally stream.close()
-
- def bytes(is: => InputStream): Array[Byte] =
- new Bytes { def inputStream() = is } toByteArray
-
- def slurp(is: => InputStream)(implicit codec: Codec): String =
- new Chars { def inputStream() = is } slurp codec
-
- def slurp(url: URL)(implicit codec: Codec): String =
- slurp(url.openStream())
-}
diff --git a/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala b/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala
deleted file mode 100644
index 0bcb2de43f..0000000000
--- a/src/compiler/scala/tools/nsc/io/VirtualDirectory.scala
+++ /dev/null
@@ -1,70 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- */
-
-package scala.tools.nsc
-package io
-
-import scala.collection.mutable
-
-/**
- * An in-memory directory.
- *
- * @author Lex Spoon
- */
-class VirtualDirectory(val name: String, maybeContainer: Option[VirtualDirectory])
-extends AbstractFile {
- def path: String =
- maybeContainer match {
- case None => name
- case Some(parent) => parent.path+'/'+ name
- }
-
- def absolute = this
-
- def container = maybeContainer.get
- def isDirectory = true
- var lastModified: Long = System.currentTimeMillis
-
- override def file = null
- override def input = sys.error("directories cannot be read")
- override def output = sys.error("directories cannot be written")
-
- /** Does this abstract file denote an existing file? */
- def create() { unsupported }
-
- /** Delete the underlying file or directory (recursively). */
- def delete() { unsupported }
-
- /** Returns an abstract file with the given name. It does not
- * check that it exists.
- */
- def lookupNameUnchecked(name: String, directory: Boolean): AbstractFile = unsupported
-
- private val files = mutable.Map.empty[String, AbstractFile]
-
- // the toList is so that the directory may continue to be
- // modified while its elements are iterated
- def iterator = files.values.toList.iterator
-
- override def lookupName(name: String, directory: Boolean): AbstractFile =
- files get name filter (_.isDirectory == directory) orNull
-
- override def fileNamed(name: String): AbstractFile =
- Option(lookupName(name, false)) getOrElse {
- val newFile = new VirtualFile(name, path+'/'+name)
- files(name) = newFile
- newFile
- }
-
- override def subdirectoryNamed(name: String): AbstractFile =
- Option(lookupName(name, true)) getOrElse {
- val dir = new VirtualDirectory(name, Some(this))
- files(name) = dir
- dir
- }
-
- def clear() {
- files.clear();
- }
-}
diff --git a/src/compiler/scala/tools/nsc/io/VirtualFile.scala b/src/compiler/scala/tools/nsc/io/VirtualFile.scala
deleted file mode 100644
index 48826ed191..0000000000
--- a/src/compiler/scala/tools/nsc/io/VirtualFile.scala
+++ /dev/null
@@ -1,102 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Martin Odersky
- */
-
-
-package scala.tools.nsc
-package io
-
-import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream }
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-
-/** This class implements an in-memory file.
- *
- * @author Philippe Altherr
- * @version 1.0, 23/03/2004
- */
-class VirtualFile(val name: String, override val path: String) extends AbstractFile {
- /**
- * Initializes this instance with the specified name and an
- * identical path.
- *
- * @param name the name of the virtual file to be created
- * @return the created virtual file
- */
- def this(name: String) = this(name, name)
-
- override def hashCode = path.hashCode
- override def equals(that: Any) = that match {
- case x: VirtualFile => x.path == path
- case _ => false
- }
-
- //########################################################################
- // Private data
- private var content = new Array[Byte](0)
-
- //########################################################################
- // Public Methods
- def absolute = this
-
- /** Returns null. */
- final def file: JFile = null
-
- override def sizeOption: Option[Int] = Some(content.size)
-
- def input : InputStream = new ByteArrayInputStream(content);
-
- override def output: OutputStream = {
- new ByteArrayOutputStream() {
- override def close() {
- super.close()
- content = toByteArray()
- }
- }
- }
-
- def container: AbstractFile = unsupported
-
- /** Is this abstract file a directory? */
- def isDirectory: Boolean = false
-
- /** Returns the time that this abstract file was last modified. */
- private var _lastModified: Long = 0
- def lastModified: Long = _lastModified
- def lastModified_=(x: Long) = _lastModified = x
-
- /** Returns all abstract subfiles of this abstract directory. */
- def iterator: Iterator[AbstractFile] = {
- assert(isDirectory, "not a directory '" + this + "'")
- Iterator.empty
- }
-
- /** Does this abstract file denote an existing file? */
- def create() { unsupported }
-
- /** Delete the underlying file or directory (recursively). */
- def delete() { unsupported }
-
- /**
- * 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.
- *
- * @param name ...
- * @param directory ...
- * @return ...
- */
- def lookupName(name: String, directory: Boolean): AbstractFile = {
- assert(isDirectory, "not a directory '" + this + "'")
- null
- }
-
- /** Returns an abstract file with the given name. It does not
- * check that it exists.
- */
- def lookupNameUnchecked(name: String, directory: Boolean) = unsupported
-
- //########################################################################
-}
diff --git a/src/compiler/scala/tools/nsc/io/ZipArchive.scala b/src/compiler/scala/tools/nsc/io/ZipArchive.scala
deleted file mode 100644
index e61a9ba0da..0000000000
--- a/src/compiler/scala/tools/nsc/io/ZipArchive.scala
+++ /dev/null
@@ -1,221 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2011 LAMP/EPFL
- * @author Paul Phillips
- */
-
-package scala.tools.nsc
-package io
-
-import java.net.URL
-import java.io.{ IOException, InputStream, ByteArrayInputStream }
-// [scala-reflect.jar migration note] uncomment when creating scala-reflect.jar
-// import java.io.{ File => JFile }
-import java.util.zip.{ ZipEntry, ZipFile, ZipInputStream }
-import scala.collection.{ immutable, mutable }
-import annotation.tailrec
-
-/** An abstraction for zip files and streams. Everything is written the way
- * it is for performance: we come through here a lot on every run. Be careful
- * about changing it.
- *
- * @author Philippe Altherr (original version)
- * @author Paul Phillips (this one)
- * @version 2.0,
- */
-object ZipArchive {
- def fromPath(path: String): FileZipArchive = fromFile(new JFile(path))
- def fromPath(path: Path): FileZipArchive = fromFile(path.toFile)
-
- /**
- * @param file a File
- * @return A ZipArchive if `file` is a readable zip file, otherwise null.
- */
- def fromFile(file: File): FileZipArchive = fromFile(file.jfile)
- def fromFile(file: JFile): FileZipArchive =
- try { new FileZipArchive(file) }
- catch { case _: IOException => null }
-
- /**
- * @param url the url of a zip file
- * @return A ZipArchive backed by the given url.
- */
- def fromURL(url: URL): URLZipArchive = new URLZipArchive(url)
- def fromURL(url: String): URLZipArchive = fromURL(new URL(url))
-
- private def dirName(path: String) = splitPath(path, true)
- private def baseName(path: String) = splitPath(path, false)
- private def splitPath(path0: String, front: Boolean): String = {
- val isDir = path0.charAt(path0.length - 1) == '/'
- val path = if (isDir) path0.substring(0, path0.length - 1) else path0
- val idx = path.lastIndexOf('/')
-
- if (idx < 0)
- if (front) "/"
- else path
- else
- if (front) path.substring(0, idx + 1)
- else path.substring(idx + 1)
- }
-}
-import ZipArchive._
-
-abstract class ZipArchive(override val file: JFile) extends AbstractFile with Equals {
- self =>
-
- override def underlyingSource = Some(this)
- def isDirectory = true
- def lookupName(name: String, directory: Boolean) = unsupported
- def lookupNameUnchecked(name: String, directory: Boolean) = unsupported
- def create() = unsupported
- def delete() = unsupported
- def output = unsupported
- def container = unsupported
- def absolute = unsupported
-
- private def walkIterator(its: Iterator[AbstractFile]): Iterator[AbstractFile] = {
- its flatMap { f =>
- if (f.isDirectory) walkIterator(f.iterator)
- else Iterator(f)
- }
- }
- def deepIterator = walkIterator(iterator)
-
- sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) {
- // have to keep this name for compat with sbt's compiler-interface
- def getArchive: ZipFile = null
- override def underlyingSource = Some(self)
- override def toString = self.path + "(" + path + ")"
- }
- class DirEntry(path: String) extends Entry(path) {
- val entries = mutable.HashMap[String, Entry]()
-
- override def isDirectory = true
- override def iterator: Iterator[Entry] = entries.valuesIterator
- override def lookupName(name: String, directory: Boolean): Entry = {
- if (directory) entries(name + "/")
- else entries(name)
- }
- }
-
- private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = {
- dirs.getOrElseUpdate(path, {
- val parent = ensureDir(dirs, dirName(path), null)
- val dir = new DirEntry(path)
- parent.entries(baseName(path)) = dir
- dir
- })
- }
- protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = {
- if (entry.isDirectory) ensureDir(dirs, entry.getName, entry)
- else ensureDir(dirs, dirName(entry.getName), null)
- }
-}
-
-final class FileZipArchive(file: JFile) extends ZipArchive(file) {
- def iterator: Iterator[Entry] = {
- val zipFile = new ZipFile(file)
- val root = new DirEntry("/")
- val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
- val enum = zipFile.entries()
-
- while (enum.hasMoreElements) {
- val zipEntry = enum.nextElement
- val dir = getDir(dirs, zipEntry)
- if (zipEntry.isDirectory) dir
- else {
- class FileEntry() extends Entry(zipEntry.getName) {
- override def getArchive = zipFile
- override def lastModified = zipEntry.getTime()
- override def input = getArchive getInputStream zipEntry
- override def sizeOption = Some(zipEntry.getSize().toInt)
- }
- val f = new FileEntry()
- dir.entries(f.name) = f
- }
- }
-
- try root.iterator
- finally dirs.clear()
- }
-
- def name = file.getName
- def path = file.getPath
- def input = File(file).inputStream()
- def lastModified = file.lastModified
-
- override def sizeOption = Some(file.length.toInt)
- override def canEqual(other: Any) = other.isInstanceOf[FileZipArchive]
- override def hashCode() = file.hashCode
- override def equals(that: Any) = that match {
- case x: FileZipArchive => file.getAbsoluteFile == x.file.getAbsoluteFile
- case _ => false
- }
-}
-
-final class URLZipArchive(val url: URL) extends ZipArchive(null) {
- def iterator: Iterator[Entry] = {
- val root = new DirEntry("/")
- val dirs = mutable.HashMap[String, DirEntry]("/" -> root)
- val in = new ZipInputStream(new ByteArrayInputStream(Streamable.bytes(input)))
-
- @tailrec def loop() {
- val zipEntry = in.getNextEntry()
- class EmptyFileEntry() extends Entry(zipEntry.getName) {
- override def toByteArray: Array[Byte] = null
- override def sizeOption = Some(0)
- }
- class FileEntry() extends Entry(zipEntry.getName) {
- override val toByteArray: Array[Byte] = {
- val len = zipEntry.getSize().toInt
- val arr = new Array[Byte](len)
- var offset = 0
-
- def loop() {
- if (offset < len) {
- val read = in.read(arr, offset, len - offset)
- if (read >= 0) {
- offset += read
- loop()
- }
- }
- }
- loop()
-
- if (offset == arr.length) arr
- else throw new IOException("Input stream truncated: read %d of %d bytes".format(offset, len))
- }
- override def sizeOption = Some(zipEntry.getSize().toInt)
- }
-
- if (zipEntry != null) {
- val dir = getDir(dirs, zipEntry)
- if (zipEntry.isDirectory)
- dir
- else {
- val f = if (zipEntry.getSize() == 0) new EmptyFileEntry() else new FileEntry()
- dir.entries(f.name) = f
- }
- in.closeEntry()
- loop()
- }
- }
-
- loop()
- try root.iterator
- finally dirs.clear()
- }
-
- def name = url.getFile()
- def path = url.getPath()
- def input = url.openStream()
- def lastModified =
- try url.openConnection().getLastModified()
- catch { case _: IOException => 0 }
-
- override def canEqual(other: Any) = other.isInstanceOf[URLZipArchive]
- override def hashCode() = url.hashCode
- override def equals(that: Any) = that match {
- case x: URLZipArchive => url == x.url
- case _ => false
- }
-}