Ulf Zibis wrote:
Hi Sherman,
I see only 1 solution: ByteToCharConverter#flush() should first invoke
decoder.decode(src, dst, true) before decoder.flush(), because there
is no compatible endOfInput-logic in sun.io package.
In this context, I must admit, that I don't understand the necessity
of this endOfInput-logic. It forces an additional invocation of
encodeLoop() even if there is nothing to do in most cases. Why can't
decoder.flush() do this job as in sun.io package???
Attached are the code I wrote back to 2006 when we were struggling
whether or not to remove
the whole sun.io package. This is only a "prototype" for the proposal,
so I did not even test it...
yes, I finally dug it out to see what I dealt with back them:-)
X-code(buffer, buffer, boolean) and flush() have different
role/functionality.
We do have some mapping testing cases for sun.io package, but I've not
yet pushed them to the
"open" area of JDK7.
sherman
package sun.io;
import java.io.*;
import java.nio.charset.*;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import sun.nio.cs.HistoricallyNamedCharset;
public class CharToByteNIOAdaptor extends CharToByteConverter
{
public static CharToByteNIOAdaptor get(String encoding)
throws UnsupportedEncodingException
{
try {
return new CharToByteNIOAdaptor(Charset.forName(encoding));
} catch (Exception x) {
throw new UnsupportedEncodingException(encoding);
}
}
private boolean subMode = true;
private int charOff;
private int byteOff;
private int badInputLength;
private CharsetEncoder enc;
CharToByteNIOAdaptor(Charset cs) {
this.enc = cs.newEncoder()
.onUnmappableCharacter(CodingErrorAction.REPLACE);
}
private CharBuffer emptyCB = CharBuffer.allocate(0);
public int convert(char[] input, int inStart, int inEnd,
byte[] output, int outStart, int outEnd)
throws MalformedInputException,
UnknownCharacterException,
ConversionBufferFullException
{
CharBuffer cb = null;
ByteBuffer bb = null;
CoderResult cr = null;
try {
cb = CharBuffer.wrap(input, inStart, inEnd - inStart);
bb = ByteBuffer.wrap(output, outStart, outEnd - outStart);
cr = enc.encode(cb, bb, false);
} catch (IllegalStateException x) {
enc.reset().encode(cb, bb, false);
} catch (IndexOutOfBoundsException xx) {
return 0; //ex from wraping
}
charOff = cb.position();
byteOff = bb.position();
if (cr.isOverflow()) {
throw new ConversionBufferFullException();
}
if (cr.isMalformed()) {
badInputLength = cr.length();
throw new MalformedInputException();
}
if (cr.isUnmappable()) {
throw new UnknownCharacterException();
}
return byteOff - outStart;
}
public int convertAny(char[] input, int inStart, int inEnd,
byte[] output, int outStart, int outEnd)
throws ConversionBufferFullException
{
if (!subMode) { /* Precondition: subMode == true */
throw new IllegalStateException("Substitution mode is not on");
}
CharBuffer cb = null;
ByteBuffer bb = null;
CoderResult cr = null;
try {
cb = CharBuffer.wrap(input, inStart, inEnd - inStart);
bb = ByteBuffer.wrap(output, outStart, outEnd - outStart);
cr = enc.onMalformedInput(CodingErrorAction.REPLACE)
.encode(cb, bb, false);
} catch (IllegalStateException x){
cr = enc.reset().encode(cb, bb, false);
} catch (IndexOutOfBoundsException xx) {
return 0;
}
enc.onMalformedInput(CodingErrorAction.REPORT);
charOff = cb.position();
byteOff = bb.position();
if (cr.isOverflow()) {
throw new ConversionBufferFullException();
}
return byteOff - outStart;
}
public byte[] convertAll(char input[]) throws MalformedInputException {
ByteBuffer bb = ByteBuffer.allocate(getMaxBytesPerChar()*input.length);
CharBuffer cb = CharBuffer.wrap(input);
CoderResult cr = enc.reset()
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.encode(cb, bb, true);
if (!subMode)
enc.onUnmappableCharacter(CodingErrorAction.REPORT);
byteOff = bb.position();
charOff = cb.position();
if (cr.isMalformed()) {
badInputLength = cr.length();
enc.reset();
throw new MalformedInputException();
}
enc.flush(bb);
enc.reset();
byteOff = bb.position();
byte[] ba = new byte[byteOff];
bb.flip();
bb.get(ba);
return ba;
}
public int flush( byte[] output, int outStart, int outEnd )
throws MalformedInputException, ConversionBufferFullException
{
CoderResult cr = null;
ByteBuffer bb = null;
try {
bb = ByteBuffer.wrap(output, outStart, outEnd - outStart);
cr = enc.encode(emptyCB, bb, true);
if (cr.isOverflow()) {
byteOff = bb.position();
throw new ConversionBufferFullException();
}
if (cr.isMalformed()) {
reset();
throw new MalformedInputException();
}
} catch (IllegalStateException x) {
//a overflowed flush() occurred? so this is the second try
} catch (IndexOutOfBoundsException xx) {
return 0; //ex from wraping
}
cr = enc.flush(bb);
if (cr.isOverflow()) {
byteOff = bb.position();
throw new ConversionBufferFullException();
}
reset();
return bb.position() - outStart;
}
public int flushAny(byte[] output, int outStart, int outEnd)
throws ConversionBufferFullException
{
if (!subMode) { /* Precondition: subMode == true */
throw new IllegalStateException("Substitution mode is not on");
}
ByteBuffer bb = null;
try {
bb = ByteBuffer.wrap(output, outStart, outEnd - outStart);
enc.onMalformedInput(CodingErrorAction.REPLACE);
if (enc.encode(emptyCB, bb, true).isOverflow() ||
enc.flush(bb).isOverflow()) {
enc.onMalformedInput(CodingErrorAction.REPORT);
throw new ConversionBufferFullException();
}
} catch (IllegalStateException x) {
} catch (IndexOutOfBoundsException xx) {
return 0; //ex from wraping
}
reset();
enc.onMalformedInput(CodingErrorAction.REPORT);
return bb.position() - outStart;
}
public void reset() {
charOff = 0;
byteOff = 0;
badInputLength = 0;
enc.reset();
}
public boolean canConvert(char c) {
return enc.canEncode(c);
}
public int getMaxBytesPerChar() {
return (int)enc.maxBytesPerChar();
}
public int getBadInputLength() {
return badInputLength;
}
public int nextCharIndex() {
return charOff;
}
public int nextByteIndex() {
return byteOff;
}
public String getCharacterEncoding() {
if (enc.charset() instanceof HistoricallyNamedCharset)
return ((HistoricallyNamedCharset)enc.charset()).historicalName();
return enc.charset().name();
}
public void setSubstitutionMode(boolean doSub) {
subMode = doSub;
enc.onUnmappableCharacter(doSub?CodingErrorAction.REPLACE
:CodingErrorAction.REPORT);
}
public void setSubstitutionBytes(byte[] newSubBytes)
throws IllegalArgumentException
{
enc.replaceWith(newSubBytes);
}
public String toString() {
return "CharToByteConverter: " + getCharacterEncoding();
}
}