View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.util;
20  
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.Reader;
25  
26  
27  /**
28   * An InputStream that decodes data from base64 representation into a binary
29   * format. 
30   * It takes a Reader as its single argument to its constructor and base64 
31   * characters read in from the Reader are correspondingly made available to be 
32   * read out in the corresponding binary format via the read() method.
33   */
34  public class Base64InputStream extends InputStream
35  {
36    /*
37     * @param in  a character stream of valid base64 characters.  the reader 
38     * should not contain invalid base64 characters (such as newlines).
39     *
40     */
41    public Base64InputStream(Reader in)
42    {
43      _in = in;
44      _byteBufferIndex = Integer.MAX_VALUE;
45      _maxByteBufferIndex = 0;
46      _byteBuffer = new byte[(int)(_QUANTUM_SIZE*0.75)];
47    }
48    
49    
50    
51    /**
52     * Read a single character. 
53     * 
54     * Overrides InputStream.read()
55     * 
56     * @return The byte read, as an integer, 
57     *         or -1 if the end of the stream has been reached 
58     * 
59     */
60    @Override
61    public int read() throws IOException
62    {
63      int result = -1;
64      
65      if ( _byteBufferIndex <= _maxByteBufferIndex ) 
66      {
67        result = _byteBuffer[_byteBufferIndex];
68        result = result & 0xff;
69        _byteBufferIndex++;
70      } 
71      else 
72      {
73        // exhausted our buffer, so fill it up and try again.
74        // Only try to read another byte if byteBuffer has been refilled 
75        // with something new.
76        
77        int b = _fillByteBuffer();
78        if (b>-1) {  
79          return read();  
80        } 
81      }
82      
83      return result;
84    }
85    
86    @Override
87    public void close() throws IOException 
88    {
89      _in.close();
90    }
91  
92    @Override
93    public int available() throws IOException 
94    {
95      return _in.ready() ? 1 : 0;
96    }
97  
98    /**
99     * Reads in _QUANTUM_SIZE number of base64 characters from the reader 
100    * and converts them into bytes and places these bytes into the decodedBuffer
101    * array.
102    * 
103    * Note: This method assumes that the reader contains ONLY valid Base64 
104    * characters.  
105    * 
106    * @return the highest index of the decodedbuffer that this method filled up
107    *  
108    *
109    */
110   private int _fillByteBuffer() throws IOException
111   {
112     //fill encodedBuffer with up to _QUANTUM_SIZE valid base64 chars from reader
113     int numValidCharsRead;
114     char[]  encodedBuffer = new char[ _QUANTUM_SIZE ]; // base64 encoded chars
115     
116     numValidCharsRead = _in.read( encodedBuffer, 0, _QUANTUM_SIZE );
117 
118     // reset the index
119     _byteBufferIndex = -1;
120     
121     char eb1, eb2, eb3, eb4;        
122     char c1, c2, c3, c4;
123     
124     for (int i = 0; i < numValidCharsRead; i += 4) 
125     {   
126       eb1 = encodedBuffer[i];
127       eb2 = encodedBuffer[i+1];
128       eb3 = encodedBuffer[i+2];
129       eb4 = encodedBuffer[i+3];
130          
131       c1 = _decode(eb1);
132       c2 = _decode(eb2);
133       c3 = _decode(eb3);
134       c4 = _decode(eb4);
135       
136       _byteBufferIndex++;
137       _byteBuffer[_byteBufferIndex] = (byte)( (c1<<2) | ((c2>>4)&0x03) );
138       if (eb3 != '=')
139       {
140         _byteBufferIndex++;  
141         _byteBuffer[_byteBufferIndex] = (byte)( (c2<<4) | ((c3>>2)&0x0f) );
142       }
143       if (eb4 != '=')
144       {
145         _byteBufferIndex++;
146         _byteBuffer[_byteBufferIndex] = (byte)( (c3<<6) | (c4&0x3f) );
147       }
148     }
149     
150     // set the maximum index to be the number of bytes written to the buffer
151     _maxByteBufferIndex = _byteBufferIndex;
152     // reset the index so we can walk through the byte buffer
153     _byteBufferIndex = 0;
154     
155     return _maxByteBufferIndex;
156       
157   }
158   
159   
160   /**
161    * Converts a base64 character into its decimal equivalent.
162    * 
163    * @param   c the base64 character as an int
164    * 
165    * @return decoded value of the input base64 character
166    */
167   static private char _decode(int c) 
168   {
169     if (c >= 'A' && c <= 'Z')
170     {
171       return (char)(c - 'A');
172     }
173     else if (c >= 'a' && c <= 'z') 
174     {
175       return (char)(c - 'a' + 26);
176     }
177     else if (c >= '0' && c <= '9') 
178     {
179       return (char)(c - '0' + 52);
180     } 
181     else if (c == '+') 
182     {
183       return 0x3e;
184     } 
185     else if (c == '/')
186     {
187       return 0x3f;
188     }
189     else if (c == '=') 
190     {
191       return '=';
192     } 
193     else 
194     {
195       return 0;
196     }
197   }
198 
199   /** the number of base64 encoded characters to read from reader at a time **/
200   /** this number should be a multiple of 4 **/
201   private static final int _QUANTUM_SIZE = 512;
202   
203   /** input stream of base64 encoded data **/
204   private final Reader  _in;
205   
206   /** an index into the decoded byte buffer **/
207   private int     _byteBufferIndex;
208   
209   /** the number of bytes in the byte buffer **/
210   private int     _maxByteBufferIndex;
211  
212   /** contains decoded bytes  **/
213   private byte[]  _byteBuffer;
214 }