001    /*
002     * To change this template, choose Tools | Templates
003     * and open the template in the editor.
004     */
005    
006    package com.kitfox.svg.xml;
007    
008    import java.io.FilterInputStream;
009    import java.io.IOException;
010    import java.io.InputStream;
011    
012    /**
013     *
014     * @author kitfox
015     */
016    public class Base64InputStream extends FilterInputStream
017    {
018        int buf;  //Cached bytes to read
019        int bufSize;  //Number of bytes waiting to be read from buffer
020        boolean drain = false;  //After set, read no more chunks
021        
022        public Base64InputStream(InputStream in)
023        {
024            super(in);
025        }
026    
027        public int read() throws IOException
028        {
029            if (drain && bufSize == 0)
030            {
031                return -1;
032            }
033            
034            if (bufSize == 0)
035            {
036                //Read next chunk into 4 byte buffer
037                int chunk = in.read();
038                if (chunk == -1)
039                {
040                    drain = true;
041                    return -1;
042                }
043                
044                //get remaining 3 bytes
045                for (int i = 0; i < 3; ++i)
046                {
047                    int value = in.read();
048                    if (value == -1)
049                    {
050                        throw new IOException("Early termination of base64 stream");
051                    }
052                    chunk = (chunk << 8) | (value & 0xff);
053                }
054    
055                //Check for special termination characters
056                if ((chunk & 0xffff) == (((byte)'=' << 8) | (byte)'='))
057                {
058                    bufSize = 1;
059                    drain = true;
060                }
061                else if ((chunk & 0xff) == (byte)'=')
062                {
063                    bufSize = 2;
064                    drain = true;
065                }
066                else
067                {
068                    bufSize = 3;
069                }
070                
071                //Fill buffer with decoded characters
072                for (int i = 0; i < bufSize + 1; ++i)
073                {
074                    buf = (buf << 6) | Base64Util.decodeByte((chunk >> 24) & 0xff);
075                    chunk <<= 8;
076                }
077            }
078            
079            //Return nth remaing bte & decrement counter
080            return (buf >> (--bufSize * 8)) & 0xff;
081        } 
082    }