001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: * Initial Developer: H2 Group
005: */
006: package org.h2.tools.net;
007:
008: import java.util.Random;
009:
010: /**
011: * This class converts binary to base64 and vice versa.
012: */
013: public class Base64 {
014:
015: private static final byte[] CODE = new byte[64];
016: private static final byte[] REV = new byte[256];
017:
018: static {
019: for (int i = 'A'; i <= 'Z'; i++) {
020: CODE[i - 'A'] = (byte) i;
021: CODE[i - 'A' + 26] = (byte) (i + 'a' - 'A');
022: }
023: for (int i = 0; i < 10; i++) {
024: CODE[i + 2 * 26] = (byte) ('0' + i);
025: }
026: CODE[62] = (byte) '+';
027: CODE[63] = (byte) '/';
028: for (int i = 0; i < 255; i++) {
029: REV[i] = -1;
030: }
031: for (int i = 0; i < 64; i++) {
032: REV[CODE[i]] = (byte) i;
033: }
034: }
035:
036: private static void check(String a, String b) {
037: if (!a.equals(b)) {
038: throw new Error("mismatch: " + a + " <> " + b);
039: }
040: }
041:
042: public static void main(String[] args) {
043: check(new String(encode(new byte[] {})), "");
044: check(new String(encode("A".getBytes())), "QQ==");
045: check(new String(encode("AB".getBytes())), "QUI=");
046: check(new String(encode("ABC".getBytes())), "QUJD");
047: check(new String(encode("ABCD".getBytes())), "QUJDRA==");
048: check(new String(decode(new byte[] {})), "");
049: check(new String(decode("QQ==".getBytes())), "A");
050: check(new String(decode("QUI=".getBytes())), "AB");
051: check(new String(decode("QUJD".getBytes())), "ABC");
052: check(new String(decode("QUJDRA==".getBytes())), "ABCD");
053: int len = 10000;
054: test(false, len);
055: test(true, len);
056: test(false, len);
057: test(true, len);
058: }
059:
060: private static void test(boolean fast, int len) {
061: Random random = new Random(10);
062: long time = System.currentTimeMillis();
063: byte[] bin = new byte[len];
064: random.nextBytes(bin);
065: for (int i = 0; i < len; i++) {
066: byte[] dec;
067: if (fast) {
068: byte[] enc = encodeFast(bin);
069: dec = decodeFast(enc);
070: } else {
071: byte[] enc = encode(bin);
072: dec = decode(enc);
073: }
074: test(bin, dec);
075: }
076: time = System.currentTimeMillis() - time;
077: System.out.println("fast=" + fast + " time=" + time);
078: }
079:
080: private static void test(byte[] in, byte[] out) {
081: if (in.length != out.length) {
082: throw new Error("Length error");
083: }
084: for (int i = 0; i < in.length; i++) {
085: if (in[i] != out[i]) {
086: throw new Error("Error at " + i);
087: }
088: }
089: }
090:
091: public static byte[] encode(byte[] bin) {
092: byte[] code = CODE;
093: int size = bin.length;
094: int len = ((size + 2) / 3) * 4;
095: byte[] enc = new byte[len];
096: int fast = size / 3 * 3, i = 0, j = 0;
097: for (; i < fast; i += 3, j += 4) {
098: int a = ((bin[i] & 255) << 16) + ((bin[i + 1] & 255) << 8)
099: + (bin[i + 2] & 255);
100: enc[j] = code[a >> 18];
101: enc[j + 1] = code[(a >> 12) & 63];
102: enc[j + 2] = code[(a >> 6) & 63];
103: enc[j + 3] = code[a & 63];
104: }
105: if (i < size) {
106: int a = (bin[i++] & 255) << 16;
107: enc[j] = code[a >> 18];
108: if (i < size) {
109: a += (bin[i] & 255) << 8;
110: enc[j + 2] = code[(a >> 6) & 63];
111: } else {
112: enc[j + 2] = (byte) '=';
113: }
114: enc[j + 1] = code[(a >> 12) & 63];
115: enc[j + 3] = (byte) '=';
116: }
117: return enc;
118: }
119:
120: public static byte[] encodeFast(byte[] bin) {
121: byte[] code = CODE;
122: int size = bin.length;
123: int len = ((size * 4) + 2) / 3;
124: byte[] enc = new byte[len];
125: int fast = size / 3 * 3, i = 0, j = 0;
126: for (; i < fast; i += 3, j += 4) {
127: int a = ((bin[i] & 255) << 16) + ((bin[i + 1] & 255) << 8)
128: + (bin[i + 2] & 255);
129: enc[j] = code[a >> 18];
130: enc[j + 1] = code[(a >> 12) & 63];
131: enc[j + 2] = code[(a >> 6) & 63];
132: enc[j + 3] = code[a & 63];
133: }
134: if (i < size) {
135: int a = (bin[i++] & 255) << 16;
136: enc[j] = code[a >> 18];
137: if (i < size) {
138: a += (bin[i] & 255) << 8;
139: enc[j + 2] = code[(a >> 6) & 63];
140: }
141: enc[j + 1] = code[(a >> 12) & 63];
142: }
143: return enc;
144: }
145:
146: public static byte[] trim(byte[] enc) {
147: byte[] rev = REV;
148: int j = 0, size = enc.length;
149: if (size > 1 && enc[size - 2] == '=') {
150: size--;
151: }
152: if (size > 0 && enc[size - 1] == '=') {
153: size--;
154: }
155: for (int i = 0; i < size; i++) {
156: if (rev[enc[i] & 255] < 0) {
157: j++;
158: }
159: }
160: if (j == 0) {
161: return enc;
162: }
163: byte[] buff = new byte[size - j];
164: for (int i = 0, k = 0; i < size; i++) {
165: int x = enc[i] & 255;
166: if (rev[x] >= 0) {
167: buff[k++] = (byte) x;
168: }
169: }
170: return buff;
171: }
172:
173: public static byte[] decode(byte[] enc) {
174: enc = trim(enc);
175: byte[] rev = REV;
176: int len = enc.length, size = (len * 3) / 4;
177: if (len > 0 && enc[len - 1] == '=') {
178: size--;
179: if (len > 1 && enc[len - 2] == '=') {
180: size--;
181: }
182: }
183: byte[] bin = new byte[size];
184: int fast = size / 3 * 3, i = 0, j = 0;
185: for (; i < fast; i += 3, j += 4) {
186: int a = (rev[enc[j] & 255] << 18)
187: + (rev[enc[j + 1] & 255] << 12)
188: + (rev[enc[j + 2] & 255] << 6)
189: + rev[enc[j + 3] & 255];
190: bin[i] = (byte) (a >> 16);
191: bin[i + 1] = (byte) (a >> 8);
192: bin[i + 2] = (byte) a;
193: }
194: if (i < size) {
195: int a = (rev[enc[j] & 255] << 10)
196: + (rev[enc[j + 1] & 255] << 4);
197: bin[i++] = (byte) (a >> 8);
198: if (i < size) {
199: a += rev[enc[j + 2] & 255] >> 2;
200: bin[i] = (byte) a;
201: }
202: }
203: return bin;
204: }
205:
206: public static byte[] decodeFast(byte[] enc) {
207: byte[] rev = REV;
208: int len = enc.length, size = (len * 3) / 4;
209: byte[] bin = new byte[size];
210: int fast = size / 3 * 3, i = 0, j = 0;
211: for (; i < fast; i += 3, j += 4) {
212: int a = (rev[enc[j] & 255] << 18)
213: + (rev[enc[j + 1] & 255] << 12)
214: + (rev[enc[j + 2] & 255] << 6)
215: + rev[enc[j + 3] & 255];
216: bin[i] = (byte) (a >> 16);
217: bin[i + 1] = (byte) (a >> 8);
218: bin[i + 2] = (byte) a;
219: }
220: if (i < size) {
221: int a = (rev[enc[j] & 255] << 10)
222: + (rev[enc[j + 1] & 255] << 4);
223: bin[i++] = (byte) (a >> 8);
224: if (i < size) {
225: a += rev[enc[j + 2] & 255] >> 2;
226: bin[i] = (byte) a;
227: }
228: }
229: return bin;
230: }
231:
232: }
|