001package net.gdface.utils;
002
003import java.io.IOException;
004import java.io.OutputStream;
005import java.io.Writer;
006
007/**
008 * copy from org.apache.axiom.util.base64.Base64Utils(axiom-api-1.2.13.jar)
009 *
010 */
011public class Base64Utils {
012    private static final char[] S_BASE64CHAR = { 'A', 'B', 'C', 'D', 'E', 'F',
013        'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
014        'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
015        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
016        't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
017        '6', '7', '8', '9', '+', '/' };
018
019    private static final char S_BASE64PAD = '=';
020    
021    private static final byte[] S_DECODETABLE = new byte[128];
022    
023    static {
024        for (int i = 0; i < S_DECODETABLE.length; i++)
025            S_DECODETABLE[i] = Byte.MAX_VALUE; // 127
026        for (int i = 0; i < S_BASE64CHAR.length; i++)
027            // 0 to 63
028            S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;
029    }
030    
031    private static int decode0(char[] ibuf, byte[] obuf, int wp) {
032        int outlen = 3;
033        if (ibuf[3] == S_BASE64PAD)
034            outlen = 2;
035        if (ibuf[2] == S_BASE64PAD)
036            outlen = 1;
037        int b0 = S_DECODETABLE[ibuf[0]];
038        int b1 = S_DECODETABLE[ibuf[1]];
039        int b2 = S_DECODETABLE[ibuf[2]];
040        int b3 = S_DECODETABLE[ibuf[3]];
041        switch (outlen) {
042            case 1:
043                obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
044                return 1;
045            case 2:
046                obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
047                obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
048                return 2;
049            case 3:
050                obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
051                obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
052                obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
053                return 3;
054            default:
055                throw new RuntimeException("internalError00");
056        }
057    }
058
059    /**
060     *
061     */
062    public static byte[] decode(char[] data, int off, int len) {
063        char[] ibuf = new char[4];
064        int ibufcount = 0;
065        byte[] obuf = new byte[len / 4 * 3 + 3];
066        int obufcount = 0;
067        for (int i = off; i < off + len; i++) {
068            char ch = data[i];
069            if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
070                    && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
071                ibuf[ibufcount++] = ch;
072                if (ibufcount == ibuf.length) {
073                    ibufcount = 0;
074                    obufcount += decode0(ibuf, obuf, obufcount);
075                }
076            }
077        }
078        if (obufcount == obuf.length)
079            return obuf;
080        byte[] ret = new byte[obufcount];
081        System.arraycopy(obuf, 0, ret, 0, obufcount);
082        return ret;
083    }
084
085    /**
086     *
087     */
088    public static byte[] decode(String data) {
089        char[] ibuf = new char[4];
090        int ibufcount = 0;
091        byte[] obuf = new byte[data.length() / 4 * 3 + 3];
092        int obufcount = 0;
093        for (int i = 0; i < data.length(); i++) {
094            char ch = data.charAt(i);
095            if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
096                    && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
097                ibuf[ibufcount++] = ch;
098                if (ibufcount == ibuf.length) {
099                    ibufcount = 0;
100                    obufcount += decode0(ibuf, obuf, obufcount);
101                }
102            }
103        }
104        if (obufcount == obuf.length)
105            return obuf;
106        byte[] ret = new byte[obufcount];
107        System.arraycopy(obuf, 0, ret, 0, obufcount);
108        return ret;
109    }
110
111    /**
112     * checks input string for invalid Base64 characters
113     *
114     * @param data
115     * @return true, if String contains only valid Base64 characters. false, otherwise
116     */
117    public static boolean isValidBase64Encoding(String data) {
118        for (int i = 0; i < data.length(); i++) {
119            char ch = data.charAt(i);
120
121            if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
122                    && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
123                //valid character.Do nothing
124            } else if (ch == '\r' || ch == '\n') {
125                //do nothing
126            } else {
127                return false;
128            }
129        }//iterate over all characters in the string
130        return true;
131    }
132
133
134    /**
135     *
136     */
137    public static void decode(char[] data, int off, int len,
138                              OutputStream ostream) throws IOException {
139        char[] ibuf = new char[4];
140        int ibufcount = 0;
141        byte[] obuf = new byte[3];
142        for (int i = off; i < off + len; i++) {
143            char ch = data[i];
144            if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
145                    && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
146                ibuf[ibufcount++] = ch;
147                if (ibufcount == ibuf.length) {
148                    ibufcount = 0;
149                    int obufcount = decode0(ibuf, obuf, 0);
150                    ostream.write(obuf, 0, obufcount);
151                }
152            }
153        }
154    }
155
156    /**
157     *
158     */
159    public static void decode(String data, OutputStream ostream)
160            throws IOException {
161        char[] ibuf = new char[4];
162        int ibufcount = 0;
163        byte[] obuf = new byte[3];
164        for (int i = 0; i < data.length(); i++) {
165            char ch = data.charAt(i);
166            if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
167                    && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
168                ibuf[ibufcount++] = ch;
169                if (ibufcount == ibuf.length) {
170                    ibufcount = 0;
171                    int obufcount = decode0(ibuf, obuf, 0);
172                    ostream.write(obuf, 0, obufcount);
173                }
174            }
175        }
176    }
177
178    /** Returns base64 representation of specified byte array. */
179    public static String encode(byte[] data) {
180        return encode(data, 0, data.length);
181    }
182
183    /** Returns base64 representation of specified byte array. */
184    public static String encode(byte[] data, int off, int len) {
185        if (len <= 0)
186            return "";
187        char[] out = new char[len / 3 * 4 + 4];
188        int rindex = off;
189        int windex = 0;
190        int rest = len - off;
191        while (rest >= 3) {
192            int i = ((data[rindex] & 0xff) << 16)
193                    + ((data[rindex + 1] & 0xff) << 8)
194                    + (data[rindex + 2] & 0xff);
195            out[windex++] = S_BASE64CHAR[i >> 18];
196            out[windex++] = S_BASE64CHAR[(i >> 12) & 0x3f];
197            out[windex++] = S_BASE64CHAR[(i >> 6) & 0x3f];
198            out[windex++] = S_BASE64CHAR[i & 0x3f];
199            rindex += 3;
200            rest -= 3;
201        }
202        if (rest == 1) {
203            int i = data[rindex] & 0xff;
204            out[windex++] = S_BASE64CHAR[i >> 2];
205            out[windex++] = S_BASE64CHAR[(i << 4) & 0x3f];
206            out[windex++] = S_BASE64PAD;
207            out[windex++] = S_BASE64PAD;
208        } else if (rest == 2) {
209            int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
210            out[windex++] = S_BASE64CHAR[i >> 10];
211            out[windex++] = S_BASE64CHAR[(i >> 4) & 0x3f];
212            out[windex++] = S_BASE64CHAR[(i << 2) & 0x3f];
213            out[windex++] = S_BASE64PAD;
214        }
215        return new String(out, 0, windex);
216    }
217
218    /** Outputs base64 representation of the specified byte array to the specified String Buffer */
219    public static void encode(byte[] data, int off, int len, StringBuffer buffer) {
220        if (len <= 0) {
221            return;
222        }
223
224        char[] out = new char[4];
225        int rindex = off;
226        int rest = len - off;
227        while (rest >= 3) {
228            int i = ((data[rindex] & 0xff) << 16)
229                    + ((data[rindex + 1] & 0xff) << 8)
230                    + (data[rindex + 2] & 0xff);
231            out[0] = S_BASE64CHAR[i >> 18];
232            out[1] = S_BASE64CHAR[(i >> 12) & 0x3f];
233            out[2] = S_BASE64CHAR[(i >> 6) & 0x3f];
234            out[3] = S_BASE64CHAR[i & 0x3f];
235            buffer.append(out);
236            rindex += 3;
237            rest -= 3;
238        }
239        if (rest == 1) {
240            int i = data[rindex] & 0xff;
241            out[0] = S_BASE64CHAR[i >> 2];
242            out[1] = S_BASE64CHAR[(i << 4) & 0x3f];
243            out[2] = S_BASE64PAD;
244            out[3] = S_BASE64PAD;
245            buffer.append(out);
246        } else if (rest == 2) {
247            int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
248            out[0] = S_BASE64CHAR[i >> 10];
249            out[1] = S_BASE64CHAR[(i >> 4) & 0x3f];
250            out[2] = S_BASE64CHAR[(i << 2) & 0x3f];
251            out[3] = S_BASE64PAD;
252            buffer.append(out);
253        }
254    }
255
256    /** Outputs base64 representation of the specified byte array to a byte stream. */
257    public static void encode(byte[] data, int off, int len,
258                              OutputStream ostream) throws IOException {
259        if (len <= 0)
260            return;
261        byte[] out = new byte[4];
262        int rindex = off;
263        int rest = len - off;
264        while (rest >= 3) {
265            int i = ((data[rindex] & 0xff) << 16)
266                    + ((data[rindex + 1] & 0xff) << 8)
267                    + (data[rindex + 2] & 0xff);
268            out[0] = (byte) S_BASE64CHAR[i >> 18];
269            out[1] = (byte) S_BASE64CHAR[(i >> 12) & 0x3f];
270            out[2] = (byte) S_BASE64CHAR[(i >> 6) & 0x3f];
271            out[3] = (byte) S_BASE64CHAR[i & 0x3f];
272            ostream.write(out, 0, 4);
273            rindex += 3;
274            rest -= 3;
275        }
276        if (rest == 1) {
277            int i = data[rindex] & 0xff;
278            out[0] = (byte) S_BASE64CHAR[i >> 2];
279            out[1] = (byte) S_BASE64CHAR[(i << 4) & 0x3f];
280            out[2] = (byte) S_BASE64PAD;
281            out[3] = (byte) S_BASE64PAD;
282            ostream.write(out, 0, 4);
283        } else if (rest == 2) {
284            int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
285            out[0] = (byte) S_BASE64CHAR[i >> 10];
286            out[1] = (byte) S_BASE64CHAR[(i >> 4) & 0x3f];
287            out[2] = (byte) S_BASE64CHAR[(i << 2) & 0x3f];
288            out[3] = (byte) S_BASE64PAD;
289            ostream.write(out, 0, 4);
290        }
291    }
292
293    /** Outputs base64 representation of the specified byte array to a character stream. */
294    public static void encode(byte[] data, int off, int len, Writer writer)
295            throws IOException {
296        if (len <= 0)
297            return;
298        char[] out = new char[4];
299        int rindex = off;
300        int rest = len - off;
301        int output = 0;
302        while (rest >= 3) {
303            int i = ((data[rindex] & 0xff) << 16)
304                    + ((data[rindex + 1] & 0xff) << 8)
305                    + (data[rindex + 2] & 0xff);
306            out[0] = S_BASE64CHAR[i >> 18];
307            out[1] = S_BASE64CHAR[(i >> 12) & 0x3f];
308            out[2] = S_BASE64CHAR[(i >> 6) & 0x3f];
309            out[3] = S_BASE64CHAR[i & 0x3f];
310            writer.write(out, 0, 4);
311            rindex += 3;
312            rest -= 3;
313            output += 4;
314            if (output % 76 == 0)
315                writer.write("\n");
316        }
317        if (rest == 1) {
318            int i = data[rindex] & 0xff;
319            out[0] = S_BASE64CHAR[i >> 2];
320            out[1] = S_BASE64CHAR[(i << 4) & 0x3f];
321            out[2] = S_BASE64PAD;
322            out[3] = S_BASE64PAD;
323            writer.write(out, 0, 4);
324        } else if (rest == 2) {
325            int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
326            out[0] = S_BASE64CHAR[i >> 10];
327            out[1] = S_BASE64CHAR[(i >> 4) & 0x3f];
328            out[2] = S_BASE64CHAR[(i << 2) & 0x3f];
329            out[3] = S_BASE64PAD;
330            writer.write(out, 0, 4);
331        }
332    }
333}