summaryrefslogblamecommitdiff
path: root/sources/scalac/util/AbstractFile.java
blob: 7069df868be1a4d1e7ac723fe85bfc2a5f6a2c26 (plain) (tree)








































                                                                          



                                        

























































































                                                                                 



                                


































































                                                                       



                                  

























































                                                              



                                



































































                                                                             



                                
























































































































                                                                              



                                    


































































                                                                



                                    


























                                                                



                                                       

















                                                                
/*     ____ ____  ____ ____  ______                                     *\
**    / __// __ \/ __// __ \/ ____/    SOcos COmpiles Scala             **
**  __\_ \/ /_/ / /__/ /_/ /\_ \       (c) 2002, LAMP/EPFL              **
** /_____/\____/\___/\____/____/                                        **
**                                                                      **
** $Id$
\*                                                                      */

package scalac.util;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;

public abstract class AbstractFile {

    /** separator
     */
    protected char separator = File.separatorChar;

    /** table of all opened jar-files
     */
    protected static Hashtable  opened = new Hashtable();

    /** get name of the file
     */
    public abstract String getName();

    /** get path of the file
     */
    public abstract String getPath();

    /** does the file exist?
     */
    public abstract boolean exists();

    /** is the file a directory?
     */
    public abstract boolean isDirectory();

    /** date file was last modified
     */
    public abstract long lastModified();

    /** read content of the file into a byte[] buffer
     */
    public abstract byte[] read() throws IOException;

    /** list contents of a directory
     */
    public abstract String[] list() throws IOException;

    /** open a new file
     */
    public abstract AbstractFile open(String name);

    /** return an input stream for the file
     */
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(read());
    }

    /** open file 'name' in directory 'dirname'
     */
    public static AbstractFile open(String dirname, String name) {
        AbstractFile res;
        if (dirname == null)
            res = new PlainFile(new File(name));
        else if (dirname.endsWith(".zip")) {
            AbstractFile dir = (AbstractFile)opened.get(dirname);
            if (dir == null) {
                dir = new ZipDir(new File(dirname));
                if (dir.isDirectory())
                    opened.put(dirname, dir);
            }
            res = (name == null) ? dir : dir.open(name);
        } else if (dirname.endsWith(".jar")) {
            AbstractFile dir = (AbstractFile)opened.get(dirname);
            if (dir == null) {
                dir = new JarArchive(new File(dirname));
                if (dir.isDirectory())
                    opened.put(dirname, dir);
            }
            res = (name == null) ? dir : dir.open(name);
        } else if (name == null)
            res = new PlainFile(new File(dirname));
        else
            res = new PlainFile(new File(dirname, name));
        if (!res.exists())
            res = null;
        return res;
    }

    /** create file given by a fully qualified name from root directory `outdir';
     *  create intermediate directories if they do not exist already
     */
    public static File create(File outdir, String name,
                              String suffix) throws IOException {
        int     start = 0;
        int     end = name.indexOf('.');
        while (end >= start) {
            outdir = new File(outdir, name.substring(start, end));
            if (!outdir.exists())
                outdir.mkdir();
            start = end + 1;
            end = name.indexOf('.', start);
        }
        return new File(outdir, name.substring(start) + suffix);
    }
}

class PlainFile extends AbstractFile {
    File f;

    PlainFile(File f) {
        this.f = f;
    }

    public String getName() {
        return f.getName();
    }

    public String getPath() {
        return f.getPath();
    }

    public boolean exists() {
        return f.exists();
    }

    public boolean isDirectory() {
        return f.isDirectory();
    }

    public long lastModified() {
	return f.lastModified();
    }

    public byte[] read() throws IOException {
        FileInputStream in = new FileInputStream(f);
        int rest = (int)f.length();
        byte[] buf = new byte[rest];
        do {
            int res = in.read(buf, buf.length - rest, rest);
            if (res == -1)
                throw new IOException("read error");
            rest -= res;
        } while (rest > 0);
        in.close();
        return buf;
    }

    public String[] list() throws IOException {
        File[] fs = f.listFiles();
        if (fs == null)
            return new String[0];
        String[] res = new String[fs.length];
        for (int i = 0; i < fs.length; i++) {
            res[i] = fs[i].getName();
            if (fs[i].isDirectory() &&
                !res[i].endsWith("/"))
                res[i] = res[i] + "/";
        }
        return res;
    }

    public AbstractFile open(String name) {
        return new PlainFile(new File(f, name));
    }
}

class ZippedFile extends AbstractFile {
    ZipDir      dir;
    ZipEntry    zipEntry;

    {
        separator = '/';
    }

