Milán Major

netscape-revival

1 branch
Code

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

/*
 * @(#)
 *
 * CAR file reader/writer code
 *
 * @author Kipp E.B. Hickman
 */
package netscape.tools.car;

import java.io.*;
import java.util.Date;

class CarTOCEntry {
    File source;
    String name;
    long lastModified;
    long offset;
    long length;

    CarTOCEntry() {
    }

    static int utfLength(String str) {
	int strlen = str.length();
	int utflen = 0;
	for (int i = 0 ; i < strlen ; i++) {
	    int c = str.charAt(i);
	    if ((c >= 0x0001) && (c <= 0x007F)) {
		utflen++;
	    } else if (c > 0x07FF) {
		utflen += 3;
	    } else {
		utflen += 2;
	    }
	}
	return utflen;
    }

    static void writeUTF(OutputStream out, String str) throws IOException {
	int strlen = str.length();
	for (int i = 0 ; i < strlen ; i++) {
	    int c = str.charAt(i);
	    if ((c >= 0x0001) && (c <= 0x007F)) {
		out.write(c);
	    } else if (c > 0x07FF) {
		out.write(0xE0 | ((c >> 12) & 0x0F));
		out.write(0x80 | ((c >>  6) & 0x3F));
		out.write(0x80 | ((c >>  0) & 0x3F));
	    } else {
		out.write(0xC0 | ((c >>  6) & 0x1F));
		out.write(0x80 | ((c >>  0) & 0x3F));
	    }
	}
    }

    static String readUTF(InputStream in) throws IOException, UTFDataFormatException {
	// Read utf encoded bytes until we get a \0
	char str[] = new char[32];
	int ix = 0;
	for (;;) {
	    int c = in.read();
	    if (c == 0)
		break;
	    if (ix == str.length) {
		char newstr[] = new char[str.length * 2];
		System.arraycopy(str, 0, newstr, 0, str.length);
		str = newstr;
	    }
	    if ((c & 0x80) == 0) {
		// one byte encoding
		str[ix++] = (char) c;
	    } else if ((c & 0xE0) == 0xC0) {
		// two byte encoding
		int c1 = in.read();
		if ((c1 & 0xc0) != 0x80) {
		    throw new UTFDataFormatException();		  
		}
		str[ix++] = (char) (((c & 0x1f) << 6) | (c1 & 0x3f));
	    } else if ((c & 0xF0) == 0xE0) {
		// three byte encoding
		int c1 = in.read();
		int c2 = in.read();
		if (((c1 & 0xc0) != 0x80) || ((c2 & 0xc0) != 0x80)) {
		    throw new UTFDataFormatException();		  
		}
		str[ix++] = (char) (((c & 0x1f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f));
	    } else
		throw new UTFDataFormatException();		  
	}
	return new String(str, 0, ix);
    }

    static String readUTF(DataInput in) throws IOException, EOFException, UTFDataFormatException {
	// Read utf encoded bytes until we get a \0
	char str[] = new char[32];
	int ix = 0;
	for (;;) {
	    int c = in.readByte();
	    if (c == 0)
		break;
	    if (ix == str.length) {
		char newstr[] = new char[str.length * 2];
		System.arraycopy(str, 0, newstr, 0, str.length);
		str = newstr;
	    }
	    if ((c & 0x80) == 0) {
		// one byte encoding
		str[ix++] = (char) c;
	    } else if ((c & 0xE0) == 0xC0) {
		// two byte encoding
		int c1 = in.readByte();
		if ((c1 & 0xc0) != 0x80) {
		    throw new UTFDataFormatException();		  
		}
		str[ix++] = (char) (((c & 0x1f) << 6) | (c1 & 0x3f));
	    } else if ((c & 0xF0) == 0xE0) {
		// three byte encoding
		int c1 = in.readByte();
		int c2 = in.readByte();
		if (((c1 & 0xc0) != 0x80) || ((c2 & 0xc0) != 0x80)) {
		    throw new UTFDataFormatException();		  
		}
		str[ix++] = (char) (((c & 0x1f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f));
	    } else
		throw new UTFDataFormatException();		  
	}
	return new String(str, 0, ix);
    }

    int tocsize() {
	return 3*8 + utfLength(name) + 1;
    }

    /**
     * Write out the TOC entry
     */
    void writeTOC(DataOutputStream out) throws IOException {
	out.writeLong(lastModified);
	out.writeLong(offset);
	out.writeLong(length);
	writeUTF(out, name);
	out.writeByte(0);
    }

    /**
     * Read in a TOC entry
     */
    CarTOCEntry(DataInput in) throws IOException, UTFDataFormatException {
	lastModified = in.readLong();
	offset = in.readLong();
	length = in.readLong();
	name = readUTF(in);
    }

    public String toString() {
	return source.getPath() + ": "
	    + " modified=" + lastModified
	    + " length=" + length
	    + " offset=" + offset;
    }

    void printTOC(PrintStream out) throws IOException {
	out.println((new Date(lastModified)).toString()
		    + " " + length
		    + " " + offset
		    + " " + name);
    }

    void check(RandomAccessFile in) throws IOException, CarCheckException {
	byte buf1[] = new byte[4096];
	byte buf2[] = new byte[4096];
	BufferedInputStream in2 = new BufferedInputStream(
	    new FileInputStream(source.getPath()));
	long fileLength = source.length();
	if (fileLength != length) {
	    throw new CarCheckException("length mismatch: car has " + length +
					" while file has " + fileLength);
	}

	in.seek(offset);
	long off = 0;
	long rem = fileLength;
	while (rem != 0) {
	    long amount = rem;
	    if (amount > 4096) {
		amount = 4096;
	    }
	    int nb1 = in.read(buf1, 0, (int)amount);
	    int nb2 = in2.read(buf2, 0, nb1);
	    if ((nb1 != (int) amount) || (nb2 != nb1)) {
		throw new IOException("nb1 = " + nb1 + ", nb2 = " + nb2);
	    }
	    for (int i = 0; i < nb1; i++) {
		if (buf1[i] != buf2[i]) {
		    throw new CarCheckException("data misatch: offset="
						+ (off + i) +
						" read " + ((int)buf1[i]) +
						" expected " + ((int)buf2[i]));
		}
	    }
	    rem -= amount;
	    off += amount;
	}
    }
}