/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*- * * 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. */ package calypso.util; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import calypso.util.ByteBuf; import calypso.util.ByteLineBuffer; public class LineBufferingInputStream extends FilterInputStream { private static final boolean DEBUG = false; private static final int CAPACITY = 1024; ByteBuf curline = new ByteBuf(); ByteBuf inbuf = new ByteBuf(CAPACITY); ByteLineBuffer linebuf = new ByteLineBuffer(); boolean eof = false; public LineBufferingInputStream(InputStream s) { super(s); if (DEBUG) { System.err.println("LBIS " + hashCode() + ": created for " + s); } } /** Reads bytes into a portion of an array. This method will block until some input is available.

The returned data will not be more than one line long: that is, there will be at most one linebreak (CR, LF, or CRLF) and if it is present, it will be at the end.

If the next line available to be read is smaller than `length', then the first `length' bytes of that line will be returned, and the remainder of the bytes on that line will be available for subsequent reads. @return the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached. */ public int read(byte[] buf, int start, int length) throws IOException { if (DEBUG) { System.err.println("LBIS " + hashCode() + ": read(byte[], " + start + ", " + length + ")"); } 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); if (DEBUG) { byte b[] = inbuf.toBytes(); System.err.print("LBIS " + hashCode() + ": read " + inlen + " bytes: "); for (int i = 0; i < inlen; i++) System.err.print((b[i] == '\r' ? "\\r" : b[i] == '\n' ? "\\n" : b[i] == '\t' ? "\\t" : b[i] == '\\' ? "\\\\" : new String(b, i, 1))); System.err.print("\n"); } linebuf.pushBytes(inbuf); } curlen = curline.length(); 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); if (DEBUG) { byte b[] = curline.toBytes(); System.err.print("LBIS " + hashCode() + ": read line: "); for (int i = 0; i < curline.length(); i++) System.err.print((b[i] == '\r' ? "\\r" : b[i] == '\n' ? "\\n" : b[i] == '\t' ? "\\t" : b[i] == '\\' ? "\\\\" : new String(b, i, 1))); System.err.print("\n"); } 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() throws IOException { if (DEBUG) { System.err.println("LBIS " + hashCode() + ": closed"); } curline = null; inbuf = null; linebuf = null; eof = true; super.close(); } /** Sets the EOL characters to look for in the incoming stream. Setting * this to be null will cause it to look for any of , , or . * Note that null (the default) could cause up to one extra to be held in * the buffer (in the case where the last byte read from the underlying * stream was , and no following byte (or EOF) has yet been read.) */ public void setInputEOL(ByteBuf buf) { linebuf.setInputEOL(buf); } /** * End of line characters & or any combination * will be replaced by this string if it is present. Setting * this to a zero length string will cause them to be stripped. * Setting this to null will cause the EOL characters to be passed * through unchanged (the default). * @param buf ByteBuf representing EOL replacement string */ public void setOutputEOL(ByteBuf buf) { linebuf.setOutputEOL(buf); } }