下面列出了java.nio.charset.CoderResult# throwException ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void write(byte[] buffer, int offset, int length) throws IOException {
while (length > 0) {
final int done = Math.min(length, this.input.remaining());
this.input.put(buffer, offset, done);
this.input.flip();
while (true) {
final CoderResult result = this.decoder.decode(
this.input, this.output, false);
if (result.isError())
result.throwException();
this.writer.write(
this.output.array(), 0, this.output.position()
);
this.writer.flush();
this.output.rewind();
if (result.isUnderflow())
break;
}
this.input.compact();
offset += done;
length -= done;
}
}
@Test
public void testGetBytes () throws Exception
{
// simulate what is done in String.getBytes
// (cannot be used directly since Charset is not installed while testing)
final String string = "café";
final CharsetEncoder encoder = tested.newEncoder ();
final ByteBuffer bb = ByteBuffer.allocate ((int) (encoder.maxBytesPerChar () * string.length ()));
final CharBuffer cb = CharBuffer.wrap (string);
encoder.reset ();
CoderResult cr = encoder.encode (cb, bb, true);
if (!cr.isUnderflow ())
cr.throwException ();
cr = encoder.flush (bb);
if (!cr.isUnderflow ())
cr.throwException ();
bb.flip ();
assertEquals ("caf&AOk-", CharsetTestHelper.asString (bb));
}
public static ByteBuffer encodeString(CharBuffer src, Charset charset) {
CharsetEncoder encoder = getEncoder(charset);
ByteBuffer dst =
ByteBuffer.allocate((int) ((double) src.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);
}
dst.flip();
return dst;
}
public static void decode(CharsetDecoder charsetDecoder, ByteBuffer byteBuf, CharBuffer charByte) {
try {
CoderResult cr = charsetDecoder.decode(byteBuf, charByte, true);
if (!cr.isUnderflow()) {
cr.throwException();
}
cr = charsetDecoder.flush(charByte);
if (!cr.isUnderflow()) {
cr.throwException();
}
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new JSONException("utf8 decode error, " + x.getMessage(), x);
}
}
byte[] encode(char[] ca, int off, int len) {
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
char[] decode(byte[] ba, int off, int len) {
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
}
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
/**
* Decode a byte array to a char array using the provided charset. This does
* the same as <code>new String (aByteArray, aCharset)</code> just without the
* intermediate objects.
*
* @param aByteArray
* The byte array to be decoded. May not be <code>null</code>.
* @param nOfs
* Offset into byte array. Must be ≥ 0.
* @param nLen
* Bytes to encode. Must be ≥ 0.
* @param aCharset
* Charset to be used. May not be <code>null</code>.
* @return The created char array. Never <code>null</code>.
* @since 8.6.4
*/
@Nonnull
public static char [] decodeBytesToChars (@Nonnull final byte [] aByteArray,
@Nonnegative final int nOfs,
@Nonnegative final int nLen,
@Nonnull final Charset aCharset)
{
final CharsetDecoder aDecoder = aCharset.newDecoder ();
final int nDecodedLen = (int) (nLen * (double) aDecoder.maxCharsPerByte ());
final char [] aCharArray = new char [nDecodedLen];
if (nLen == 0)
return aCharArray;
aDecoder.onMalformedInput (CodingErrorAction.REPLACE).onUnmappableCharacter (CodingErrorAction.REPLACE).reset ();
final ByteBuffer aSrcBuf = ByteBuffer.wrap (aByteArray, nOfs, nLen);
final CharBuffer aDstBuf = CharBuffer.wrap (aCharArray);
try
{
CoderResult aRes = aDecoder.decode (aSrcBuf, aDstBuf, true);
if (!aRes.isUnderflow ())
aRes.throwException ();
aRes = aDecoder.flush (aDstBuf);
if (!aRes.isUnderflow ())
aRes.throwException ();
}
catch (final CharacterCodingException x)
{
// Substitution is always enabled,
// so this shouldn't happen
throw new IllegalStateException (x);
}
final int nDstLen = aDstBuf.position ();
if (nDstLen == aCharArray.length)
return aCharArray;
return Arrays.copyOf (aCharArray, nDstLen);
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
static byte[] encode(Charset cs, char[] ca, int off, int len) {
CharsetEncoder ce = cs.newEncoder();
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ca = Arrays.copyOfRange(ca, off, off + len);
off = 0;
}
}
ce.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
char[] decode(byte[] ba, int off, int len) {
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
cd.reset();
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
}
}
byte[] encode(char[] ca, int off, int len) {
int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
if (ce instanceof ArrayEncoder) {
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
return safeTrim(ba, blen, cs, isTrusted);
} else {
ce.reset();
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca, off, len);
try {
CoderResult cr = ce.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = ce.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ba, bb.position(), cs, isTrusted);
}
}
static Result decode(Charset cs, byte[] ba, int off, int len) {
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
// de/encode() method. These SD/E objects are short-lived, the young-gen
// gc should be able to take care of them well. But the best approach
// is still not to generate them if not really necessary.
// (2)The defensive copy of the input byte/char[] has a big performance
// impact, as well as the outgoing result byte/char[]. Need to do the
// optimization check of (sm==null && classLoader0==null) for both.
// (3)getClass().getClassLoader0() is expensive
// (4)There might be a timing gap in isTrusted setting. getClassLoader0()
// is only checked (and then isTrusted gets set) when (SM==null). It is
// possible that the SM==null for now but then SM is NOT null later
// when safeTrim() is invoked...the "safe" way to do is to redundant
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
// but it then can be argued that the SM is null when the operation
// is started...
if (cs == UTF_8) {
return StringDecoderUTF8.decode(ba, off, len, new Result());
}
CharsetDecoder cd = cs.newDecoder();
// ascii fastpath
if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) &&
((ArrayDecoder)cd).isASCIICompatible() &&
!hasNegatives(ba, off, len))) {
if (COMPACT_STRINGS) {
return new Result().with(Arrays.copyOfRange(ba, off, off + len),
LATIN1);
} else {
return new Result().with(StringLatin1.inflate(ba, off, len), UTF16);
}
}
int en = scale(len, cd.maxCharsPerByte());
if (len == 0) {
return new Result().with();
}
if (System.getSecurityManager() != null &&
cs.getClass().getClassLoader0() != null) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
cd.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
char[] ca = new char[en];
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return new Result().with(ca, 0, clen);
}
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return new Result().with(ca, 0, cb.position());
}
/**
* Reads a string which has a length field before the actual
* encoded string, using the specified <code>decoder</code> and returns it.
*
* @param prefixLength the length of the length field (1, 2, or 4)
* @param decoder the decoder to use for decoding the string
* @return the prefixed string
* @throws CharacterCodingException when decoding fails
* @throws BufferUnderflowException when there is not enough data available
*/
@Override
public String getPrefixedString(int prefixLength, CharsetDecoder decoder) throws CharacterCodingException {
if (!prefixedDataAvailable(prefixLength)) {
throw new BufferUnderflowException();
}
int fieldSize = 0;
switch (prefixLength) {
case 1:
fieldSize = getUnsigned();
break;
case 2:
fieldSize = getUnsignedShort();
break;
case 4:
fieldSize = getInt();
break;
}
if (fieldSize == 0) {
return "";
}
boolean utf16 = decoder.charset().name().startsWith("UTF-16");
if (utf16 && (fieldSize & 1) != 0) {
throw new IllegalArgumentException("fieldSize is not even for a UTF-16 string.");
}
int oldLimit = limit();
int end = position() + fieldSize;
if (oldLimit < end) {
throw new BufferUnderflowException();
}
limit(end);
decoder.reset();
int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
CharBuffer out = CharBuffer.allocate(expectedLength);
for (;;) {
CoderResult cr;
if (hasRemaining()) {
cr = decoder.decode(buf(), out, true);
} else {
cr = decoder.flush(out);
}
if (cr.isUnderflow()) {
break;
}
if (cr.isOverflow()) {
CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
out.flip();
o.put(out);
out = o;
continue;
}
cr.throwException();
}
limit(oldLimit);
position(end);
return out.flip().toString();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
// Obey InputStream contract.
checkPositionIndexes(off, off + len, b.length);
if (len == 0) {
return 0;
}
// The rest of this method implements the process described by the CharsetEncoder javadoc.
int totalBytesRead = 0;
boolean doneEncoding = endOfInput;
DRAINING:
while (true) {
// We stay in draining mode until there are no bytes left in the output buffer. Then we go
// back to encoding/flushing.
if (draining) {
totalBytesRead += drain(b, off + totalBytesRead, len - totalBytesRead);
if (totalBytesRead == len || doneFlushing) {
return (totalBytesRead > 0) ? totalBytesRead : -1;
}
draining = false;
byteBuffer.clear();
}
while (true) {
// We call encode until there is no more input. The last call to encode will have endOfInput
// == true. Then there is a final call to flush.
CoderResult result;
if (doneFlushing) {
result = CoderResult.UNDERFLOW;
} else if (doneEncoding) {
result = encoder.flush(byteBuffer);
} else {
result = encoder.encode(charBuffer, byteBuffer, endOfInput);
}
if (result.isOverflow()) {
// Not enough room in output buffer--drain it, creating a bigger buffer if necessary.
startDraining(true);
continue DRAINING;
} else if (result.isUnderflow()) {
// If encoder underflows, it means either:
// a) the final flush() succeeded; next drain (then done)
// b) we encoded all of the input; next flush
// c) we ran of out input to encode; next read more input
if (doneEncoding) { // (a)
doneFlushing = true;
startDraining(false);
continue DRAINING;
} else if (endOfInput) { // (b)
doneEncoding = true;
} else { // (c)
readMoreChars();
}
} else if (result.isError()) {
// Only reach here if a CharsetEncoder with non-REPLACE settings is used.
result.throwException();
return 0; // Not called.
}
}
}
}
static char[] decode(Charset cs, byte[] ba, int off, int len) {
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
// de/encode() method. These SD/E objects are short-lifed, the young-gen
// gc should be able to take care of them well. But the best approash
// is still not to generate them if not really necessary.
// (2)The defensive copy of the input byte/char[] has a big performance
// impact, as well as the outgoing result byte/char[]. Need to do the
// optimization check of (sm==null && classLoader0==null) for both.
// (3)getClass().getClassLoader0() is expensive
// (4)There might be a timing gap in isTrusted setting. getClassLoader0()
// is only chcked (and then isTrusted gets set) when (SM==null). It is
// possible that the SM==null for now but then SM is NOT null later
// when safeTrim() is invoked...the "safe" way to do is to redundant
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
// but it then can be argued that the SM is null when the opertaion
// is started...
CharsetDecoder cd = cs.newDecoder();
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
}
cd.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
}
}
static char[] decode(Charset cs, byte[] ba, int off, int len) {
// (1)We never cache the "external" cs, the only benefit of creating
// an additional StringDe/Encoder object to wrap it is to share the
// de/encode() method. These SD/E objects are short-lifed, the young-gen
// gc should be able to take care of them well. But the best approash
// is still not to generate them if not really necessary.
// (2)The defensive copy of the input byte/char[] has a big performance
// impact, as well as the outgoing result byte/char[]. Need to do the
// optimization check of (sm==null && classLoader0==null) for both.
// (3)getClass().getClassLoader0() is expensive
// (4)There might be a timing gap in isTrusted setting. getClassLoader0()
// is only chcked (and then isTrusted gets set) when (SM==null). It is
// possible that the SM==null for now but then SM is NOT null later
// when safeTrim() is invoked...the "safe" way to do is to redundant
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
// but it then can be argued that the SM is null when the opertaion
// is started...
CharsetDecoder cd = cs.newDecoder();
int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
boolean isTrusted = false;
if (System.getSecurityManager() != null) {
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
ba = Arrays.copyOfRange(ba, off, off + len);
off = 0;
}
}
cd.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.reset();
if (cd instanceof ArrayDecoder) {
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
return safeTrim(ca, clen, cs, isTrusted);
} else {
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
CharBuffer cb = CharBuffer.wrap(ca);
try {
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = cd.flush(cb);
if (!cr.isUnderflow())
cr.throwException();
} catch (CharacterCodingException x) {
// Substitution is always enabled,
// so this shouldn't happen
throw new Error(x);
}
return safeTrim(ca, cb.position(), cs, isTrusted);
}
}
/**
* Convert the given characters to bytes.
*
* @param cc char input
* @param bc byte output
*/
public void convert(CharChunk cc, ByteChunk bc)
throws IOException {
if ((bb == null) || (bb.array() != bc.getBuffer())) {
// Create a new byte buffer if anything changed
bb = ByteBuffer.wrap(bc.getBuffer(), bc.getEnd(),
bc.getBuffer().length - bc.getEnd());
} else {
// Initialize the byte buffer
bb.limit(bc.getBuffer().length);
bb.position(bc.getEnd());
}
if ((cb == null) || (cb.array() != cc.getBuffer())) {
// Create a new char buffer if anything changed
cb = CharBuffer.wrap(cc.getBuffer(), cc.getStart(),
cc.getLength());
} else {
// Initialize the char buffer
cb.limit(cc.getEnd());
cb.position(cc.getStart());
}
CoderResult result = null;
// Parse leftover if any are present
if (leftovers.position() > 0) {
int pos = bb.position();
// Loop until one char is encoded or there is a encoder error
do {
leftovers.put((char) cc.substract());
leftovers.flip();
result = encoder.encode(leftovers, bb, false);
leftovers.position(leftovers.limit());
leftovers.limit(leftovers.array().length);
} while (result.isUnderflow() && (bb.position() == pos));
if (result.isError() || result.isMalformed()) {
result.throwException();
}
cb.position(cc.getStart());
leftovers.position(0);
}
// Do the decoding and get the results into the byte chunk and the char
// chunk
result = encoder.encode(cb, bb, false);
if (result.isError() || result.isMalformed()) {
result.throwException();
} else if (result.isOverflow()) {
// Propagate current positions to the byte chunk and char chunk
bc.setEnd(bb.position());
cc.setOffset(cb.position());
} else if (result.isUnderflow()) {
// Propagate current positions to the byte chunk and char chunk
bc.setEnd(bb.position());
cc.setOffset(cb.position());
// Put leftovers in the leftovers char buffer
if (cc.getLength() > 0) {
leftovers.limit(leftovers.array().length);
leftovers.position(cc.getLength());
cc.substract(leftovers.array(), 0, cc.getLength());
}
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
// Obey InputStream contract.
if (len == 0) {
return 0;
}
// The rest of this method implements the process described by the CharsetEncoder javadoc.
int totalBytesRead = 0;
boolean doneEncoding = endOfInput;
DRAINING:
while (true) {
// We stay in draining mode until there are no bytes left in the output buffer. Then we go
// back to encoding/flushing.
if (draining) {
totalBytesRead += drain(b, off + totalBytesRead, len - totalBytesRead);
if (totalBytesRead == len || doneFlushing) {
return (totalBytesRead > 0) ? totalBytesRead : -1;
}
draining = false;
byteBuffer.clear();
}
while (true) {
// We call encode until there is no more input. The last call to encode will have endOfInput
// == true. Then there is a final call to flush.
CoderResult result;
if (doneFlushing) {
result = CoderResult.UNDERFLOW;
} else if (doneEncoding) {
result = encoder.flush(byteBuffer);
} else {
result = encoder.encode(charBuffer, byteBuffer, endOfInput);
}
if (result.isOverflow()) {
// Not enough room in output buffer--drain it, creating a bigger buffer if necessary.
startDraining(true);
continue DRAINING;
} else if (result.isUnderflow()) {
// If encoder underflows, it means either:
// a) the final flush() succeeded; next drain (then done)
// b) we encoded all of the input; next flush
// c) we ran of out input to encode; next read more input
if (doneEncoding) { // (a)
doneFlushing = true;
startDraining(false);
continue DRAINING;
} else if (endOfInput) { // (b)
doneEncoding = true;
} else { // (c)
readMoreChars();
}
} else if (result.isError()) {
// Only reach here if a CharsetEncoder with non-REPLACE settings is used.
result.throwException();
return 0; // Not called.
}
}
}
}