pjs/grendel/storage/DotTerminatedInputStream.java

154 строки
4.3 KiB
Java

/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Grendel mail/news client.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are Copyright (C) 1997
* Netscape Communications Corporation. All Rights Reserved.
*
* Created: Terry Weissman <terry@netscape.com>, 5 Sep 1997.
*/
package grendel.storage;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import calypso.util.Assert;
import calypso.util.ByteBuf;
import calypso.util.ByteLineBuffer;
class DotTerminatedInputStream extends FilterInputStream {
private static final int CAPACITY = 1024;
ByteBuf curline = new ByteBuf();
ByteBuf inbuf = new ByteBuf(CAPACITY);
ByteLineBuffer linebuf;
boolean eof = false;
DotTerminatedInputStream(InputStream s) {
super(s);
linebuf = new ByteLineBuffer();
ByteBuf inputeol = new ByteBuf();
inputeol.append((byte) '\r');
inputeol.append((byte) '\n');
linebuf.setInputEOL(inputeol);
}
public int read(byte[] buf, int start, int length) throws IOException {
if (length <= 0) return length;
int curlen = curline.length();
if (curlen == 0) {
if (eof) return -1;
while (!linebuf.pullLine(curline)) {
inbuf.setLength(CAPACITY);
int inlen = in.read(inbuf.toBytes(), 0, CAPACITY);
if (inlen <= 0) {
eof = true;
linebuf.pushEOF();
linebuf.pullLine(curline); // Try for the last gasp...
break;
}
inbuf.setLength(inlen);
// System.out.println("<< " + inbuf);
linebuf.pushBytes(inbuf);
}
// System.out.println(">> " + curline);
curlen = curline.length();
if (curlen >= 2 && curline.byteAt(0) == '.') {
byte c = curline.byteAt(1);
if (c == '\r' || c == '\n') {
eof = true;
curline.setLength(0);
curlen = 0;
} else if (c == '.' && curlen >= 3) {
c = curline.byteAt(2);
if (c == '\r' || c == '\n') {
// This line is a "..", which we need to translate to ".".
curline.remove(0, 1);
curlen--;
}
}
}
if (curlen == 0) return -1;
}
int result = length;
if (result > curlen) result = curlen;
curline.getBytes(0, result, buf, start);
curlen -= result;
curline.remove(0, result);
// for (int i=0 ; i<result ; i++) System.out.print(buf[i]);
return result;
}
public int read(byte[] buf) throws IOException {
return read(buf, 0, buf.length);
}
byte[] singlebyte;
public int read() throws IOException {
if (singlebyte == null) singlebyte = new byte[1];
if (read(singlebyte, 0, 1) <= 0) return -1;
return singlebyte[0];
}
public long skip(long n) {
return 0; // Feh.
}
public boolean markSupported() {
return false;
}
public void close() {
if (!eof) {
// Flush out the rest of the data.
byte tmp[] = new byte[CAPACITY];
int numread;
do {
numread = -1;
try {
numread = read(tmp, 0, CAPACITY);
} catch (IOException e) {
}
} while (numread > 0);
}
}
// Suck everything up into a buffer, so that we can use the input socket
// for something else. Right now, we just suck it into memory; we should
// put it on a temp file if it becomes real big. ###
public void bufferUpEverything() {
if (eof) return;
ByteBuf tmp = new ByteBuf(CAPACITY);
int length = 0;
for (;;) {
tmp.ensureCapacity(length + CAPACITY);
int numread = -1;
try {
numread = read(tmp.toBytes(), length, CAPACITY);
} catch (IOException e) {
}
if (numread <= 0) break;
length += numread;
}
Assert.Assertion(eof);
curline = tmp;
}
}