001
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
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 }