dmose%mozilla.org 9fc7780ead updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52523 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:20:05 +00:00

503 lines
13 KiB
Java

/*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Netscape Messaging Access SDK Version 3.5 code,
* released on or about June 15, 1998. *
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): ______________________________________.
*/
/*
* Copyright (c) 1997 and 1998 Netscape Communications Corporation
* (http://home.netscape.com/misc/trademarks.html)
*/
package netscape.messaging.mime;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* ByteString is similar to java.lang.String, except that it contains
* bytes instead of characters.
*/
public class ByteString extends Object implements Cloneable {
protected byte[] buffer;
protected int lo;
protected int hi;
protected static byte CR = '\r';
protected static byte LF = '\n';
protected static byte[] CRLF = "\r\n".getBytes();
protected ByteString () {
buffer = null;
lo = 0;
hi = 0;
}
public ByteString (String string) {
buffer = string.getBytes();
lo = 0;
hi = buffer.length;
}
public ByteString (byte[] buffer) {
this.buffer = buffer;
this.lo = 0;
this.hi = buffer.length;
}
public ByteString (byte[] buffer, int lo, int hi) {
if (lo > hi) throw new IndexOutOfBoundsException();
this.buffer = buffer;
this.lo = lo;
this.hi = hi;
}
/**
* hashCode() -- Overrides java.lang.Object.hashCode()
*/
public final int hashCode () {
int result = 0;
// TODO: improve hash function
for (int i = lo; i < hi; i++) {
result += buffer[i];
}
return result;
}
/**
* equals() -- Overrides java.lang.Object.equals()
*/
public final boolean equals (Object that) {
if (this == that)
return true;
else
return equals(((ByteString) that).buffer, ((ByteString) that).lo, ((ByteString) that).size());
}
public final boolean equals (byte[] buf) {
return equals(buf, 0, buf.length);
}
public final boolean equals (byte[] buf, int low, int length) {
if (this.size() != length)
return false;
for (int i = 0; i < length; i++) {
if (this.byteAt(i) != buf[low++])
return false;
}
return true;
}
/**
* Compare this to that in lex order
*/
public final boolean greaterOrEqual (ByteString that) {
int m = this.size();
int n = that.size();
for (int i = 0; i < n; i++) {
if (i >= m)
return false;
else {
byte x = this.byteAt(i);
byte y = that.byteAt(i);
if (x < y)
return false;
else if (x > y)
return true;
}
}
return true;
}
/**
* Return number of bytes
*/
public final int size () {
return (hi-lo);
}
/**
* Return byte at given offset.
*/
public final byte byteAt (int i) {
if (lo + i >= hi) throw new IndexOutOfBoundsException();
return buffer[lo+i];
}
/**
* Check whether the ByteString starts with the given byte[].
* Ignores case.
*/
private final boolean startsWith (byte[] that) {
if (that.length > hi - lo) return false;
for (int i = 0; i < that.length; i++) {
char x = (char)(buffer[lo+i]);
char y = (char)(that[i]);
if (x != y && (x < 'a' || x > 'z' || (x + 'A' - 'a') != y))
return false;
}
return true;
}
/**
* Returns the offset for the first occurrence of a given byte
* in the ByteString if present, and -1 otherwise.
*/
public final int firstIndexOf (byte x) {
for (int i = lo; i < hi; i++) {
if (buffer[i] == x)
return (i-lo);
}
return (-1);
}
/**
* Returns the offset for the first occurrence of a given byte
* in the ByteString to the right of the given offset if present, and
* -1 otherwise.
*/
public final int firstIndexOf (byte x, int offset) {
for (int i = lo+offset+1; i < hi; i++) {
if (buffer[i] == x)
return (i-lo);
}
return (-1);
}
/**
* Returns the offset for the last occurrence of a given byte
* in the ByteString if present, and -1 otherwise.
*/
public final int lastIndexOf (byte x) {
for (int i = hi; --i >= lo; ) {
if (buffer[i] == x)
return (i-lo);
}
return -1;
}
/**
* Returns the offset for the last occurrence of a given byte
* in the ByteString to the left of the given offset if present, and
* -1 otherwise.
*/
public final int lastIndexOf (byte x, int offset) {
for (int i = lo+offset; --i >= lo; ) {
if (buffer[i] == x)
return (i-lo);
}
return -1;
}
/**
* Return the offset for the first occurrence of a given byte[]
* in the ByteString to the right of the given offset if present,
* and -1 otherwise. Case insensitive.
*/
public final int firstIndexOf (byte[] that) {
return firstIndexOf(that, 0);
}
/**
* Return the offset for the first occurrence of a given byte[]
* in the ByteString to the right of the given offset if present,
* and -1 otherwise. Case insensitive.
*/
public final int firstIndexOf (byte[] that, int offset) {
for (int i = lo+offset; i <= hi-that.length; i++) {
int j;
for (j = 0; j < that.length; j++) {
char x = (char)(buffer[i+j]);
char y = (char)(that[j]);
if (x != y && (x < 'a' || x > 'z' || (x + 'A' - 'a') != y))
break;
}
if (j >= that.length) {
return i-lo;
}
}
return -1;
}
/**
* Convert to String
*/
public final String toString () {
return new String(buffer, lo, hi-lo);
}
/**
* Convert to byte[]
* clone version
*/
public final byte[] getBytes () { return getBytes( true ); }
/**
* Convert to byte[]
* clonable version
*/
public final byte[] getBytes ( boolean clone )
{
if ( clone )
{
byte[] result = new byte[hi-lo];
System.arraycopy(buffer, lo, result, 0, hi-lo);
return result;
}
return buffer;
}
public final byte[] getBytes ( int len[] )
{
len[0] = hi;
return buffer;
}
/**
* Extract X out of ByteString X+Y+Z, where Y is the given delimiter.
* Replace original ByteString (X+Y+Z) by Z. Not MT-safe.
* Returns null if Y is absent.
*/
public final ByteString extractTill (byte[] y) {
int offset = firstIndexOf(y, 0);
if (offset < 0) {
return null;
}
else {
ByteString result = substring(0, offset);
lo += (offset + y.length);
return result;
}
}
/**
* Remove Y from ByteString Y+Z, where Y is the given token,
* If successful, replace original ByteString (Y+Z) by Z, and
* & return true. Else return false. Not MT-safe.
* Throw ArrayIndexOutOfBoundsException if ByteString does
* not start with Y.
*/
public final boolean extractToken (byte[] y) {
if (startsWith(y)) {
lo += y.length;
return true;
}
else {
return false;
}
}
/**
* Discard COUNT bytes from ByteString
*/
public final void discard(int count) {
if (lo + count > hi) throw new IndexOutOfBoundsException();
lo += count;
}
/**
* Discard X+Y from ByteString X+Y+Z, where Y is the given token.
* Throw ArrayIndexOutOfBoundsException if Y is absent.
*/
public final void discardTill (byte[] y) {
lo += (firstIndexOf(y, 0) + y.length);
}
/**
* Discard X+Y from ByteString X+Y+Z, where Y is LF or CRLF.
* Throw ArrayIndexOutOfBoundsException if Y is absent.
*/
public final void discardLine () {
lo += (firstIndexOf(LF, 0) + 1);
}
/**
* Checks for absence of complete lines
*/
public final boolean noLines () {
return firstIndexOf(LF, 0) < 0;
}
/**
* Checks for absence of complete lines to the right of the given offset
*/
public final boolean noLines (int offset) {
return firstIndexOf(LF, offset) < 0;
}
/*
* Extract the first line and return it as a substring.
* Throw ArrayIndexOutOfBoundsException if there are no lines.
*/
public final ByteString extractLine() {
ByteString result;
int offset = firstIndexOf(LF, 0);
if (offset > 1 && byteAt(offset-1) == CR) {
result = substring(0, offset-1);
lo += (offset + 1);
}
else {
result = substring(0, offset);
lo += (offset + 1);
}
return result;
}
/**
* Extract the first line and write it to given output stream.
* Throw ArrayIndexOutOfBoundsException if there are no lines.
* return number of byte wrote
*/
public final int extractLine(OutputStream stream)
throws IOException {
int origin = lo;
int offset = firstIndexOf(LF, 0);
if (offset > 1 && byteAt(offset-1) == CR) {
stream.write(buffer, lo, offset-1);
stream.write(CRLF);
lo += (offset + 1);
}
else {
stream.write(buffer, lo, offset);
stream.write(CRLF);
lo += (offset + 1);
}
return (lo - origin);
}
public void discardLeadingSpace()
{
// skip leading space
for (; lo < hi; lo++) {
if (buffer[lo] != ' ' )
break;
}
}
/**
* bulk write to a stream.
*/
public final void write (OutputStream stream)
throws IOException {
stream.write(buffer, lo, hi-lo);
}
/**
* Extract a long
**/
public final long extractLong() {
long n = 0;
for (int i = lo; i < lo+8; i++) {
n <<= 8;
n += buffer[i];
}
lo += 8;
return n;
}
/**
* Extract an int
**/
public final int extractInt() {
int n = 0;
for (int i = lo; i < lo+4; i++) {
n <<= 8;
n += buffer[i];
}
lo += 4;
return n;
}
/**
* Return substring from offset start (inclusive) till offset
* finish (exclusive).
*/
public ByteString substring (int start, int finish) {
if (start > finish || lo+finish > hi)
throw new IndexOutOfBoundsException();
return new ByteString(buffer, lo+start, lo+finish);
}
/**
* Return substring from offset start (inclusive) till the
* end of the ByteString.
*/
public ByteString substring (int start) {
if (lo+start > hi) throw new IndexOutOfBoundsException();
return new ByteString(buffer, lo+start, hi);
}
/**
* Display the contents of the ByteString for
* the purpose of debugging
*/
public void displayBuffer (String caption, BufferedOutputStream stream) {
int saved = lo;
try {
for (int i = 0; !noLines(); i++) {
stream.write(caption.getBytes());
extractLine(stream);
}
stream.write(caption.getBytes());
stream.write(getBytes());
lo = saved;
stream.flush();
} catch (IOException e) {
System.err.println(e + " while displaying contents of ByteString");
}
}
/**
* Clones an instance of the ByteString object.
* @exception CloneNotSupportedException could be thrown by constituent components.
*/
public Object clone () throws CloneNotSupportedException
{
ByteString l_theClone = (ByteString) super.clone();
if (buffer != null)
{
l_theClone.buffer = new byte [buffer.length];
System.arraycopy (buffer, 0, l_theClone.buffer, 0, buffer.length);
}
return (l_theClone);
}
public void setSize( int len )
{
hi = len;
lo = 0;
}
}