001    /**
002     * Copyright (c) 2000-2013 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            @Override
035            public int available() throws IOException {
036                    return ((_inputStream.available() * 3) / 4) + _avaiableBytes;
037            }
038    
039            @Override
040            public int read() throws IOException {
041                    if (_avaiableBytes == 0) {
042                            _avaiableBytes = decodeUnit(_unitBuffer, 0);
043    
044                            if (_avaiableBytes <= 0) {
045                                    return -1;
046                            }
047    
048                            _unitBufferIndex = 0;
049                    }
050    
051                    _avaiableBytes--;
052    
053                    return _unitBuffer[_unitBufferIndex++] & 0xff;
054            }
055    
056            @Override
057            public int read(byte[] bytes, int offset, int length) throws IOException {
058                    if ((length <= 0) || (offset < 0)) {
059                            return -1;
060                    }
061    
062                    int initialLength = length;
063    
064                    while ((_avaiableBytes > 0) && (length > 0)) {
065                            bytes[offset++] = _unitBuffer[_unitBufferIndex++];
066    
067                            _avaiableBytes--;
068                            length--;
069                    }
070    
071                    int bytesLength = length - (length % 3);
072    
073                    while (bytesLength > 0) {
074                            int returnValue = decodeUnit(bytes, offset);
075    
076                            if (returnValue > 0) {
077                                    offset += returnValue;
078                                    length -= returnValue;
079                            }
080    
081                            if (returnValue < 3) {
082                                    if (initialLength == length) {
083                                            return -1;
084                                    }
085    
086                                    return initialLength - length;
087                            }
088    
089                            bytesLength -= 3;
090                    }
091    
092                    while (length > 0) {
093                            int intValue = read();
094    
095                            if (intValue == -1) {
096                                    break;
097                            }
098    
099                            bytes[offset++] = (byte)intValue;
100    
101                            length--;
102                    }
103    
104                    if (initialLength == length) {
105                            return -1;
106                    }
107    
108                    return initialLength - length;
109            }
110    
111            @Override
112            public long skip(long skip) throws IOException {
113                    long initialSkip = skip;
114    
115                    while (skip > 0) {
116                            if (read() <= 0) {
117                                    break;
118                            }
119    
120                            skip--;
121                    }
122    
123                    return initialSkip - skip;
124            }
125    
126            protected int decode(
127                    byte[] bytes, byte[] outputBuffer, int position, int padNumber) {
128    
129                    int intValue = 0;
130    
131                    for (int next = 0; next < 4; next++) {
132                            intValue <<= 6;
133                            intValue |= bytes[next];
134                    }
135    
136                    if (padNumber == 2) {
137                            intValue >>= 16;
138    
139                            outputBuffer[position] = (byte)(intValue & 0xff);
140    
141                            return 1;
142                    }
143                    else if (padNumber == 1) {
144                            intValue >>= 8;
145    
146                            outputBuffer[position + 1] = (byte)(intValue & 0xff);
147    
148                            intValue >>= 8;
149    
150                            outputBuffer[position] = (byte)(intValue & 0xff);
151    
152                            return 2;
153                    }
154                    else if (padNumber == 0) {
155                            outputBuffer[position + 2] = (byte)(intValue & 0xff);
156    
157                            intValue >>= 8;
158    
159                            outputBuffer[position + 1] = (byte)(intValue & 0xff);
160    
161                            intValue >>= 8;
162    
163                            outputBuffer[position] = (byte)(intValue & 0xff);
164    
165                            return 3;
166                    }
167                    else {
168                            return -1;
169                    }
170            }
171    
172            protected int decodeUnit(byte[] outputBuffer, int position)
173                    throws IOException {
174    
175                    int intValue = -1;
176                    int padNumber = 0;
177                    int count = 0;
178                    byte[] decodeUnitBuffer = new byte[4];
179    
180                    while (count < 4) {
181                            intValue = getEncodedByte();
182    
183                            if (intValue == -1) {
184                                    return -1;
185                            }
186    
187                            if (intValue == -2) {
188                                    if (count < 2) {
189                                            return -1;
190                                    }
191    
192                                    padNumber++;
193                                    count++;
194    
195                                    while (count < 4) {
196                                            intValue = getEncodedByte();
197    
198                                            if (intValue != -2) {
199                                                    return -1;
200                                            }
201    
202                                            padNumber++;
203                                            count++;
204                                    }
205    
206                                    int returnValue = decode(
207                                            decodeUnitBuffer, outputBuffer, position, padNumber);
208    
209                                    return returnValue;
210                            }
211    
212                            decodeUnitBuffer[count++] = (byte)intValue;
213                    }
214    
215                    return decode(decodeUnitBuffer, outputBuffer, position, padNumber);
216            }
217    
218            protected int getByte(char character) {
219                    if ((character >= CharPool.UPPER_CASE_A) &&
220                            (character <= CharPool.UPPER_CASE_Z)) {
221    
222                            return character - 65;
223                    }
224    
225                    if ((character >= CharPool.LOWER_CASE_A) &&
226                            (character <= CharPool.LOWER_CASE_Z)) {
227    
228                            return (character - 97) + 26;
229                    }
230    
231                    if ((character >= CharPool.NUMBER_0) &&
232                            (character <= CharPool.NUMBER_9)) {
233    
234                            return (character - 48) + 52;
235                    }
236    
237                    if (character == CharPool.PLUS) {
238                            return 62;
239                    }
240    
241                    if (character == CharPool.SLASH) {
242                            return 63;
243                    }
244    
245                    if (character != CharPool.EQUAL) {
246                            return -1;
247                    }
248                    else {
249                            return 0;
250                    }
251            }
252    
253            protected int getEncodedByte() throws IOException {
254                    while (true) {
255                            int returnValue = _inputStream.read();
256    
257                            if (returnValue == -1) {
258                                    return -1;
259                            }
260    
261                            char character = (char)(returnValue & 0xff);
262    
263                            if (character == CharPool.EQUAL) {
264                                    return -2;
265                            }
266    
267                            int byteValue = getByte(character);
268    
269                            if (byteValue == -1) {
270                                    continue;
271                            }
272    
273                            return byteValue;
274                    }
275            }
276    
277            private int _avaiableBytes;
278            private InputStream _inputStream;
279            private byte[] _unitBuffer;
280            private int _unitBufferIndex;
281    
282    }