* Resolved issue: NETTY-269 (Add ChannelBuffers.copiedBuffer() that accepts char[], CharBuffer, and CharSequence)

* Rewrote toString() and copiedBuffer() implementation
* Removed unnecessary methods in CharsetUtil
This commit is contained in:
Trustin Lee 2009-12-29 07:24:24 +00:00
parent 33766a1f4f
commit 7036654647
5 changed files with 243 additions and 76 deletions

View File

@ -18,14 +18,18 @@ package org.jboss.netty.buffer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import org.jboss.netty.util.CharsetUtil;
/** /**
* A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link ChannelBuffers#directBuffer(int)} * A NIO {@link ByteBuffer} based buffer. It is recommended to use {@link ChannelBuffers#directBuffer(int)}
@ -302,23 +306,31 @@ public class ByteBufferBackedChannelBuffer extends AbstractChannelBuffer {
} }
public String toString(int index, int length, Charset charset) { public String toString(int index, int length, Charset charset) {
if (!buffer.isReadOnly() && buffer.hasArray()) { if (length == 0) {
try { return "";
return new String(
buffer.array(), index + buffer.arrayOffset(), length,
charset.name());
} catch (UnsupportedEncodingException e) {
throw new UnsupportedCharsetException(charset.name());
}
} else {
byte[] tmp = new byte[length];
((ByteBuffer) buffer.duplicate().position(index)).get(tmp);
try {
return new String(tmp, charset.name());
} catch (UnsupportedEncodingException e) {
throw new UnsupportedCharsetException(charset.name());
}
} }
final CharsetDecoder decoder = CharsetUtil.getDecoder(charset);
final ByteBuffer src =
((ByteBuffer) buffer.duplicate().position(
index).limit(index + length)).order(order());
final CharBuffer dst = CharBuffer.allocate(
(int) ((double) length * decoder.maxCharsPerByte()));
try {
CoderResult cr = decoder.decode(src, dst, true);
if (!cr.isUnderflow()) {
cr.throwException();
}
cr = decoder.flush(dst);
if (!cr.isUnderflow()) {
cr.throwException();
}
} catch (CharacterCodingException x) {
throw new IllegalStateException(x);
}
dst.flip();
return dst.toString();
} }
public ChannelBuffer slice(int index, int length) { public ChannelBuffer slice(int index, int length) {

View File

@ -15,14 +15,18 @@
*/ */
package org.jboss.netty.buffer; package org.jboss.netty.buffer;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.jboss.netty.util.CharsetUtil;
/** /**
* Creates a new {@link ChannelBuffer} by allocating new space or by wrapping * Creates a new {@link ChannelBuffer} by allocating new space or by wrapping
@ -660,16 +664,159 @@ public class ChannelBuffers {
/** /**
* Creates a new big-endian buffer whose content is the specified * Creates a new big-endian buffer whose content is the specified
* {@code string} encoded by the specified {@code charsetName}. * {@code string} encoded in the specified {@code charset}.
* The new buffer's {@code readerIndex} and {@code writerIndex} are * The new buffer's {@code readerIndex} and {@code writerIndex} are
* {@code 0} and the length of the encoded string respectively. * {@code 0} and the length of the encoded string respectively.
*/ */
public static ChannelBuffer copiedBuffer(String string, Charset charset) { public static ChannelBuffer copiedBuffer(CharSequence string, Charset charset) {
return copiedBuffer(BIG_ENDIAN, string, charset); return copiedBuffer(BIG_ENDIAN, string, 0, string.length(), charset);
} }
/** /**
* @deprecated Use {@link #copiedBuffer(String, Charset)} instead. * Creates a new big-endian buffer whose content is a subregion of
* the specified {@code string} encoded in the specified {@code charset}.
* The new buffer's {@code readerIndex} and {@code writerIndex} are
* {@code 0} and the length of the encoded string respectively.
*/
public static ChannelBuffer copiedBuffer(
CharSequence string, int offset, int length, Charset charset) {
return copiedBuffer(BIG_ENDIAN, string, offset, length, charset);
}
/**
* Creates a new buffer with the specified {@code endianness} whose
* content is the specified {@code string} encoded in the specified
* {@code charset}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(ByteOrder endianness, CharSequence string, Charset charset) {
return copiedBuffer(endianness, string, 0, string.length(), charset);
}
/**
* Creates a new buffer with the specified {@code endianness} whose
* content is a subregion of the specified {@code string} encoded in the
* specified {@code charset}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(
ByteOrder endianness, CharSequence string, int offset, int length, Charset charset) {
if (string == null) {
throw new NullPointerException("string");
}
if (length == 0) {
return EMPTY_BUFFER;
}
return copiedBuffer(
endianness, CharBuffer.wrap(string, offset, offset + length),
charset);
}
/**
* Creates a new big-endian buffer whose content is the specified
* {@code array} encoded in the specified {@code charset}.
* The new buffer's {@code readerIndex} and {@code writerIndex} are
* {@code 0} and the length of the encoded string respectively.
*/
public static ChannelBuffer copiedBuffer(char[] array, Charset charset) {
return copiedBuffer(BIG_ENDIAN, array, 0, array.length, charset);
}
/**
* Creates a new big-endian buffer whose content is a subregion of
* the specified {@code array} encoded in the specified {@code charset}.
* The new buffer's {@code readerIndex} and {@code writerIndex} are
* {@code 0} and the length of the encoded string respectively.
*/
public static ChannelBuffer copiedBuffer(
char[] array, int offset, int length, Charset charset) {
return copiedBuffer(BIG_ENDIAN, array, offset, length, charset);
}
/**
* Creates a new buffer with the specified {@code endianness} whose
* content is the specified {@code array} encoded in the specified
* {@code charset}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(ByteOrder endianness, char[] array, Charset charset) {
return copiedBuffer(endianness, array, 0, array.length, charset);
}
/**
* Creates a new buffer with the specified {@code endianness} whose
* content is a subregion of the specified {@code array} encoded in the
* specified {@code charset}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(
ByteOrder endianness, char[] array, int offset, int length, Charset charset) {
if (array == null) {
throw new NullPointerException("array");
}
if (length == 0) {
return EMPTY_BUFFER;
}
return copiedBuffer(
endianness, CharBuffer.wrap(array, offset, length), charset);
}
/**
* Creates a new big-endian buffer whose content is the specified NIO
* {@code buffer} encoded in the specified {@code charset}.
* The new buffer's {@code readerIndex} and {@code writerIndex} are
* {@code 0} and the length of the encoded string respectively.
*/
public static ChannelBuffer copiedBuffer(CharBuffer buffer, Charset charset) {
return copiedBuffer(BIG_ENDIAN, buffer, charset);
}
/**
* Creates a new buffer with the specified {@code endianness} whose
* content is the specified {@code string} encoded in the specified
* NIO {@code buffer}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(ByteOrder endianness, CharBuffer buffer, Charset charset) {
if (endianness == null) {
throw new NullPointerException("endianness");
}
if (buffer == null) {
throw new NullPointerException("buffer");
}
if (!buffer.hasRemaining()) {
return EMPTY_BUFFER;
}
CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
CharBuffer src = buffer;
ByteBuffer dst = ByteBuffer.allocate(
(int) ((double) buffer.remaining() * encoder.maxBytesPerChar()));
try {
CoderResult cr = encoder.encode(src, dst, true);
if (!cr.isUnderflow()) {
cr.throwException();
}
cr = encoder.flush(dst);
if (!cr.isUnderflow()) {
cr.throwException();
}
} catch (CharacterCodingException x) {
throw new IllegalStateException(x);
}
ChannelBuffer result = wrappedBuffer(endianness, dst.array());
result.writerIndex(dst.position());
return result;
}
/**
* @deprecated Use {@link #copiedBuffer(CharSequence, Charset)} instead.
*/ */
@Deprecated @Deprecated
public static ChannelBuffer copiedBuffer(String string, String charsetName) { public static ChannelBuffer copiedBuffer(String string, String charsetName) {
@ -677,22 +824,7 @@ public class ChannelBuffers {
} }
/** /**
* Creates a new buffer with the specified {@code endianness} whose * @deprecated Use {@link #copiedBuffer(ByteOrder, CharSequence, Charset)} instead.
* content is the specified {@code string} encoded by the specified
* {@code charsetName}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0} and the length of the encoded string
* respectively.
*/
public static ChannelBuffer copiedBuffer(ByteOrder endianness, String string, Charset charset) {
try {
return wrappedBuffer(endianness, string.getBytes(charset.name()));
} catch (UnsupportedEncodingException e) {
throw new UnsupportedCharsetException(charset.name());
}
}
/**
* @deprecated Use {@link #copiedBuffer(ByteOrder, String, Charset)} instead.
*/ */
@Deprecated @Deprecated
public static ChannelBuffer copiedBuffer(ByteOrder endianness, String string, String charsetName) { public static ChannelBuffer copiedBuffer(ByteOrder endianness, String string, String charsetName) {

View File

@ -18,17 +18,21 @@ package org.jboss.netty.buffer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.jboss.netty.util.CharsetUtil;
/** /**
* A virtual buffer which shows multiple buffers as a single merged buffer. It * A virtual buffer which shows multiple buffers as a single merged buffer. It
@ -595,26 +599,45 @@ public class CompositeChannelBuffer extends AbstractChannelBuffer {
index - indices[componentId], length, charset); index - indices[componentId], length, charset);
} }
if (length == 0) {
return "";
}
byte[] data = new byte[length]; byte[] data = new byte[length];
int dataIndex = 0; int dataIndex = 0;
int i = componentId; int i = componentId;
while (length > 0) { int remaining = length;
while (remaining > 0) {
ChannelBuffer s = components[i]; ChannelBuffer s = components[i];
int adjustment = indices[i]; int adjustment = indices[i];
int localLength = Math.min(length, s.capacity() - (index - adjustment)); int localLength = Math.min(remaining, s.capacity() - (index - adjustment));
s.getBytes(index - adjustment, data, dataIndex, localLength); s.getBytes(index - adjustment, data, dataIndex, localLength);
index += localLength; index += localLength;
dataIndex += localLength; dataIndex += localLength;
length -= localLength; remaining -= localLength;
i ++; i ++;
} }
final CharsetDecoder decoder = CharsetUtil.getDecoder(charset);
final ByteBuffer src = ByteBuffer.wrap(data);
final CharBuffer dst = CharBuffer.allocate(
(int) ((double) length * decoder.maxCharsPerByte()));
try { try {
return new String(data, charset.name()); CoderResult cr = decoder.decode(src, dst, true);
} catch (UnsupportedEncodingException e) { if (!cr.isUnderflow()) {
throw new UnsupportedCharsetException(charset.name()); cr.throwException();
}
cr = decoder.flush(dst);
if (!cr.isUnderflow()) {
cr.throwException();
}
} catch (CharacterCodingException x) {
throw new IllegalStateException(x);
} }
dst.flip();
return dst.toString();
} }
private int componentId(int index) { private int componentId(int index) {

View File

@ -18,13 +18,17 @@ package org.jboss.netty.buffer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
import java.nio.channels.GatheringByteChannel; import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import org.jboss.netty.util.CharsetUtil;
/** /**
* A skeletal implementation for Java heap buffers. * A skeletal implementation for Java heap buffers.
@ -208,10 +212,28 @@ public abstract class HeapChannelBuffer extends AbstractChannelBuffer {
} }
public String toString(int index, int length, Charset charset) { public String toString(int index, int length, Charset charset) {
try { if (length == 0) {
return new String(array, index, length, charset.name()); return "";
} catch (UnsupportedEncodingException e) {
throw new UnsupportedCharsetException(charset.name());
} }
final CharsetDecoder decoder = CharsetUtil.getDecoder(charset);
final ByteBuffer src = ByteBuffer.wrap(array, index, length);
final CharBuffer dst = CharBuffer.allocate(
(int) ((double) length * decoder.maxCharsPerByte()));
try {
CoderResult cr = decoder.decode(src, dst, true);
if (!cr.isUnderflow()) {
cr.throwException();
}
cr = decoder.flush(dst);
if (!cr.isUnderflow()) {
cr.throwException();
}
} catch (CharacterCodingException x) {
throw new IllegalStateException(x);
}
dst.flip();
return dst.toString();
} }
} }

View File

@ -80,17 +80,6 @@ public class CharsetUtil {
} }
}; };
/**
* Returns a cached thread-local {@link CharsetEncoder} for the specified
* <tt>charset</tt>.
*/
public static CharsetEncoder getEncoder(String charset) {
if (charset == null) {
throw new NullPointerException("charset");
}
return getEncoder(Charset.forName(charset));
}
/** /**
* Returns a cached thread-local {@link CharsetEncoder} for the specified * Returns a cached thread-local {@link CharsetEncoder} for the specified
* <tt>charset</tt>. * <tt>charset</tt>.
@ -116,17 +105,6 @@ public class CharsetUtil {
return e; return e;
} }
/**
* Returns a cached thread-local {@link CharsetDecoder} for the specified
* <tt>charset</tt>.
*/
public static CharsetDecoder getDecoder(String charset) {
if (charset == null) {
throw new NullPointerException("charset");
}
return getDecoder(Charset.forName(charset));
}
/** /**
* Returns a cached thread-local {@link CharsetDecoder} for the specified * Returns a cached thread-local {@link CharsetDecoder} for the specified
* <tt>charset</tt>. * <tt>charset</tt>.