Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/netscape/tools/car/CarFile.java

package netscape.tools.car;

import java.io.*;
import java.util.Hashtable;

class CarInputStream extends InputStream {
    RandomAccessFile in;
    long offset;
    int limit;

    CarInputStream(RandomAccessFile in, long offset, int length) {
	this.in = in;
	this.offset = offset;
	this.limit = length;
    }

    public int read() throws IOException {
	if (limit == 0) {
	    return -1;
	}
	in.seek(offset);
	int c = in.read();
	if (c == -1) {
	    limit = 0;
	} else {
	    offset++;
	    limit--;
	}
	return c;
    }

    public int read(byte b[]) throws IOException {
	return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
	if (len > limit) {
	    len = limit;
	}
	in.seek(offset);
	int rv = in.read(b, off, len);
	if (rv == -1) {
	    limit = 0;
	} else {
	    offset += rv;
	    limit -= rv;
	}
	return rv;
    }

    public long skip(long n) throws IOException {
	if (n > limit) {
	    limit = 0;
	    return 0;
	} else {
	    limit -= n;
	    offset += n;
	    return n;
	}
    }

    public int available() throws IOException {
	return limit;
    }

    public void close() {
    }

    public synchronized void mark(int readlimit) {
    }

    public synchronized void reset() throws IOException {
	throw new IOException("mark not supported");
    }

    public boolean markSupported() {
	return false;
    }
}

public class CarFile {
    RandomAccessFile in;
    Hashtable toc;

    public CarFile(File file) throws IOException {
	in = new RandomAccessFile(file, "r");
	readHeader();
    }

    public final int MAGIC = 0xBEBACAFF;
    public final int VERSION = 0x00000002;

    /**
     * Read in the header and the table of contents
     */
    void readHeader() throws IOException {
	int magic = in.readInt();
	if (magic != MAGIC) {
	    throw new IOException("bad magic number " + magic
				  + " (expected " + MAGIC + ")");
	}
	int version = in.readInt();
	if (version != VERSION) {
	    throw new IOException("bad version number " + version
				  + " (expected " + VERSION + ")");
	}
	int entries = in.readInt();
	if (entries < 0) {
	    throw new IOException("bad entries " + entries);
	}
	long length = in.readLong();
	readTOC(in, entries);	// XXX: should be able to check length
    }

    void readTOC(DataInput in, int n) throws IOException, UTFDataFormatException {
	toc = new Hashtable();
	for (int i = 0; i < n; i++) {
	    CarTOCEntry e = new CarTOCEntry(in);
	    toc.put(e.name, e);
	}
    }

    /**
     * Lookup the name in the car file and if found return an
     * input stream which can read the file in. If not found
     * return null.
     */
    public InputStream findFile(String name) {
	if (name.startsWith("./")) {
	    name = name.substring(2);
	}
	CarTOCEntry entry = (CarTOCEntry) toc.get(name);
	if (entry != null) {
	    return new CarInputStream(in, entry.offset, (int) entry.length);
	}
	return null;
    }
}