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();
    }
}


Reply via email to