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.OutputStream;
021    
022    /**
023     * @author Tina Tian
024     */
025    public class Base64OutputStream extends OutputStream {
026    
027            public Base64OutputStream(OutputStream outputStream) {
028                    _outputStream = outputStream;
029                    _unitBuffer = new byte[3];
030                    _unitBufferIndex = 0;
031                    _outputBuffer = new byte[4];
032            }
033    
034            @Override
035            public void close() throws IOException {
036                    flush();
037    
038                    _outputStream.close();
039            }
040    
041            @Override
042            public void flush() throws IOException {
043                    if (_unitBufferIndex == 1) {
044                            encodeUnit(_unitBuffer[0]);
045                    }
046                    else if (_unitBufferIndex == 2) {
047                            encodeUnit(_unitBuffer[0], _unitBuffer[1]);
048                    }
049    
050                    _unitBufferIndex = 0;
051    
052                    _outputStream.flush();
053            }
054    
055            @Override
056            public void write(byte[] bytes) throws IOException {
057                    write(bytes, 0, bytes.length);
058            }
059    
060            @Override
061            public void write(byte[] bytes, int offset, int length) throws IOException {
062                    if (length <= 0) {
063                            return;
064                    }
065    
066                    while ((_unitBufferIndex != 0) && (length > 0)) {
067                            write(bytes[offset++]);
068    
069                            length--;
070                    }
071    
072                    if (length <= 0) {
073                            return;
074                    }
075    
076                    int bytesLength = length - (length % 3);
077    
078                    length -= bytesLength;
079    
080                    while (bytesLength > 0) {
081                            encodeUnit(bytes[offset], bytes[offset + 1], bytes[offset + 2]);
082    
083                            bytesLength -= 3;
084                            offset += 3;
085                    }
086    
087                    while (length > 0) {
088                            write(bytes[offset++]);
089    
090                            length--;
091                    }
092            }
093    
094            @Override
095            public void write(int byteValue) throws IOException {
096                    _unitBuffer[_unitBufferIndex++] = (byte)byteValue;
097    
098                    if (_unitBufferIndex == 3) {
099                            encodeUnit(_unitBuffer[0], _unitBuffer[1], _unitBuffer[2]);
100    
101                            _unitBufferIndex = 0;
102                    }
103            }
104    
105            protected void encodeUnit(byte byteValue) throws IOException {
106                    int intValue = byteValue & 0xff;
107    
108                    intValue <<= 4;
109    
110                    _outputBuffer[3] = (byte)CharPool.EQUAL;
111                    _outputBuffer[2] = (byte)CharPool.EQUAL;
112                    _outputBuffer[1] = (byte)getChar(intValue & 0x3f);
113    
114                    intValue >>= 6;
115    
116                    _outputBuffer[0] = (byte)getChar(intValue & 0x3f);
117    
118                    _outputStream.write(_outputBuffer);
119            }
120    
121            protected void encodeUnit(byte byte1, byte byte2) throws IOException {
122                    int intValue = byte1 & 0xff;
123    
124                    intValue <<= 8;
125                    intValue |= byte2 & 0xff;
126                    intValue <<= 2;
127    
128                    _outputBuffer[3] = (byte)CharPool.EQUAL;
129                    _outputBuffer[2] = (byte)getChar(intValue & 0x3f);
130    
131                    intValue >>= 6;
132    
133                    _outputBuffer[1] = (byte)getChar(intValue & 0x3f);
134    
135                    intValue >>= 6;
136    
137                    _outputBuffer[0] = (byte)getChar(intValue & 0x3f);
138    
139                    _outputStream.write(_outputBuffer);
140            }
141    
142            protected void encodeUnit(byte byte1, byte byte2, byte byte3)
143                    throws IOException {
144    
145                    int intVallue = byte1 & 0xff;
146    
147                    intVallue <<= 8;
148                    intVallue |= byte2 & 0xff;
149                    intVallue <<= 8;
150                    intVallue |= byte3 & 0xff;
151    
152                    _outputBuffer[3] = (byte)getChar(intVallue & 0x3f);
153    
154                    intVallue >>= 6;
155    
156                    _outputBuffer[2] = (byte)getChar(intVallue & 0x3f);
157    
158                    intVallue >>= 6;
159    
160                    _outputBuffer[1] = (byte)getChar(intVallue & 0x3f);
161    
162                    intVallue >>= 6;
163    
164                    _outputBuffer[0] = (byte)getChar(intVallue & 0x3f);
165    
166                    _outputStream.write(_outputBuffer);
167            }
168    
169            protected char getChar(int sixbit) {
170                    if ((sixbit >= 0) && (sixbit <= 25)) {
171                            return (char)(65 + sixbit);
172                    }
173    
174                    if ((sixbit >= 26) && (sixbit <= 51)) {
175                            return (char)(97 + (sixbit - 26));
176                    }
177    
178                    if ((sixbit >= 52) && (sixbit <= 61)) {
179                            return (char)(48 + (sixbit - 52));
180                    }
181    
182                    if (sixbit == 62) {
183                            return CharPool.PLUS;
184                    }
185    
186                    if (sixbit != 63) {
187                            return CharPool.QUESTION;
188                    }
189                    else {
190                            return CharPool.SLASH;
191                    }
192            }
193    
194            private byte[] _outputBuffer;
195            private OutputStream _outputStream;
196            private byte[] _unitBuffer;
197            private int _unitBufferIndex;
198    
199    }