FileDocCategorySizeDatePackage
UTF7StyleCharsetEncoder.javaAPI DocAndroid 1.5 API8368Wed May 06 22:42:46 BST 2009com.beetstra.jutf7

UTF7StyleCharsetEncoder

public class UTF7StyleCharsetEncoder extends CharsetEncoder

The CharsetEncoder used to encode both variants of the UTF-7 charset and the modified-UTF-7 charset.

Please note this class does not behave strictly according to the specification in Sun Java VMs before 1.6. This is done to get around a bug in the implementation of {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)}. Unfortunately, that method cannot be overridden.

see
JDK bug 6221056< /a>
author
Jaap Beetstra

Fields Summary
private static final float
AVG_BYTES_PER_CHAR
private static final float
MAX_BYTES_PER_CHAR
private final UTF7StyleCharset
cs
private final Base64Util
base64
private final byte
shift
private final byte
unshift
private final boolean
strict
private boolean
base64mode
private int
bitsToOutput
private int
sextet
static boolean
useUglyHackToForceCallToFlushInJava5
Constructors Summary
UTF7StyleCharsetEncoder(UTF7StyleCharset cs, Base64Util base64, boolean strict)

     
        String version = System.getProperty("java.specification.version");
        String vendor = System.getProperty("java.vm.vendor");
        useUglyHackToForceCallToFlushInJava5 = "1.4".equals(version) || "1.5".equals(version);
        useUglyHackToForceCallToFlushInJava5 &= "Sun Microsystems Inc.".equals(vendor);
    
        super(cs, AVG_BYTES_PER_CHAR, MAX_BYTES_PER_CHAR);
        this.cs = cs;
        this.base64 = base64;
        this.strict = strict;
        this.shift = cs.shift();
        this.unshift = cs.unshift();
    
Methods Summary
private voidencodeBase64(char ch, java.nio.ByteBuffer out)

Writes the bytes necessary to encode a character in base 64 mode. All bytes which are fully determined will be written. The fields bitsToOutput and sextet are used to remember the bytes not yet fully determined.

param
out
param
ch

        if (!base64mode)
            out.put(shift);
        base64mode = true;
        bitsToOutput += 16;
        while (bitsToOutput >= 6) {
            bitsToOutput -= 6;
            sextet += (ch >> bitsToOutput);
            sextet &= 0x3F;
            out.put(base64.getChar(sextet));
            sextet = 0;
        }
        sextet = (ch << (6 - bitsToOutput)) & 0x3F;
    
protected java.nio.charset.CoderResultencodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out)
{@inheritDoc}

Note that this method might return CoderResult.OVERFLOW, even though there is sufficient space available in the output buffer. This is done to force the broken implementation of {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)} to call flush (the buggy method is final, thus cannot be overridden).

However, String.getBytes() fails if CoderResult.OVERFLOW is returned, since this assumes it always allocates sufficient bytes (maxBytesPerChar * nr_of_chars). Thus, as an extra check, the size of the input buffer is compared against the size of the output buffer. A static variable is used to indicate if a broken java version is used.

It is not possible to directly write the last few bytes, since more bytes might be waiting to be encoded then those available in the input buffer.

see
JDK bug 6221056< /a>
param
in The input character buffer
param
out The output byte buffer
return
A coder-result object describing the reason for termination

        while (in.hasRemaining()) {
            if (out.remaining() < 4)
                return CoderResult.OVERFLOW;
            char ch = in.get();
            if (cs.canEncodeDirectly(ch)) {
                unshift(out, ch);
                out.put((byte)ch);
            } else if (!base64mode && ch == shift) {
                out.put(shift);
                out.put(unshift);
            } else
                encodeBase64(ch, out);
        }
        /*
         * <HACK type="ugly"> These lines are required to trick JDK 1.5 and
         * earlier into flushing when using Charset.encode(String),
         * Charset.encode(CharBuffer) or CharsetEncoder.encode(CharBuffer)
         * Without them, the last few bytes may be missing.
         */
        if (base64mode && useUglyHackToForceCallToFlushInJava5
                && out.limit() != MAX_BYTES_PER_CHAR * in.limit())
            return CoderResult.OVERFLOW;
        /* </HACK> */
        return CoderResult.UNDERFLOW;
    
protected java.nio.charset.CoderResultimplFlush(java.nio.ByteBuffer out)
{@inheritDoc}

Note that this method might return CoderResult.OVERFLOW (as is required by the specification) if insufficient space is available in the output buffer. However, calling it again on JDKs before Java 6 triggers a bug in {@link java.nio.charset.CharsetEncoder#flush(ByteBuffer)} causing it to throw an IllegalStateException (the buggy method is final, thus cannot be overridden).

see
JDK bug 6227608< /a>
param
out The output byte buffer
return
A coder-result object describing the reason for termination

        if (base64mode) {
            if (out.remaining() < 2)
                return CoderResult.OVERFLOW;
            if (bitsToOutput != 0)
                out.put(base64.getChar(sextet));
            out.put(unshift);
        }
        return CoderResult.UNDERFLOW;
    
protected voidimplReset()

        base64mode = false;
        sextet = 0;
        bitsToOutput = 0;
    
private voidunshift(java.nio.ByteBuffer out, char ch)

Writes the bytes necessary to leave base 64 mode. This might include an unshift character.

param
out
param
ch

        if (!base64mode)
            return;
        if (bitsToOutput != 0)
            out.put(base64.getChar(sextet));
        if (base64.contains(ch) || ch == unshift || strict)
            out.put(unshift);
        base64mode = false;
        sextet = 0;
        bitsToOutput = 0;