001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.io;
016    
017    import com.liferay.portal.kernel.util.CharPool;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    
022    /**
023     * @author Tina Tian
024     */
025    public class Base64InputStream extends InputStream {
026    
027            public Base64InputStream(InputStream inputStream) {
028                    _inputStream = inputStream;
029                    _unitBufferIndex = 0;
030                    _avaiableBytes = 0;
031                    _unitBuffer = new byte[3];
032            }
033    
034            public int available() throws IOException {
035                    return ((_inputStream.available() * 3) / 4) + _avaiableBytes;
036            }
037    
038            public int read() throws IOException {
039                    if (_avaiableBytes == 0) {
040                            _avaiableBytes = decodeUnit(_unitBuffer, 0);
041    
042                            if (_avaiableBytes <= 0) {
043                                    return -1;
044                            }
045    
046                            _unitBufferIndex = 0;
047                    }
048    
049                    _avaiableBytes--;
050    
051                    return _unitBuffer[_unitBufferIndex++] & 0xff;
052            }
053    
054            public int read(byte[] buffer, int offset, int length) throws IOException {
055                    if ((length <= 0) || (offset < 0)) {
056                            return -1;
057                    }
058    
059                    int initialLength = length;
060    
061                    while ((_avaiableBytes > 0) && (length > 0)) {
062                            buffer[offset++] = _unitBuffer[_unitBufferIndex++];
063    
064                            _avaiableBytes--;
065                            length--;
066                    }
067    
068                    int bytesLength = length - (length % 3);
069    
070                    while (bytesLength > 0) {
071                            int returnValue = decodeUnit(buffer, offset);
072    
073                            if (returnValue > 0) {
074                                    offset += returnValue;
075                                    length -= returnValue;
076                            }
077    
078                            if (returnValue < 3) {
079                                    if (initialLength == length) {
080                                            return -1;
081                                    }
082    
083                                    return initialLength - length;
084                            }
085    
086                            bytesLength -= 3;
087                    }
088    
089                    while (length > 0) {
090                            int intValue = read();
091    
092                            if (intValue == -1) {
093                                    break;
094                            }
095    
096                            buffer[offset++] = (byte)intValue;
097    
098                            length--;
099                    }
100    
101                    if (initialLength == length) {
102                            return -1;
103                    }
104    
105                    return initialLength - length;
106            }
107    
108            public long skip(long skip) throws IOException {
109                    long initialSkip = skip;
110    
111                    while (skip > 0) {
112                            if (read() <= 0) {
113                                    break;
114                            }
115    
116                            skip--;
117                    }
118    
119                    return initialSkip - skip;
120            }
121    
122            protected int decode(
123                    byte[] bytes, byte[] outputBuffer, int position, int padNumber) {
124    
125                    int intValue = 0;
126    
127                    for(int next = 0; next < 4; next++) {
128                            intValue <<= 6;
129                            intValue |= bytes[next];
130                    }
131    
132                    if (padNumber == 2) {
133                            intValue >>= 16;
134    
135                            outputBuffer[position] = (byte)(intValue & 0xff);
136    
137                            return 1;
138                    }
139                    else if (padNumber == 1) {
140                            intValue >>= 8;
141    
142                            outputBuffer[position + 1] = (byte)(intValue & 0xff);
143    
144                            intValue >>= 8;
145    
146                            outputBuffer[position] = (byte)(intValue & 0xff);
147    
148                            return 2;
149                    }
150                    else if (padNumber == 0) {
151                            outputBuffer[position + 2] = (byte)(intValue & 0xff);
152    
153                            intValue >>= 8;
154    
155                            outputBuffer[position + 1] = (byte)(intValue & 0xff);
156    
157                            intValue >>= 8;
158    
159                            outputBuffer[position] = (byte)(intValue & 0xff);
160    
161                            return 3;
162                    }
163                    else {
164                            return -1;
165                    }
166            }
167    
168            protected int decodeUnit(byte[] outputBuffer, int position)
169                    throws IOException {
170    
171                    int intValue = -1;
172                    int padNumber = 0;
173                    int count = 0;
174                    byte[] decodeUnitBuffer = new byte[4];
175    
176                    while (count < 4) {
177                            intValue = getEncodedByte();
178    
179                            if (intValue == -1) {
180                                    return -1;
181                            }
182    
183                            if (intValue == -2) {
184                                    if (count < 2) {
185                                            return -1;
186                                    }
187    
188                                    padNumber++;
189                                    count++;
190    
191                                    while (count < 4) {
192                                            intValue = getEncodedByte();
193    
194                                            if (intValue != -2) {
195                                                    return -1;
196                                            }
197    
198                                            padNumber++;
199                                            count++;
200                                    }
201    
202                                    int returnValue = decode(
203                                            decodeUnitBuffer, outputBuffer, position, padNumber);
204    
205                                    return returnValue;
206                            }
207    
208                            decodeUnitBuffer[count++] = (byte)intValue;
209                    }
210    
211                    return decode(decodeUnitBuffer, outputBuffer, position, padNumber);
212            }
213    
214            protected int getByte(char character) {
215                    if ((character >= CharPool.UPPER_CASE_A) &&
216                            (character <= CharPool.UPPER_CASE_Z)) {
217    
218                            return character - 65;
219                    }
220    
221                    if ((character >= CharPool.LOWER_CASE_A) &&
222                            (character <= CharPool.LOWER_CASE_Z)) {
223    
224                            return (character - 97) + 26;
225                    }
226    
227                    if ((character >= CharPool.NUMBER_0) &&
228                            (character <= CharPool.NUMBER_9)) {
229    
230                            return (character - 48) + 52;
231                    }
232    
233                    if (character == CharPool.PLUS) {
234                            return 62;
235                    }
236    
237                    if (character == CharPool.SLASH) {
238                            return 63;
239                    }
240    
241                    if (character != CharPool.EQUAL) {
242                            return -1;
243                    }
244                    else {
245                            return 0;
246                    }
247            }
248    
249            protected int getEncodedByte() throws IOException {
250                    while (true) {
251                            int returnValue = _inputStream.read();
252    
253                            if (returnValue == -1) {
254                                    return -1;
255                            }
256    
257                            char character = (char)(returnValue & 0xff);
258    
259                            if (character == CharPool.EQUAL) {
260                                    return -2;
261                            }
262    
263                            int byteValue = getByte(character);
264    
265                            if (byteValue == -1) {
266                                    continue;
267                            }
268    
269                            return byteValue;
270                    }
271            }
272    
273            private int _avaiableBytes;
274            private InputStream _inputStream;
275            private byte[] _unitBuffer;
276            private int _unitBufferIndex;
277    
278    }