mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-07 04:05:49 +00:00
350 lines
13 KiB
Java
350 lines
13 KiB
Java
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (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.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
package calypso.util;
|
|
|
|
/**
|
|
* This class is stores data in a private ByteBuf appending new
|
|
* data as needed, and returning line separated data.
|
|
*/
|
|
|
|
public class ByteLineBuffer {
|
|
|
|
private static final boolean DEBUG = false;
|
|
|
|
private boolean buffer_full;
|
|
private ByteBuf buffer;
|
|
private ByteBuf outputeol;
|
|
private ByteBuf inputeol;
|
|
|
|
/**
|
|
* Constructs an empty ByteLineBuffer.
|
|
*/
|
|
|
|
public ByteLineBuffer() {
|
|
buffer = new ByteBuf();
|
|
buffer_full = false;
|
|
|
|
if (DEBUG) {
|
|
System.err.println("BLB " + hashCode() + ": created");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Appends data to the end of the internal ByteBuf.
|
|
* @param buf data to append to internal buffer
|
|
*/
|
|
public void pushBytes(ByteBuf buf) {
|
|
if (DEBUG) {
|
|
System.err.print("BLB " + hashCode() + ": pushBytes(\"");
|
|
byte b[] = buf.toBytes();
|
|
for (int i = 0; i < buf.length(); i++)
|
|
System.err.print((b[i] == '\r' ? "\\r" :
|
|
b[i] == '\n' ? "\\n" :
|
|
b[i] == '\t' ? "\\t" :
|
|
b[i] == '"' ? "\\\"" :
|
|
b[i] == '\\' ? "\\\\" :
|
|
new String(b, i, 1)));
|
|
System.err.print("\")\n");
|
|
}
|
|
buffer.append(buf);
|
|
}
|
|
|
|
/**
|
|
* indicates that the last piece of data is now present.
|
|
*/
|
|
|
|
public void pushEOF() {
|
|
if (DEBUG) {
|
|
System.err.println("BLB " + hashCode() + ": pushEOF()");
|
|
}
|
|
buffer_full = true;
|
|
}
|
|
|
|
/** Sets the EOL characters to look for in the incoming stream. Setting
|
|
* this to be null will cause it to look for any of <CR>, <LF>, or <CRLF>.
|
|
* 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 <CR>, and no following byte (or EOF) has yet been read.)
|
|
*/
|
|
public void setInputEOL(ByteBuf buf) {
|
|
Assert.Assertion(buf == null || buf.length() > 0);
|
|
inputeol = buf;
|
|
}
|
|
|
|
/**
|
|
* End of line characters <CR> & <LF> 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) {
|
|
outputeol = buf;
|
|
}
|
|
|
|
/**
|
|
* Returns a ByteBuf with a line of data which was separated by
|
|
* <CR><LF> or any combination. Holds the last line in the ByteBuf
|
|
* until pushEOF() is called. If a ByteBuf containing data is sent in,
|
|
* the data is removed.
|
|
* @param buf single line of data in a ByteBuf
|
|
* @return true if a line was retrieved, false if not
|
|
*/
|
|
|
|
public boolean pullLine(ByteBuf buf) {
|
|
int position;
|
|
int buffer_length;
|
|
byte value;
|
|
// Remove any data that already exists in the buffer sent in
|
|
buf.setLength(0);
|
|
|
|
if (buffer_full && buffer == null)
|
|
return false;
|
|
|
|
buffer_length = buffer.length();
|
|
|
|
if (inputeol != null) {
|
|
int last = buffer_length - inputeol.length() + 1;
|
|
byte first = inputeol.byteAt(0);
|
|
byte[] peekbuf = buffer.toBytes();
|
|
for (position = 0 ; position < last ; position++) {
|
|
if (peekbuf[position] == first) {
|
|
boolean match = true;
|
|
for (int j=inputeol.length() - 1 ; j>=1 ; j--) {
|
|
if (peekbuf[position + j] != inputeol.byteAt(j)) {
|
|
match = false;
|
|
break;
|
|
}
|
|
}
|
|
if (match) {
|
|
buf.setLength(0);
|
|
if (outputeol != null) {
|
|
buf.append(peekbuf, 0, position);
|
|
buf.append(outputeol);
|
|
} else {
|
|
buf.append(peekbuf, 0,
|
|
position + inputeol.length());
|
|
}
|
|
buffer.remove(0, position + inputeol.length());
|
|
|
|
if (DEBUG) {
|
|
System.err.print("BLB " + hashCode() +
|
|
": EOL matched; returning: \"");
|
|
byte b[] = buf.toBytes();
|
|
for (int i = 0; i < buf.length(); i++)
|
|
System.err.print((b[i] == '\r' ? "\\r" :
|
|
b[i] == '\n' ? "\\n" :
|
|
b[i] == '\t' ? "\\t" :
|
|
b[i] == '"' ? "\\\"" :
|
|
b[i] == '\\' ? "\\\\" :
|
|
new String(b, i, 1)));
|
|
System.err.print("\"\n");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// process the entire buffer, or until a newline character is hit
|
|
for (position = 0; position < buffer_length; position++) {
|
|
value = buffer.byteAt(position);
|
|
if (value == '\n' || value == '\r') {
|
|
|
|
boolean ambiguous = true;
|
|
|
|
position++;
|
|
// got a newline, pass it
|
|
if (value == '\r' && position < buffer_length) {
|
|
|
|
if (DEBUG) {
|
|
System.err.println("BLB " + hashCode() +
|
|
": got \\r not at end of buffer");
|
|
}
|
|
|
|
// if we have seen \r, and we know what character
|
|
// lies after it, then there is no ambiguity:
|
|
// the linebreak is "\r" or "\r\n", and we can
|
|
// tell which it is.
|
|
//
|
|
ambiguous = false;
|
|
|
|
// if we are not replacing the EOL chars, return the
|
|
// existing ones
|
|
if (outputeol == null)
|
|
buf.append(value);
|
|
value = buffer.byteAt(position);
|
|
if (value == '\n') {
|
|
position++;
|
|
if (outputeol == null)
|
|
buf.append(value);
|
|
}
|
|
} else {
|
|
|
|
if (DEBUG) {
|
|
if (value == '\r')
|
|
System.err.println("BLB " + hashCode() +
|
|
": got \\r at end of buffer");
|
|
else
|
|
System.err.println("BLB " + hashCode() +
|
|
": got \\n without \\r");
|
|
}
|
|
|
|
// If we have seen \n, then the linebreak is
|
|
// unambiguously "\n". If we have seen \r, but we
|
|
// don't know what character follows it (because
|
|
// it happened to be at the end of the buffer) then
|
|
// the linebreak is ambiguous ("\r" or "\r\n").
|
|
//
|
|
ambiguous = (value == '\r');
|
|
|
|
if (outputeol == null) {
|
|
buf.append(value);
|
|
}
|
|
}
|
|
|
|
// if this is the last line in the buffer, and pushEOF()
|
|
// hasn't been called, and the linebreak was ambiguous,
|
|
// then wait for more data or a call to pushEOF() before
|
|
// returning this line.
|
|
//
|
|
if (position == buffer_length &&
|
|
!buffer_full &&
|
|
ambiguous) {
|
|
|
|
if (DEBUG) {
|
|
System.err.println("BLB " + hashCode() +
|
|
": waiting for next line");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
// remove the string from the internal ByteBuf
|
|
buffer.remove(0,position);
|
|
// if we have a replacement EOL string, use it
|
|
if (outputeol != null)
|
|
buf.append(outputeol);
|
|
|
|
if (DEBUG) {
|
|
System.err.print("BLB " + hashCode() +
|
|
": returning line: \"");
|
|
byte b[] = buf.toBytes();
|
|
for (int i = 0; i < buf.length(); i++)
|
|
System.err.print((b[i] == '\r' ? "\\r" :
|
|
b[i] == '\n' ? "\\n" :
|
|
b[i] == '\t' ? "\\t" :
|
|
b[i] == '"' ? "\\\"" :
|
|
b[i] == '\\' ? "\\\\" :
|
|
new String(b, i, 1)));
|
|
System.err.print("\"\n");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
// append bytes to output ByteBuf
|
|
buf.append(value);
|
|
}
|
|
}
|
|
// process full buffer
|
|
if (buffer_full && buffer_length > 0)
|
|
{
|
|
if (outputeol != null)
|
|
buf.append(outputeol);
|
|
buffer.remove(0,position);
|
|
buffer.Recycle(buffer);
|
|
buffer = null;
|
|
|
|
if (DEBUG) {
|
|
System.err.print("BLB " + hashCode() +
|
|
": at EOF; returning line: \"");
|
|
byte b[] = buf.toBytes();
|
|
for (int i = 0; i < buf.length(); i++)
|
|
System.err.print((b[i] == '\r' ? "\\r" :
|
|
b[i] == '\n' ? "\\n" :
|
|
b[i] == '\t' ? "\\t" :
|
|
b[i] == '"' ? "\\\"" :
|
|
b[i] == '\\' ? "\\\\" :
|
|
new String(b, i, 1)));
|
|
System.err.print("\"\n");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// didn't get a string this time around.
|
|
buf.setLength(0);
|
|
|
|
if (DEBUG) {
|
|
System.err.println("BLB " + hashCode() +
|
|
": don't have a line yet");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// public static void main(String args[]) {
|
|
//
|
|
// ByteLineBuffer blb = new ByteLineBuffer();
|
|
// ByteBuf bb = new ByteBuf();
|
|
// ByteBuf line_bytes = new ByteBuf(100);
|
|
//
|
|
// bb.setLength(0);
|
|
// bb.append("from: jwz");
|
|
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
|
// while(blb.pullLine(line_bytes)) {
|
|
// System.err.println(" pulled \"" + line_bytes + "\"");
|
|
// }
|
|
//
|
|
// bb.setLength(0);
|
|
// bb.append("\r\n");
|
|
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
|
// while(blb.pullLine(line_bytes)) {
|
|
// System.err.println(" pulled \"" + line_bytes + "\"");
|
|
// }
|
|
//
|
|
// bb.setLength(0);
|
|
// bb.append("content-type: text/plain");
|
|
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
|
// while(blb.pullLine(line_bytes)) {
|
|
// System.err.println(" pulled \"" + line_bytes + "\"");
|
|
// }
|
|
//
|
|
// bb.setLength(0);
|
|
// bb.append("\r\n");
|
|
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
|
// while(blb.pullLine(line_bytes)) {
|
|
// System.err.println(" pulled \"" + line_bytes + "\"");
|
|
// }
|
|
//
|
|
// bb.setLength(0);
|
|
// System.err.println("\npushed EOF"); blb.pushEOF();
|
|
// while(blb.pullLine(line_bytes)) {
|
|
// System.err.println(" pulled \"" + line_bytes + "\"");
|
|
// }
|
|
// }
|
|
|
|
}
|