summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/util/AbstractFile.java
blob: 723d983a4ae840f774b36aa03af6d2a576b658af (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
\*                                                                      */

// $Id$

package scala.tools.util;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.jar.JarFile;
import java.util.zip.ZipFile;

/**
 * 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.
 */
public abstract class AbstractFile {

    //########################################################################
    // Public Factories

    /** Returns "getFile(new File(path))". */
    public static AbstractFile getFile(String path) {
        return 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.
     */
    public static AbstractFile getFile(File file) {
        return file.isFile() ? new PlainFile(file) : null;
    }


    /** Returns "getDirectory(new File(path))". */
    public static AbstractFile getDirectory(String path) {
        return 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.
     */
    public static AbstractFile getDirectory(File file) {
        if (file.isDirectory()) return new PlainFile(file);
        if (file.isFile()) {
            String path = file.getPath();
            if (path.endsWith(".jar") || path.endsWith(".zip"))
                return ZipArchive.fromFile(file);
        }
        return null;
    }

    //########################################################################
    // Public Methods

    /** Returns the name of this abstract file. */
    public abstract String getName();

    /** Returns the path of this abstract file. */
    public abstract String getPath();

    /** Returns the underlying File if any and null otherwise. */
    public abstract File getFile();

    /** Is this abstract file a directory? */
    public abstract boolean isDirectory();

    /** Returns the time that this abstract file was last modified. */
    public abstract long lastModified();

    /** Reads the content of this abstract file into a byte array. */
    public abstract byte[] read() throws IOException;

    /** Returns all abstract subfiles of this abstract directory. */
    public abstract Iterator/*<AbstractFile>*/ list();

    /**
     * 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.
     */
    public abstract AbstractFile lookupName(String name, boolean directory);

    /**
     * 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 or a regular file.
     */
    public final AbstractFile lookupPath(String path, boolean directory) {
        final int length = path.length();
        final char separator = File.separatorChar;
        assert 0 < length && path.lastIndexOf(separator) < length - 1: path;
        AbstractFile file = this;
        for (int start = 0, index; true; start = index + 1) {
            index = path.indexOf(separator, start);
            assert index < 0 || start < index: path+" - "+start+" - "+index;
            String name = path.substring(start, index < 0 ? length : index);
            file = file.lookupName(name, index < 0 ? directory : true);
            if (file == null || index < 0) return file;
        }
    }

    /** Returns the path of this abstract file. */
    public final String toString() {
        return getPath();
    }

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