Home | History | Annotate | Download | only in json
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 /*
     19  * NOTE: This class copied from the Android Open Source Project:
     20  * dalvik/libcore/luni/src/main/java/org/apache/harmony/luni/util/Base64.java
     21  */
     22 
     23 /**
     24 * @author Alexander Y. Kleymenov
     25 * @version $Revision$
     26 */
     27 
     28 package com.google.polo.wire.json;
     29 
     30 import java.io.UnsupportedEncodingException;
     31 
     32 /**
     33  * This class implements Base64 encoding/decoding functionality
     34  * as specified in RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt).
     35  */
     36 public class Base64 {
     37 
     38     public static byte[] decode(byte[] in) {
     39         return decode(in, in.length);
     40     }
     41 
     42     public static byte[] decode(byte[] in, int len) {
     43         // approximate output length
     44         int length = len / 4 * 3;
     45         // return an empty array on emtpy or short input without padding
     46         if (length == 0) {
     47             return new byte[0];
     48         }
     49         // temporary array
     50         byte[] out = new byte[length];
     51         // number of padding characters ('=')
     52         int pad = 0;
     53         byte chr;
     54         // compute the number of the padding characters
     55         // and adjust the length of the input
     56         for (;;len--) {
     57             chr = in[len-1];
     58             // skip the neutral characters
     59             if ((chr == '\n') || (chr == '\r') ||
     60                     (chr == ' ') || (chr == '\t')) {
     61                 continue;
     62             }
     63             if (chr == '=') {
     64                 pad++;
     65             } else {
     66                 break;
     67             }
     68         }
     69         // index in the output array
     70         int out_index = 0;
     71         // index in the input array
     72         int in_index = 0;
     73         // holds the value of the input character
     74         int bits = 0;
     75         // holds the value of the input quantum
     76         int quantum = 0;
     77         for (int i=0; i<len; i++) {
     78             chr = in[i];
     79             // skip the neutral characters
     80             if ((chr == '\n') || (chr == '\r') ||
     81                     (chr == ' ') || (chr == '\t')) {
     82                 continue;
     83             }
     84             if ((chr >= 'A') && (chr <= 'Z')) {
     85                 // char ASCII value
     86                 //  A    65    0
     87                 //  Z    90    25 (ASCII - 65)
     88                 bits = chr - 65;
     89             } else if ((chr >= 'a') && (chr <= 'z')) {
     90                 // char ASCII value
     91                 //  a    97    26
     92                 //  z    122   51 (ASCII - 71)
     93                 bits = chr - 71;
     94             } else if ((chr >= '0') && (chr <= '9')) {
     95                 // char ASCII value
     96                 //  0    48    52
     97                 //  9    57    61 (ASCII + 4)
     98                 bits = chr + 4;
     99             } else if (chr == '+') {
    100                 bits = 62;
    101             } else if (chr == '/') {
    102                 bits = 63;
    103             } else {
    104                 return null;
    105             }
    106             // append the value to the quantum
    107             quantum = (quantum << 6) | (byte) bits;
    108             if (in_index%4 == 3) {
    109                 // 4 characters were read, so make the output:
    110                 out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
    111                 out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
    112                 out[out_index++] = (byte) (quantum & 0x000000FF);
    113             }
    114             in_index++;
    115         }
    116         if (pad > 0) {
    117             // adjust the quantum value according to the padding
    118             quantum = quantum << (6*pad);
    119             // make output
    120             out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
    121             if (pad == 1) {
    122                 out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
    123             }
    124         }
    125         // create the resulting array
    126         byte[] result = new byte[out_index];
    127         System.arraycopy(out, 0, result, 0, out_index);
    128         return result;
    129     }
    130 
    131     private static final byte[] map = new byte[]
    132         {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    133          'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
    134          'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
    135          'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
    136          '4', '5', '6', '7', '8', '9', '+', '/'};
    137 
    138     public static String encode(byte[] in, String charsetName) throws UnsupportedEncodingException {
    139         int length = in.length * 4 / 3;
    140         length += length / 76 + 3; // for crlr
    141         byte[] out = new byte[length];
    142         int index = 0, i, crlr = 0, end = in.length - in.length%3;
    143         for (i=0; i<end; i+=3) {
    144             out[index++] = map[(in[i] & 0xff) >> 2];
    145             out[index++] = map[((in[i] & 0x03) << 4)
    146                                 | ((in[i+1] & 0xff) >> 4)];
    147             out[index++] = map[((in[i+1] & 0x0f) << 2)
    148                                 | ((in[i+2] & 0xff) >> 6)];
    149             out[index++] = map[(in[i+2] & 0x3f)];
    150             if (((index - crlr)%76 == 0) && (index != 0)) {
    151                 out[index++] = '\n';
    152                 crlr++;
    153                 //out[index++] = '\r';
    154                 //crlr++;
    155             }
    156         }
    157         switch (in.length % 3) {
    158             case 1:
    159                 out[index++] = map[(in[end] & 0xff) >> 2];
    160                 out[index++] = map[(in[end] & 0x03) << 4];
    161                 out[index++] = '=';
    162                 out[index++] = '=';
    163                 break;
    164             case 2:
    165                 out[index++] = map[(in[end] & 0xff) >> 2];
    166                 out[index++] = map[((in[end] & 0x03) << 4)
    167                                     | ((in[end+1] & 0xff) >> 4)];
    168                 out[index++] = map[((in[end+1] & 0x0f) << 2)];
    169                 out[index++] = '=';
    170                 break;
    171         }
    172         return new String(out, 0, index, charsetName);
    173     }
    174 }
    175 
    176