extends CharsetDecoder to create Base64 Decoder : Charset « I18N « Java






extends CharsetDecoder to create Base64 Decoder

   

/*
 * Base64Decoder.java
 *
 * Created on 20 December 2005, 12:14
 *
 */

import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;


/**
 * <p>Base 64 decoder class. Converts byte array to characters.</p>
 * <p>If measure is supplied this is a line width, and \n characters
 * are inserted when it's exceeeded.</p>
 *
 * @author Malcolm McMahon
 * @version $Revision: 1.1 $
 */
public class Base64Decoder extends CharsetDecoder {
    Integer measure;
    int charCount;
    char padding;
    String codeChars;
    char[] excessChars;
    int codeState;
    int bits;
    
    /** 
     * Creates a new instance of Base64Decoder 
     * @param cs The Charset that created this object
     * @param padding The padding character, usually =
     * @param measure The line width in characters
     */
    public Base64Decoder(Charset cs,String codeChars, char padding, int measure)  {
        super(cs, 1.33f, 4f);
        this.measure = measure;
        this.codeChars  = codeChars;
        this.padding = padding;
    }
    
    /**
     * @param cs The Charset that created this object
     * @param padding The padding character, usually =
     */
    
    public Base64Decoder(Charset cs,String codeChars, char padding)  {
        super(cs, 1.33f, 4f);
        this.codeChars  = codeChars;
        this.padding = padding;
    }
    
    private boolean flushExcess(CharBuffer out) {
        if(excessChars == null)
            return true;
        for(int i = 0; i < excessChars.length; i++)
            if(out.remaining() > 0)
                out.put(excessChars[i]);
            else {
            char[] nc = new char[excessChars.length - i];
            System.arraycopy(excessChars, i, nc, 0, nc.length);
            excessChars = nc;
            return false;
            }
        excessChars = null;
        return true;
    }
    /**
     * Output one character. These character output methods
     * park characters in excessChars if the buffer overflows.
     * The also add newlines if the measure calls for it.
     * @return true if space found
     */
    private boolean out(CharBuffer out, char ch) {
        if(measure != null && ++charCount > measure) {
            charCount = -1;
            return out(out, '\n', ch);
        }
        if(out.remaining() > 0) {
            out.put(ch);
            return true;
        } else {
            excessChars = new char[]{ch};
            return false;
        }
    }
    /**
     * Output two characters
     * @return true if space found
     */
    private boolean out(CharBuffer out, char ch1, char ch2) {
        if(measure != null && (charCount += 2) > measure) {
            if(charCount - 1 != measure) {
                charCount = 2;
                return out(out, '\n', ch1, ch2);
            } else {
                charCount = 1;
                return out(out, ch1, '\n', ch2);
            }
        }
        switch(out.remaining()) {
            case 0:
                excessChars = new char[]{ch1, ch2};
                return false;
            case 1:
                out.put(ch1);
                excessChars = new char[]{ch2};
                return false;
            default:
                out.put(ch1);
                out.put(ch2);
                return true;
        }
    }
    
    private boolean out(CharBuffer out, char ch1, char ch2, char ch3) {
        switch(out.remaining()) {
            case 0:
                excessChars = new char[]{ch1, ch2, ch3};
                return false;
            case 1:
                out.put(ch1);
                excessChars = new char[]{ch2, ch3};
                return false;
            case 2:
                out.put(ch1);
                out.put(ch2);
                excessChars = new char[]{ch3};
                return false;
            default:
                out.put(ch1);
                out.put(ch2);
                out.put(ch3);
                return true;
        }
    }
    
