17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/*
27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  Licensed to the Apache Software Foundation (ASF) under one or more
37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  contributor license agreements.  See the NOTICE file distributed with
47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  this work for additional information regarding copyright ownership.
57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  The ASF licenses this file to You under the Apache License, Version 2.0
67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  (the "License"); you may not use this file except in compliance with
77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  the License.  You may obtain a copy of the License at
87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *     http://www.apache.org/licenses/LICENSE-2.0
107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  Unless required by applicable law or agreed to in writing, software
127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  distributed under the License is distributed on an "AS IS" BASIS,
137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  See the License for the specific language governing permissions and
157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *  limitations under the License.
167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/*
197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * NOTE: This class copied from the Android Open Source Project:
207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * dalvik/libcore/luni/src/main/java/org/apache/harmony/luni/util/Base64.java
217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/**
247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet* @author Alexander Y. Kleymenov
257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet* @version $Revision$
267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet*/
277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpackage com.google.polo.wire.json;
297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.io.UnsupportedEncodingException;
317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/**
337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * This class implements Base64 encoding/decoding functionality
347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * as specified in RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt).
357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpublic class Base64 {
377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public static byte[] decode(byte[] in) {
397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return decode(in, in.length);
407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public static byte[] decode(byte[] in, int len) {
437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // approximate output length
447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int length = len / 4 * 3;
457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // return an empty array on emtpy or short input without padding
467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (length == 0) {
477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return new byte[0];
487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // temporary array
507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] out = new byte[length];
517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // number of padding characters ('=')
527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int pad = 0;
537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte chr;
547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // compute the number of the padding characters
557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // and adjust the length of the input
567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (;;len--) {
577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            chr = in[len-1];
587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            // skip the neutral characters
597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if ((chr == '\n') || (chr == '\r') ||
607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                    (chr == ' ') || (chr == '\t')) {
617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                continue;
627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if (chr == '=') {
647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                pad++;
657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else {
667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // index in the output array
707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int out_index = 0;
717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // index in the input array
727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int in_index = 0;
737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // holds the value of the input character
747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int bits = 0;
757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // holds the value of the input quantum
767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int quantum = 0;
777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (int i=0; i<len; i++) {
787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            chr = in[i];
797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            // skip the neutral characters
807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if ((chr == '\n') || (chr == '\r') ||
817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                    (chr == ' ') || (chr == '\t')) {
827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                continue;
837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if ((chr >= 'A') && (chr <= 'Z')) {
857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                // char ASCII value
867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  A    65    0
877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  Z    90    25 (ASCII - 65)
887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                bits = chr - 65;
897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else if ((chr >= 'a') && (chr <= 'z')) {
907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                // char ASCII value
917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  a    97    26
927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  z    122   51 (ASCII - 71)
937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                bits = chr - 71;
947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else if ((chr >= '0') && (chr <= '9')) {
957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                // char ASCII value
967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  0    48    52
977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //  9    57    61 (ASCII + 4)
987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                bits = chr + 4;
997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else if (chr == '+') {
1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                bits = 62;
1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else if (chr == '/') {
1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                bits = 63;
1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            } else {
1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                return null;
1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            // append the value to the quantum
1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            quantum = (quantum << 6) | (byte) bits;
1087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if (in_index%4 == 3) {
1097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                // 4 characters were read, so make the output:
1107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
1117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
1127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[out_index++] = (byte) (quantum & 0x000000FF);
1137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
1147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            in_index++;
1157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (pad > 0) {
1177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            // adjust the quantum value according to the padding
1187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            quantum = quantum << (6*pad);
1197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            // make output
1207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
1217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if (pad == 1) {
1227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
1237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
1247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // create the resulting array
1267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] result = new byte[out_index];
1277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        System.arraycopy(out, 0, result, 0, out_index);
1287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return result;
1297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private static final byte[] map = new byte[]
1327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
1337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet         'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
1347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet         'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
1357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet         'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
1367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet         '4', '5', '6', '7', '8', '9', '+', '/'};
1377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public static String encode(byte[] in, String charsetName) throws UnsupportedEncodingException {
1397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int length = in.length * 4 / 3;
1407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        length += length / 76 + 3; // for crlr
1417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] out = new byte[length];
1427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int index = 0, i, crlr = 0, end = in.length - in.length%3;
1437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (i=0; i<end; i+=3) {
1447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            out[index++] = map[(in[i] & 0xff) >> 2];
1457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            out[index++] = map[((in[i] & 0x03) << 4)
1467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                | ((in[i+1] & 0xff) >> 4)];
1477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            out[index++] = map[((in[i+1] & 0x0f) << 2)
1487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                | ((in[i+2] & 0xff) >> 6)];
1497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            out[index++] = map[(in[i+2] & 0x3f)];
1507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if (((index - crlr)%76 == 0) && (index != 0)) {
1517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = '\n';
1527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                crlr++;
1537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //out[index++] = '\r';
1547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                //crlr++;
1557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
1567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (in.length % 3) {
1587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case 1:
1597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = map[(in[end] & 0xff) >> 2];
1607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = map[(in[end] & 0x03) << 4];
1617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = '=';
1627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = '=';
1637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
1647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case 2:
1657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = map[(in[end] & 0xff) >> 2];
1667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = map[((in[end] & 0x03) << 4)
1677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                                    | ((in[end+1] & 0xff) >> 4)];
1687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = map[((in[end+1] & 0x0f) << 2)];
1697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                out[index++] = '=';
1707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
1717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new String(out, 0, index, charsetName);
1737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
1757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
176