OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2002-2013 Sun Microsystems, Inc. All rights reserved |
| 2 * |
| 3 * This program is distributed under the terms of |
| 4 * the GNU General Public License Version 2. See the LICENSE file |
| 5 * at the top of the source tree. |
| 6 */ |
| 7 package org.pantsbuild.jmake; |
| 8 |
| 9 import java.util.Arrays; |
| 10 |
| 11 |
| 12 /** |
| 13 * JMake needs to run against old versions of Java, that may not have JAXB's |
| 14 * javax.xml.bind.DatatypeConverter. And we don't want JMake to depend on third-
party external libraries, |
| 15 * especially not just for this. So we implement a lightweight Base64 converter
here ourselves. |
| 16 |
| 17 * Note that sun.misc.BASE64Encoder is not official API and can go away at any t
ime. Plus it inserts |
| 18 * line breaks into its emitted string, which is not what we want. So we can't u
se that either. |
| 19 */ |
| 20 |
| 21 public class Base64 { |
| 22 // The easiest way to grok this code is to think of Base64 as the following
chain of |
| 23 // conversions (ignoring padding issues): |
| 24 // 3 bytes -> 24 bits -> 4 6-bit nibbles -> 4 indexes from 0-63 -> 4 charact
ers. |
| 25 private static final char[] indexToDigit = |
| 26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCha
rArray(); |
| 27 private static final int[] digitToIndex = new int[128]; |
| 28 static { |
| 29 assert(indexToDigit.length == 64); |
| 30 Arrays.fill(digitToIndex, -1); |
| 31 for (int i = 0; i < indexToDigit.length; i++) digitToIndex[(int)indexToD
igit[i]] = i; |
| 32 } |
| 33 |
| 34 private Base64() {} |
| 35 |
| 36 public static char[] encode(byte[] in) { |
| 37 char[] ret = new char[(in.length + 2) / 3 * 4]; |
| 38 int p = 0; |
| 39 int i = 0; |
| 40 while (i < in.length) { |
| 41 // Lowest 24 bits count. |
| 42 int bits = (in[i++] & 0xff) << 16 | (i < in.length ? in[i++] & 0xff
: 0) << 8 | (i < in.length ? in[i++] & 0xff : 0); |
| 43 ret[p++] = indexToDigit[(bits & 0xfc0000) >> 18]; |
| 44 ret[p++] = indexToDigit[(bits & 0x3f000) >> 12]; |
| 45 ret[p++] = indexToDigit[(bits & 0xfc0) >> 6]; |
| 46 ret[p++] = indexToDigit[bits & 0x3f]; |
| 47 } |
| 48 assert(p == ret.length); |
| 49 int padding = (3 - in.length % 3) % 3; |
| 50 for (int j = ret.length - padding; j < ret.length; j++) ret[j] = '='; |
| 51 return ret; |
| 52 } |
| 53 |
| 54 public static byte[] decode(char[] in) { |
| 55 if (in.length % 4 != 0) throw new IllegalArgumentException("Base64-encod
ed string must be of length that is a multiple of 4."); |
| 56 int len = in.length; |
| 57 while(len > 0 && in[len - 1] == '=') len--; |
| 58 int padding = in.length - len; |
| 59 byte[] ret = new byte[in.length / 4 * 3 - padding]; |
| 60 int i = 0; |
| 61 int p = 0; |
| 62 while (i < len) { |
| 63 char c0 = in[i++]; |
| 64 char c1 = in[i++]; |
| 65 char c2 = i < len ? in[i++] : 'A'; |
| 66 char c3 = i < len ? in[i++] : 'A'; |
| 67 if (c0 > 127 || c1 > 127 || c2 > 127 || c3 > 127) throw new IllegalA
rgumentException("Invalid Base64 digit in: " + c0 + c1 + c2 + c3); |
| 68 int n0 = digitToIndex[c0]; |
| 69 int n1 = digitToIndex[c1]; |
| 70 int n2 = digitToIndex[c2]; |
| 71 int n3 = digitToIndex[c3]; |
| 72 if (n0 < 0 || n1 < 0 || n2 < 0 || n3 < 0) throw new IllegalArgumentE
xception("Invalid Base64 digit in: " + c0 + c1 + c2 + c3); |
| 73 int bits = (n0 << 18) | (n1 << 12) | (n2 << 6) | n3; |
| 74 ret[p++] = (byte)((bits & 0xff0000) >> 16); |
| 75 if (p < ret.length) ret[p++] = (byte)((bits & 0xff00) >> 8); |
| 76 if (p < ret.length) ret[p++] = (byte)(bits & 0xff); |
| 77 } |
| 78 return ret; |
| 79 } |
| 80 } |
OLD | NEW |