summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/io/AbstractFile.scala
blob: 8753396e1641ae90acf34810ab9a843f09975371 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                


       
                          

 
                   



                                           
                                                                   





                                                                   
                                                                     


                                                
                                                                             


















                                                                        
























                                                                          






                                                                            
                  

                                                
                  

                                                               
                

                                           
                          

                                                                    
                        

                                                                   



                                                                                   

                                                                  
                                      
 







                                                                             
     
                                                                
 







                                                                               

                                                                    




                                                                        
                  





                                                                        




                                                
                                


                                                                            
/* NSC -- new Scala compiler
 * Copyright 2005-2006 LAMP/EPFL
 * @author  Martin Odersky
 */
// $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
  }

}

/**
 * <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>
 *   bq: The interface allows to access the content as bytes and as chars.
 *   In fact, only the ClassFileParser should access bytes, because
 *   only there we know that the charset of the file is UTF-8. For
 *   all other cases, the <code>global.settings.encoding.value</code> must
 *   be respected.
 * </p>
 * @todo it would be better if reading chars from sources was exclusively
 *       done in <code>SourceFile</code> and reading bytes for classfiles
 *       was done in <code>symtab.classfile.AbstractFileReader</code>.
 */
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 getBytes: Array[Byte] = error("getBytes not supported by "+this.getClass())

  /** Reads the content of this abstract file into a char array. */
  //def getChars: Array[Char] = error("getChars not supported by "+this.getClass())

  /** 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
   *  <code>directory</code> tells whether to look for a directory or
   *  a regular file.
   *
   *  @param name      ...
   *  @param directory ...
   *  @return          ...
   */
  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
   *  <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 = {
    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)
      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

  //########################################################################
}