1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.kernel.io;
16  
17  import com.liferay.portal.kernel.util.CharPool;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  
22  /**
23   * <a href="Base64InputStream.java.html"><b><i>View Source</i></b></a>
24   *
25   * @author Tina Tian
26   */
27  public class Base64InputStream extends InputStream {
28  
29      public Base64InputStream(InputStream inputStream) {
30          _inputStream = inputStream;
31          _unitBufferIndex = 0;
32          _avaiableBytes = 0;
33          _unitBuffer = new byte[3];
34      }
35  
36      public int available() throws IOException {
37          return ((_inputStream.available() * 3) / 4) + _avaiableBytes;
38      }
39  
40      public int read() throws IOException {
41          if (_avaiableBytes == 0) {
42              _avaiableBytes = decodeUnit(_unitBuffer, 0);
43  
44              if (_avaiableBytes <= 0) {
45                  return -1;
46              }
47  
48              _unitBufferIndex = 0;
49          }
50  
51          _avaiableBytes--;
52  
53          return _unitBuffer[_unitBufferIndex++] & 0xff;
54      }
55  
56      public int read(byte[] buffer, int offset, int length) throws IOException {
57          if ((length <= 0) || (offset < 0)) {
58              return -1;
59          }
60  
61          int initialLength = length;
62  
63          while ((_avaiableBytes > 0) && (length > 0)) {
64              buffer[offset++] = _unitBuffer[_unitBufferIndex++];
65  
66              _avaiableBytes--;
67              length--;
68          }
69  
70          int bytesLength = length - (length % 3);
71  
72          while (bytesLength > 0) {
73              int returnValue = decodeUnit(buffer, offset);
74  
75              if (returnValue > 0) {
76                  offset += returnValue;
77                  length -= returnValue;
78              }
79  
80              if (returnValue < 3) {
81                  if (initialLength == length) {
82                      return -1;
83                  }
84  
85                  return initialLength - length;
86              }
87  
88              bytesLength -= 3;
89          }
90  
91          while (length > 0) {
92              int intValue = read();
93  
94              if (intValue == -1) {
95                  break;
96              }
97  
98              buffer[offset++] = (byte)intValue;
99  
100             length--;
101         }
102 
103         if (initialLength == length) {
104             return -1;
105         }
106 
107         return initialLength - length;
108     }
109 
110     public long skip(long skip) throws IOException {
111         long initialSkip = skip;
112 
113         while (skip > 0) {
114             if (read() <= 0) {
115                 break;
116             }
117 
118             skip--;
119         }
120 
121         return initialSkip - skip;
122     }
123 
124     protected int decode(
125         byte[] bytes, byte[] outputBuffer, int position, int padNumber) {
126 
127         int intValue = 0;
128 
129         for(int next = 0; next < 4; next++) {
130             intValue <<= 6;
131             intValue |= bytes[next];
132         }
133 
134         if (padNumber == 2) {
135             intValue >>= 16;
136 
137             outputBuffer[position] = (byte)(intValue & 0xff);
138 
139             return 1;
140         }
141         else if (padNumber == 1) {
142             intValue >>= 8;
143 
144             outputBuffer[position + 1] = (byte)(intValue & 0xff);
145 
146             intValue >>= 8;
147 
148             outputBuffer[position] = (byte)(intValue & 0xff);
149 
150             return 2;
151         }
152         else if (padNumber == 0) {
153             outputBuffer[position + 2] = (byte)(intValue & 0xff);
154 
155             intValue >>= 8;
156 
157             outputBuffer[position + 1] = (byte)(intValue & 0xff);
158 
159             intValue >>= 8;
160 
161             outputBuffer[position] = (byte)(intValue & 0xff);
162 
163             return 3;
164         }
165         else {
166             return -1;
167         }
168     }
169 
170     protected int decodeUnit(byte[] outputBuffer, int position)
171         throws IOException {
172 
173         int intValue = -1;
174         int padNumber = 0;
175         int count = 0;
176         byte[] decodeUnitBuffer = new byte[4];
177 
178         while (count < 4) {
179             intValue = getEncodedByte();
180 
181             if (intValue == -1) {
182                 return -1;
183             }
184 
185             if (intValue == -2) {
186                 if (count < 2) {
187                     return -1;
188                 }
189 
190                 padNumber++;
191                 count++;
192 
193                 while (count < 4) {
194                     intValue = getEncodedByte();
195 
196                     if (intValue != -2) {
197                         return -1;
198                     }
199 
200                     padNumber++;
201                     count++;
202                 }
203 
204                 int returnValue = decode(
205                     decodeUnitBuffer, outputBuffer, position, padNumber);
206 
207                 return returnValue;
208             }
209 
210             decodeUnitBuffer[count++] = (byte)intValue;
211         }
212 
213         return decode(decodeUnitBuffer, outputBuffer, position, padNumber);
214     }
215 
216     protected int getByte(char character) {
217         if ((character >= CharPool.UPPER_CASE_A) &&
218             (character <= CharPool.UPPER_CASE_Z)) {
219 
220             return character - 65;
221         }
222 
223         if ((character >= CharPool.LOWER_CASE_A) &&
224             (character <= CharPool.LOWER_CASE_Z)) {
225 
226             return (character - 97) + 26;
227         }
228 
229         if ((character >= CharPool.NUMBER_0) &&
230             (character <= CharPool.NUMBER_9)) {
231 
232             return (character - 48) + 52;
233         }
234 
235         if (character == CharPool.PLUS) {
236             return 62;
237         }
238 
239         if (character == CharPool.SLASH) {
240             return 63;
241         }
242 
243         if (character != CharPool.EQUAL) {
244             return -1;
245         }
246         else {
247             return 0;
248         }
249     }
250 
251     protected int getEncodedByte() throws IOException {
252         while (true) {
253             int returnValue = _inputStream.read();
254 
255             if (returnValue == -1) {
256                 return -1;
257             }
258 
259             char character = (char)(returnValue & 0xff);
260 
261             if (character == CharPool.EQUAL) {
262                 return -2;
263             }
264 
265             int byteValue = getByte(character);
266 
267             if (byteValue == -1) {
268                 continue;
269             }
270 
271             return byteValue;
272         }
273     }
274 
275     private int _avaiableBytes;
276     private InputStream _inputStream;
277     private byte[] _unitBuffer;
278     private int _unitBufferIndex;
279 
280 }