    ZippedFile(ZipDir dir, String name) {
        this.dir = dir;
        if (dir.zipFile != null) {
            name = name.replace(File.separatorChar, separator);
            zipEntry = this.dir.zipFile.getEntry(name);
            if (zipEntry == null)
                zipEntry = this.dir.zipFile.getEntry(name + separator);
        }
    }

    public String getName() {
        return zipEntry.getName();
    }

    public String getPath() {
        return dir.getPath() + "(" + zipEntry.getName() + ")";
    }

    public boolean exists() {
        return (zipEntry != null);
    }

    public boolean isDirectory() {
        return zipEntry.isDirectory();
    }

    public long lastModified() {
	return zipEntry.getTime();
    }

    public byte[] read() throws IOException {
        InputStream in = dir.zipFile.getInputStream(zipEntry);
        int rest = (int)zipEntry.getSize();
        byte[] buf = new byte[rest];
        do {
            int res = in.read(buf, buf.length - rest, rest);
            if (res == -1)
                throw new IOException("read error");
            rest -= res;
        } while (rest > 0);
        in.close();
        return buf;
    }

    public String[] list() throws IOException {
        if (!isDirectory())
            throw new IOException("not a directory");
        return dir.list(zipEntry.getName());
    }

    public AbstractFile open(String name) {
        String  pathname = zipEntry.getName();
        return new ZippedFile(dir, pathname + name);
    }
}

class ZipDir extends AbstractFile {
    File f;
    ZipFile zipFile;

    {
        separator = '/';
    }

    ZipDir(File f) {
        this.f = f;
        try {
            zipFile = new ZipFile(f);
        } catch (ZipException e) {
        } catch (IOException e) {}
    }

    public String getName() {
        return f.getName();
    }

    public String getPath() {
        return f.getPath();
    }

    public boolean exists() {
        return (zipFile != null);
    }

    public boolean isDirectory() {
        return (zipFile != null);
    }

    public long lastModified() {
	return -1;
    }

    public byte[] read() throws IOException {
        throw new IOException("cannot read directory");
    }

    public String[] list(String prefix) {
        int n = 0;
        for (Enumeration enum = zipFile.entries(); enum.hasMoreElements();) {
            ZipEntry    e = (ZipEntry)enum.nextElement();
            if (e.getName().startsWith(prefix)) {
                String  candidate = e.getName().substring(prefix.length());
                if (candidate.indexOf(separator) < 0)
                    n++;
            }
        }
        String[] filenames = new String[n];
        n = 0;
        for (Enumeration enum = zipFile.entries(); enum.hasMoreElements();) {
            ZipEntry    e = (ZipEntry)enum.nextElement();
            if (e.getName().startsWith(prefix)) {
                String  candidate = e.getName().substring(prefix.length());
                if (candidate.indexOf(separator) < 0)
                    filenames[n++] = candidate;
            }
        }
        return filenames;
    }

    public String[] list() throws IOException {
        return list("");
    }

    public AbstractFile open(String name) {
        return new ZippedFile(this, name);
    }
}

final class JarArchive extends AbstractFile {
    File f;
    JarFile jarFile;
    HashMap entries;

    public final static String[] EMPTY = new String[0];


    JarArchive(File f) {
        try {
            jarFile = new JarFile(this.f = f);
        }
        catch (ZipException e) {}
        catch (IOException e) {}
    }

    public String getName() {
        return f.getName();
    }

    public String getPath() {
        return f.getPath();
    }

    public boolean exists() {
        return jarFile != null;
    }

    public boolean isDirectory() {
        return jarFile != null;
    }

    public long lastModified() {
	return -1;
    }

    public byte[] read() throws IOException {
        throw new IOException("cannot read archive");
    }

    private void load() {
        entries = new HashMap();
        if (jarFile == null)
            return;
        Enumeration enum = jarFile.entries();
        while (enum.hasMoreElements()) {
            String candidate = ((JarEntry)enum.nextElement()).getName();
            int i = candidate.indexOf('/');
            int j = 0;
            HashMap files = entries;
            while (i >= 0) {
                String dirname = candidate.substring(j, j = (i + 1));
                JarDirEntry dir = (JarDirEntry)files.get(dirname);
                if (dir == null)
                    files.put(dirname, dir = new JarDirEntry(
                        candidate.substring(0, j)));
                files = dir.entries;
                i = candidate.indexOf('/', j);
            }
            if (j < (candidate.length() - 1)) {
                String filename = candidate.substring(j);
                JarFileEntry file = (JarFileEntry)files.get(filename);
                if (file == null)
                    files.put(filename, new JarFileEntry(candidate));
            }
        }
    }

