gecko-dev/grendel/sources/calypso/util/ByteBuf.java

922 строки
29 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): Edwin Woudt <edwin@woudt.nl>
*/
package calypso.util;
import java.util.*;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.RandomAccessFile;
/**
* This class is similar to java/lang/StringBuffer with the following changes:
* <UL><LI>Stores bytes, not chars
* <LI>None of the methods are synchronized
* <LI>There is no sharing of the character array
* <LI>Converting to a String requires a copy of the character data
* <LI>Alloc and Recycle are provided to speed up allocation
* <LI>A bunch of useful operations are provided (comparisons, etc.)
* </UL>
*/
public final class ByteBuf {
private byte value[];
private int count;
// static ByteBufRecycler gRecycler;
/**
* Constructs an empty String buffer, reusing one from the
* recycler.
*/
static synchronized public ByteBuf Alloc() {
return new ByteBuf();
// if (gRecycler == null) {
// gRecycler = new ByteBufRecycler();
// }
// return gRecycler.alloc();
}
/**
* Release a ByteBuf to the recycler. It is up to the caller
* to ensure that buffer is no longer being used otherwise
* unpredicatable program behavior will result.
*/
static synchronized public void Recycle(ByteBuf aBuf) {
// if (gRecycler == null) {
// gRecycler = new ByteBufRecycler();
// }
// gRecycler.recycle(aBuf);
}
/**
* Empty the recycler discarding any cached ByteBuf objects
*/
static synchronized public void EmptyRecycler() {
// if (null != gRecycler) {
// gRecycler = null;
// }
}
static void classFinalize() throws Throwable {
// Poof! Now we are unloadable even though we have a static
// variable.
}
/**
* Constructs an empty String buffer.
*/
public ByteBuf() {
this(16);
}
/**
* Constructs an empty byte buffer with the specified initial length.
* @param length the initial length
*/
public ByteBuf(int length) {
value = new byte[length];
}
/**
* Constructs a byte buffer with the specified initial value.
* @param str the initial value of the buffer
*/
public ByteBuf(String str) {
this(str.length() + 16);
append(str);
}
public ByteBuf(byte bytes[], int offset, int length) {
value = new byte[length];
System.arraycopy(bytes, offset, value, 0, length);
count = length;
}
/**
* Returns the length (character count) of the buffer.
*/
public int length() {
return count;
}
/**
* Returns the current capacity of the String buffer. The capacity
* is the amount of storage available for newly inserted
* characters; beyond which an allocation will occur.
*/
public int capacity() {
return value.length;
}
/**
* Ensures that the capacity of the buffer is at least equal to the
* specified minimum.
* @param minimumCapacity the minimum desired capacity
*/
public void ensureCapacity(int minimumCapacity) {
int maxCapacity = value.length;
if (minimumCapacity > maxCapacity) {
int newCapacity = (maxCapacity + 1) * 2;
if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
byte newValue[] = new byte[newCapacity];
System.arraycopy(value, 0, newValue, 0, count);
value = newValue;
}
}
/**
* Sets the length of the String. If the length is reduced, characters
* are lost. If the length is extended, the values of the new characters
* are set to 0.
* @param newLength the new length of the buffer
* @exception StringIndexOutOfBoundsException If the length is invalid.
*/
public void setLength(int newLength) {
if (newLength < 0) {
throw new StringIndexOutOfBoundsException(newLength);
}
if (count < newLength) {
ensureCapacity(newLength);
for (; count < newLength; count++) {
value[count] = (byte)'\0';
}
}
count = newLength;
}
/**
* Returns the byte at the specified index. An index ranges
* from 0..length()-1.
* @param index the index of the desired character
* @exception StringIndexOutOfBoundsException If the index is invalid.
*/
public byte byteAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
/**
* Copies the characters of the specified substring (determined by
* srcBegin and srcEnd) into the character array, starting at the
* array's dstBegin location. Both srcBegin and srcEnd must be legal
* indexes into the buffer.
* @param srcBegin begin copy at this offset in the String
* @param srcEnd stop copying at this offset in the String
* @param dst the array to copy the data into
* @param dstBegin offset into dst
* @exception StringIndexOutOfBoundsException If there is an invalid index into the buffer.
*/
public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
if ((srcBegin < 0) || (srcBegin >= count)) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if ((srcEnd < 0) || (srcEnd > count)) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin < srcEnd) {
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
}
/**
* Changes the byte at the specified index to be ch.
* @param index the index of the character
* @param ch the new character
* @exception StringIndexOutOfBoundsException If the index is invalid.
*/
public void setByteAt(int index, byte b) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
value[index] = b;
}
/**
* Appends an object to the end of this buffer.
* @param obj the object to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(Object obj) {
return append(String.valueOf(obj));
}
/**
* Appends a String to the end of this buffer. This just appends one byte
* per char; it strips off the upper 8 bits. If you want the localized
* method of converting chars to bytes, use append(String.getBytes()).
* @param str the String to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(String str) {
if (str == null) {
str = String.valueOf(str);
}
int len = str.length();
ensureCapacity(count + len);
for (int i=0 ; i<len ; i++) {
value[count++] = (byte) str.charAt(i);
}
return this;
}
/**
* Appends an array of bytes to the end of this buffer.
* @param str the characters to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(byte str[]) {
int len = str.length;
ensureCapacity(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
}
/**
* Appends a part of an array of characters to the end of this buffer.
* @param str the characters to be appended
* @param offset where to start
* @param len the number of characters to add
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(byte str[], int offset, int len) {
ensureCapacity(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
public ByteBuf append(ByteBuf buf) {
append(buf.toBytes(), 0, buf.length());
return this;
}
/**
* Appends a boolean to the end of this buffer.
* @param b the boolean to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(boolean b) {
return append(String.valueOf(b));
}
/**
* Appends a byte to the end of this buffer.
* @param ch the character to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(byte b) {
ensureCapacity(count + 1);
value[count++] = b;
return this;
}
/**
* Appends an integer to the end of this buffer.
* @param i the integer to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(int i) {
return append(String.valueOf(i));
}
/**
* Appends a long to the end of this buffer.
* @param l the long to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(long l) {
return append(String.valueOf(l));
}
/**
* Appends a float to the end of this buffer.
* @param f the float to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(float f) {
return append(String.valueOf(f));
}
/**
* Appends a double to the end of this buffer.
* @param d the double to be appended
* @return the ByteBuf itself, NOT a new one.
*/
public ByteBuf append(double d) {
return append(String.valueOf(d));
}
/**
* Inserts an object into the String buffer.
* @param offset the offset at which to insert
* @param obj the object to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
/**
* Inserts a String into the String buffer.
* @param offset the offset at which to insert
* @param str the String to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, String str) {
if ((offset < 0) || (offset > count)) {
throw new StringIndexOutOfBoundsException();
}
int len = str.length();
ensureCapacity(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
for (int i=0 ; i<len ; i++) {
value[offset++] = (byte) str.charAt(i);
}
count += len;
return this;
}
/**
* Inserts an array of bytes into the String buffer.
* @param offset the offset at which to insert
* @param str the characters to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, byte str[]) {
if ((offset < 0) || (offset > count)) {
throw new StringIndexOutOfBoundsException();
}
int len = str.length;
ensureCapacity(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
System.arraycopy(str, 0, value, offset, len);
count += len;
return this;
}
/**
* Inserts a boolean into the String buffer.
* @param offset the offset at which to insert
* @param b the boolean to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, boolean b) {
return insert(offset, String.valueOf(b));
}
/**
* Inserts a byte into the String buffer.
* @param offset the offset at which to insert
* @param ch the character to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset invalid.
*/
public ByteBuf insert(int offset, byte b) {
ensureCapacity(count + 1);
System.arraycopy(value, offset, value, offset + 1, count - offset);
value[offset] = b;
count += 1;
return this;
}
/**
* Inserts an integer into the String buffer.
* @param offset the offset at which to insert
* @param i the integer to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, int i) {
return insert(offset, String.valueOf(i));
}
/**
* Inserts a long into the String buffer.
* @param offset the offset at which to insert
* @param l the long to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, long l) {
return insert(offset, String.valueOf(l));
}
/**
* Inserts a float into the String buffer.
* @param offset the offset at which to insert
* @param f the float to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, float f) {
return insert(offset, String.valueOf(f));
}
/**
* Inserts a double into the String buffer.
* @param offset the offset at which to insert
* @param d the double to insert
* @return the ByteBuf itself, NOT a new one.
* @exception StringIndexOutOfBoundsException If the offset is invalid.
*/
public ByteBuf insert(int offset, double d) {
return insert(offset, String.valueOf(d));
}
/**
* Reverse the order of the characters in the String buffer.
*/
public ByteBuf reverse() {
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; --j) {
byte temp = value[j];
value[j] = value[n - j];
value[n - j] = temp;
}
return this;
}
/**
* Converts to a String representing the data in the buffer.
*/
public String toString() {
return new String(value, 0, count);
}
public byte[] toBytes() {
return value;
}
/**
* Compares this ByteBuf to another ByteBuf. Returns true if the
* other ByteBuf is equal to this ByteBuf; that is, has the same length
* and the same characters in the same sequence. Upper case
* characters are folded to lower case before they are compared.
*
* @param anotherString the String to compare this String against
* @return true if the Strings are equal, ignoring case; false otherwise.
*/
public boolean equalsIgnoreCase(ByteBuf anotherString) {
if ((anotherString != null) && (anotherString.count == count)) {
for (int i = 0; i < count; i++) {
byte c1 = value[i];
byte c2 = anotherString.value[i];
if (c1 != c2) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase((char) c1);
char u2 = Character.toUpperCase((char) c2);
if (u1 == u2)
continue;
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
continue;
return false;
}
}
return true;
}
return false;
}
public boolean equals(Object aObject) {
if (aObject != null) {
if (aObject instanceof ByteBuf) {
return equals((ByteBuf) aObject);
} else if (aObject instanceof String) {
return equals((String) aObject);
}
}
return false;
}
/**
* Compares this ByteBuf to another ByteBuf. Returns true if the
* other ByteBuf is equal to this ByteBuf; that is, has the same length
* and the same characters in the same sequence.
*
* @param anotherString the String to compare this String against
* @return true if the Strings are equal, ignoring case; false otherwise.
*/
public boolean equals(ByteBuf anotherString) {
if ((anotherString != null) && (anotherString.count == count)) {
for (int i = 0; i < count; i++) {
byte c1 = value[i];
byte c2 = anotherString.value[i];
if (c1 != c2) {
return false;
}
}
return true;
}
return false;
}
/**
* Compares this ByteBuf to another String. Returns true if the
* other String is equal to this ByteBuf; that is, has the same length
* and the same characters in the same sequence. (No localization is done;
* if the string doesn't contain 8-bit chars, it won't be equal to this
* ByteBuf.)
*
* @param anotherString the String to compare this String against
* @return true if the Strings are equal, ignoring case; false otherwise.
*/
public boolean equals(String anotherString) {
if ((anotherString != null) && (anotherString.length() == count)) {
for (int i = 0; i < count; i++) {
byte c1 = value[i];
byte c2 = (byte) anotherString.charAt(i);
if (c1 != c2) {
return false;
}
}
return true;
}
return false;
}
/**
* Tests if two byte regions are equal.
* <p>
* If <code>toffset</code> or <code>ooffset</code> is negative, or
* if <code>toffset</code>+<code>length</code> is greater than the
* length of this ByteBuf, or if
* <code>ooffset</code>+<code>length</code> is greater than the
* length of the argument, then this method returns
* <code>false</code>.
*
* @param toffset the starting offset of the subregion in this ByteBuf.
* @param other the other bytes.
* @param ooffset the starting offset of the subregion in the argument.
* @param len the number of bytes to compare.
* @return <code>true</code> if the specified subregion of this ByteBuf
* exactly matches the specified subregion of the argument;
* <code>false</code> otherwise.
*/
public boolean regionMatches(int toffset, byte other[],
int ooffset, int len) {
return regionMatches(false, toffset, other, ooffset, len);
}
/**
* Tests if two byte regions are equal.
* <p>
* If <code>toffset</code> or <code>ooffset</code> is negative, or
* if <code>toffset</code>+<code>length</code> is greater than the
* length of this ByteBuf, or if
* <code>ooffset</code>+<code>length</code> is greater than the
* length of the argument, then this method returns
* <code>false</code>.
*
* @param ignoreCase if <code>true</code>, ignore case when comparing
* bytes (treating them as characters).
* @param toffset the starting offset of the subregion in this
* ByteBuf.
* @param other the other bytes.
* @param ooffset the starting offset of the subregion in the
* argument.
* @param len the number of bytes to compare.
* @return <code>true</code> if the specified subregion of this ByteBuf
* matches the specified subregion of the argument;
* <code>false</code> otherwise. Whether the matching is exact
* or case insensitive depends on the <code>ignoreCase</code>
* argument.
*/
public boolean regionMatches(boolean ignoreCase,
int toffset,
byte other[],
int ooffset,
int len) {
/* Lifted (and changed from char to byte) from java.lang.String. */
byte ta[] = value;
int to = toffset;
int tlim = count;
byte pa[] = other;
int po = ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0) || (toffset > count - len) ||
(ooffset > other.length - len)) {
return false;
}
while (len-- > 0) {
byte c1 = ta[to++];
byte c2 = pa[po++];
if (c1 == c2)
continue;
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase((char) c1);
char u2 = Character.toUpperCase((char) c2);
if (u1 == u2)
continue;
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
continue;
}
return false;
}
return true;
}
public boolean regionMatches(int toffset, ByteBuf other,
int ooffset, int len) {
return regionMatches(false, toffset, other.value, ooffset, len);
}
public boolean regionMatches(boolean ignoreCase,
int toffset, ByteBuf other,
int ooffset, int len) {
return regionMatches(ignoreCase, toffset, other.value, ooffset, len);
}
/**
* Tests if two byte regions are equal.
* <p>
* If <code>toffset</code> or <code>ooffset</code> is negative, or
* if <code>toffset</code>+<code>length</code> is greater than the
* length of this ByteBuf, or if
* <code>ooffset</code>+<code>length</code> is greater than the
* length of the argument, then this method returns
* <code>false</code>.
*
* @param toffset the starting offset of the subregion in this ByteBuf.
* @param other the other String.
* @param ooffset the starting offset of the subregion in the argument.
* @param len the number of bytes/characters to compare.
* @return <code>true</code> if the specified subregion of this ByteBuf
* exactly matches the specified subregion of the String argument;
* <code>false</code> otherwise.
*/
public boolean regionMatches(int toffset, String other,
int ooffset, int len) {
return regionMatches(false, toffset, other, ooffset, len);
}
/**
* Tests if two byte regions are equal.
* <p>
* If <code>toffset</code> or <code>ooffset</code> is negative, or
* if <code>toffset</code>+<code>length</code> is greater than the
* length of this ByteBuf, or if
* <code>ooffset</code>+<code>length</code> is greater than the
* length of the argument, then this method returns
* <code>false</code>.
*
* @param ignoreCase if <code>true</code>, ignore case when comparing
* bytes (treating them as characters).
* @param toffset the starting offset of the subregion in this
* ByteBuf.
* @param other the other String.
* @param ooffset the starting offset of the subregion in the
* String argument.
* @param len the number of bytes to compare.
* @return <code>true</code> if the specified subregion of this ByteBuf
* matches the specified subregion of the String argument;
* <code>false</code> otherwise. Whether the matching is exact
* or case insensitive depends on the <code>ignoreCase</code>
* argument.
*/
public boolean regionMatches(boolean ignoreCase,
int toffset,
String other,
int ooffset,
int len) {
/* Lifted (and changed from char to byte) from java.lang.String. */
byte ta[] = value;
int to = toffset;
int tlim = count;
int po = ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0) || (toffset > count - len) ||
(ooffset > other.length() - len)) {
return false;
}
while (len-- > 0) {
byte c1 = ta[to++];
byte c2 = (byte) other.charAt(po++);
if (c1 == c2)
continue;
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase((char) c1);
char u2 = Character.toUpperCase((char) c2);
if (u1 == u2)
continue;
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
continue;
}
return false;
}
return true;
}
public int indexOf(int ch) {
return indexOf(ch, 0);
}
public int indexOf(int ch, int fromIndex) {
int max = count;
byte v[] = value;
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= count) {
// Note: fromIndex might be near -1>>>1.
return -1;
}
for (int i = fromIndex ; i < max ; i++) {
if (v[i] == ch) {
return i;
}
}
return -1;
}
public void remove(int fromIndex) {
remove(fromIndex, count);
}
/**
* Remove characters from the ByteBuf starting at fromIndex and up
* to but not including toIndex. If toIndex is beyond the length of
* the ByteBuf then it is automatically clamped to the end of the
* ByteBuf. If fromIndex is out of range a StringIndexOutOfBoundsException
* is thrown.
*/
public void remove(int fromIndex, int toIndex) {
if ((fromIndex >= toIndex) || (fromIndex >= count)) {
throw new StringIndexOutOfBoundsException(fromIndex);
}
if (toIndex > count) toIndex = count;
if (toIndex == count) {
count = fromIndex;
return;
}
System.arraycopy(value, toIndex, value, fromIndex, count - toIndex);
count -= toIndex - fromIndex;
}
public int toInteger() throws NumberFormatException {
int result = 0;
int sign = 1;
int i = 0;
if (count == 0) {
throw new NumberFormatException();
}
while (i < count - 1 && (value[i] <= ' ')) {
i++;
}
if (value[i] == '-' && i < count - 1) {
sign = -1;
i++;
}
do {
byte b = value[i];
if (b >= '0' || b <= '9') {
result = (result * 10) + (b - '0');
} else {
throw new NumberFormatException();
}
i++;
} while (i < count && value[i] > ' ');
while (i < count && value[i] < ' ') {
i++;
}
if (i < count) {
throw new NumberFormatException();
}
return result * sign;
}
public ByteBuf trim() {
int i=0;
while (i < count && value[i] <= ' ') i++;
if (i > 0) {
count -= i;
System.arraycopy(value, i, value, 0, count);
}
while (count > 0 && value[count-1] <= ' ') count--;
return this;
}
/** Write to the given output stream a detailed description of each
byte in this buffer. */
public void fullDump(PrintStream out) {
fullDump(out, 0, count);
}
/** Write to the given output stream a detailed description of the given
bytes in this buffer. */
public void fullDump(PrintStream out, int start, int end) {
for (int i=start ; i<end ; i++) {
out.write(value[i]);
out.print("(" + ((int) value[i]) + ") ");
}
out.println("");
}
/** Invokes InputStream.read(), appending the bytes to this Bytebuf.
@return the number of bytes read, or -1 if eof.
*/
public int read(InputStream file, int max_bytes)
throws IOException {
ensureCapacity(count + max_bytes);
int i = file.read(value, count, max_bytes);
if (i > 0) count += i;
return i;
}
/** Invokes RandomAccessFile.read(), appending the bytes to this Bytebuf.
(A RandomAccessFile is not an InputStream, because Java is a crock.)
@return the number of bytes read, or -1 if eof.
*/
public int read(RandomAccessFile file, int max_bytes)
throws IOException {
ensureCapacity(count + max_bytes);
int i = file.read(value, count, max_bytes);
if (i > 0) count += i;
return i;
}
/** Writes the contents to the given output stream. */
public void write(OutputStream out) throws IOException {
out.write(value, 0, count);
}
/** Writes the contents to the given RandomAccessFile. */
public void write(RandomAccessFile out) throws IOException {
out.write(value, 0, count);
}
/** Creates a new InputStream whose content is this ByteBuf. Note that
changing the ByteBuf can affect the stream; the data is <i>not</i>
copied. */
public InputStream makeInputStream() {
return new ByteArrayInputStream(value, 0, count);
}
}