    /**
     * Flushes this decoder.
     *
     * <p> The default implementation of this method does nothing, and always
     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
     * by decoders that may need to write final characters to the output buffer
     * once the entire input sequence has been read. </p>
     *
     * @param  out
     *         The output character buffer
     *
     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
     *          {@link CoderResult#OVERFLOW}
     */
    protected java.nio.charset.CoderResult implFlush(CharBuffer out) {
        if(!flushExcess(out))
            return CoderResult.OVERFLOW;
        switch(codeState) {
            case 0:  // full quanta count
                implReset();
                return CoderResult.UNDERFLOW;
            case 1:
                if(!out(out, codeChars.charAt(bits), padding))
                    return CoderResult.OVERFLOW;
                break;
            case 2:
                if(!out(out, codeChars.charAt(bits)))
                    return CoderResult.OVERFLOW;
                break;
                
        }
        if(out(out, padding)) {
            implReset();
            return CoderResult.UNDERFLOW;
        } else
            return CoderResult.OVERFLOW;
        
    }
    
    /**
     * Decodes one or more bytes into one or more characters.
     *
     * <p> This method encapsulates the basic decoding loop, decoding as many
     * bytes as possible until it either runs out of input, runs out of room
     * in the output buffer, or encounters a decoding error.  This method is
     * invoked by the {@link #decode decode} method, which handles result
     * interpretation and error recovery.
     *
     * <p> The buffers are read from, and written to, starting at their current
     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
     * will be read, and at most {@link Buffer#remaining out.remaining()}
     * characters will be written.  The buffers' positions will be advanced to
     * reflect the bytes read and the characters written, but their marks and
     * limits will not be modified.
     *
     * <p> This method returns a {@link CoderResult} object to describe its
     * reason for termination, in the same manner as the {@link #decode decode}
     * method.  Most implementations of this method will handle decoding errors
     * by returning an appropriate result object for interpretation by the
     * {@link #decode decode} method.  An optimized implementation may instead
     * examine the relevant error action and implement that action itself.
     *
     * <p> An implementation of this method may perform arbitrary lookahead by
     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
     * input.  </p>
     *
     * @param  in
     *         The input byte buffer
     *
     * @param  out
     *         The output character buffer
     *
     * @return  A coder-result object describing the reason for termination
     */
    public java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out) {
        if(!flushExcess(out))
            return CoderResult.OVERFLOW;
        while(in.remaining() > 0) {
            int b = in.get() & 0xff;
            switch(codeState) {
                case 0:
                    bits = (b << 4) & 0x30;
                    codeState = 1;
                    if(!out(out, codeChars.charAt((b >> 2) & 0x3f)))
                        return CoderResult.OVERFLOW;
                    break;
                case 1:
                    int cc = bits | (b >> 4) & 0xf;
                    bits = (b << 2) & 0x3c;
                    codeState = 2;
                    if(!out(out, codeChars.charAt(cc)))
                        return CoderResult.OVERFLOW;
                    break;
                case 2:
                    cc = bits | (b >> 6) & 3;
                    codeState = 0;
                    if(!out(out, codeChars.charAt(cc), codeChars.charAt(b & 0x3f)))
                        return CoderResult.OVERFLOW;
            }
        }
        return CoderResult.UNDERFLOW;
    }
    
    /**
     * Resets this decoder, clearing any charset-specific internal state.
     *
     * <p> The default implementation of this method does nothing.  This method
     * should be overridden by decoders that maintain internal state.  </p>
     */
    protected void implReset() {
        bits = 0;
        excessChars = null;
        codeState = 0;
        charCount = 0;
        
    }
    
}

   
    
    
  








Related examples in the same category

1.List the Charset in your system
2.Converting Between Strings (Unicode) and Other Character Set Encodings
3.Charset encoding test
4.encoder and decoder use a supplied ByteBuffer
5.Translate Charset
6.Detect non-ASCII characters in string
7.Displays Charsets and aliasesDisplays Charsets and aliases
8.Encode and DecodeEncode and Decode
9.extends Charset to create Hex Charset
10.Get the default charset
11.Charset Toolkit
12.Defines common charsets supported in all Java platforms.
13.How to auto-detect a file's encoding