    public String[] list(String prefix) {
        prefix = prefix.replace(File.separatorChar, '/');
        if (entries == null)
            load();
        int i = prefix.indexOf('/');
        int j = 0;
        HashMap files = entries;
        while (i >= 0) {
            String dirname = prefix.substring(j, j = (i + 1));
            JarDirEntry dir = (JarDirEntry)files.get(dirname);
            if (dir == null)
                return EMPTY;
            files = dir.entries;
            i = prefix.indexOf('/', j);
        }
        if (j < (prefix.length() - 1)) {
            String filename = prefix.substring(j);
            return (files.get(filename) != null) ? new String[]{prefix}
                                                 : EMPTY;
        } else
            return (String[])files.keySet().toArray(new String[files.size()]);
    }

    public String[] list() throws IOException {
        return list("");
    }

    public AbstractFile open(String name) {
        if (entries == null)
            load();
        name = name.replace(File.separatorChar, '/');
        int i = name.indexOf('/');
        int j = 0;
        int namelen = name.length();
        HashMap files = entries;
        while (i >= 0) {
            String dirname = name.substring(j, j = (i + 1));
            if (files != null) {
                JarDirEntry dir = (JarDirEntry)files.get(dirname);
                if (dir == null)
                    files = null;
                else if (j == namelen)
                    return dir;
                else
                    files = dir.entries;
            }
            i = name.indexOf('/', j);
        }
        if (j < (namelen - 1)) {
            String filename = name.substring(j);
            if (files == null)
                return new NoJarFileEntry(name);
            JarFileEntry file = (JarFileEntry)files.get(filename);
            if (file == null)
                return new NoJarFileEntry(name);
            else
                return file;
        } else
            return new NoJarDirEntry(name);
    }

    static class NoJarDirEntry extends AbstractFile {
        String name;

        NoJarDirEntry(String name) {
            this.name = name;
        }

        public String getName() {
            return name.substring(
                name.lastIndexOf('/', name.length() - 2) + 1);
        }

        public String getPath() {
            return name;
        }

        public String getFullName() {
            return name;
        }

        public boolean exists() {
            return false;
        }

        public boolean isDirectory() {
            return true;
        }

	public long lastModified() {
	    return -1;
	}

        public String[] list() throws IOException {
            throw new IOException("not a directory");
        }

        public byte[] read() throws IOException {
            throw new IOException("cannot read archive");
        }

        public AbstractFile open(String fname) {
            throw new Error("cannot open archive entry");
        }
    }

    final class JarDirEntry extends NoJarDirEntry {
        HashMap entries;

        JarDirEntry(String name) {
            super(name);
            this.entries = new HashMap();
        }

        public String getPath() {
            return JarArchive.this.getPath() + "(" + name + ")";
        }

        public boolean exists() {
            return true;
        }

        public String[] list() throws IOException {
            return JarArchive.this.list(name);
        }

        public AbstractFile open(String fname) {
            fname = fname.replace(File.separatorChar, '/');
            return JarArchive.this.open(name + fname);
        }
    }

    static class NoJarFileEntry extends AbstractFile {
        String name;

        NoJarFileEntry(String name) {
            this.name = name;
        }

        public String getName() {
            return name.substring(
                name.lastIndexOf('/', name.length() - 1) + 1);
        }

        public String getFullName() {
            return name;
        }

        public String getPath() {
            return name;
        }

        public boolean exists() {
            return false;
        }

        public boolean isDirectory() {
            return false;
        }

	public long lastModified() {
	    return -1;
	}

        public String[] list() throws IOException {
            throw new IOException("not a directory");
        }

        public byte[] read() throws IOException {
            throw new IOException("cannot read archive");
        }

        public AbstractFile open(String fname) {
            throw new Error("not a directory");
        }
    }

    final class JarFileEntry extends NoJarFileEntry {

        JarFileEntry(String name) {
            super(name);
        }

        public String getPath() {
            return JarArchive.this.getPath() + "(" + name + ")";
        }

        public boolean exists() {
            return true;
        }

	public long lastModified() {
	    return jarFile.getJarEntry(name).getTime();
	}

        public byte[] read() throws IOException {
            JarEntry jarEntry = jarFile.getJarEntry(name);
            if (jarEntry == null)
                throw new IOException("unable to read " + name);
            InputStream in = jarFile.getInputStream(jarEntry);
            int rest = (int)jarEntry.getSize();
            byte[] buf = new byte[rest];
            do {
                int res = in.read(buf, buf.length - rest, rest);
                if (res == -1)
                    throw new IOException("read error");
                rest -= res;
            } while (rest > 0);
            in.close();
            return buf;
        }
    }
}