- cfpassphrase/src/com/lambdaworks/codec/Base64.java
- 5 KB
- 157
1// Copyright (C) 2011 - Will Glozer. All rights reserved.
2
3package com.lambdaworks.codec;
4
5import java.util.Arrays;
6
7/**
8 * High-performance base64 codec based on the algorithm used in Mikael Grev's MiG Base64.
9 * This implementation is designed to handle base64 without line splitting and with
10 * optional padding. Alternative character tables may be supplied to the {@code encode}
11 * and {@code decode} methods to implement modified base64 schemes.
12 *
13 * Decoding assumes correct input, the caller is responsible for ensuring that the input
14 * contains no invalid characters.
15 *
16 * @author Will Glozer
17 */
18public class Base64 {
19 private static final char[] encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
20 private static final int[] decode = new int[128];
21 private static final char pad = '=';
22
23 static {
24 Arrays.fill(decode, -1);
25 for (int i = 0; i < encode.length; i++) {
26 decode[encode[i]] = i;
27 }
28 decode[pad] = 0;
29 }
30
31 /**
32 * Decode base64 chars to bytes.
33 *
34 * @param chars Chars to encode.
35 *
36 * @return Decoded bytes.
37 */
38 public static byte[] decode(char[] chars) {
39 return decode(chars, decode, pad);
40 }
41
42 /**
43 * Encode bytes to base64 chars, with padding.
44 *
45 * @param bytes Bytes to encode.
46 *
47 * @return Encoded chars.
48 */
49 public static char[] encode(byte[] bytes) {
50 return encode(bytes, encode, pad);
51 }
52
53 /**
54 * Encode bytes to base64 chars, with optional padding.
55 *
56 * @param bytes Bytes to encode.
57 * @param padded Add padding to output.
58 *
59 * @return Encoded chars.
60 */
61 public static char[] encode(byte[] bytes, boolean padded) {
62 return encode(bytes, encode, padded ? pad : 0);
63 }
64
65 /**
66 * Decode base64 chars to bytes using the supplied decode table and padding
67 * character.
68 *
69 * @param src Base64 encoded data.
70 * @param table Decode table.
71 * @param pad Padding character.
72 *
73 * @return Decoded bytes.
74 */
75 public static byte[] decode(char[] src, int[] table, char pad) {
76 int len = src.length;
77
78 if (len == 0) return new byte[0];
79
80 int padCount = (src[len - 1] == pad ? (src[len - 2] == pad ? 2 : 1) : 0);
81 int bytes = (len * 6 >> 3) - padCount;
82 int blocks = (bytes / 3) * 3;
83
84 byte[] dst = new byte[bytes];
85 int si = 0, di = 0;
86
87 while (di < blocks) {
88 int n = table[src[si++]] << 18 | table[src[si++]] << 12 | table[src[si++]] << 6 | table[src[si++]];
89 dst[di++] = (byte) (n >> 16);
90 dst[di++] = (byte) (n >> 8);
91 dst[di++] = (byte) n;
92 }
93
94 if (di < bytes) {
95 int n = 0;
96 switch (len - si) {
97 case 4: n |= table[src[si+3]];
98 case 3: n |= table[src[si+2]] << 6;
99 case 2: n |= table[src[si+1]] << 12;
100 case 1: n |= table[src[si]] << 18;
101 }
102 for (int r = 16; di < bytes; r -= 8) {
103 dst[di++] = (byte) (n >> r);
104 }
105 }
106
107 return dst;
108 }
109
110 /**
111 * Encode bytes to base64 chars using the supplied encode table and with
112 * optional padding.
113 *
114 * @param src Bytes to encode.
115 * @param table Encoding table.
116 * @param pad Padding character, or 0 for no padding.
117 *
118 * @return Encoded chars.
119 */
120 public static char[] encode(byte[] src, char[] table, char pad) {
121 int len = src.length;
122
123 if (len == 0) return new char[0];
124
125 int blocks = (len / 3) * 3;
126 int chars = ((len - 1) / 3 + 1) << 2;
127 int tail = len - blocks;
128 if (pad == 0 && tail > 0) chars -= 3 - tail;
129
130 char[] dst = new char[chars];
131 int si = 0, di = 0;
132
133 while (si < blocks) {
134 int n = (src[si++] & 0xff) << 16 | (src[si++] & 0xff) << 8 | (src[si++] & 0xff);
135 dst[di++] = table[(n >>> 18) & 0x3f];
136 dst[di++] = table[(n >>> 12) & 0x3f];
137 dst[di++] = table[(n >>> 6) & 0x3f];
138 dst[di++] = table[n & 0x3f];
139 }
140
141 if (tail > 0) {
142 int n = (src[si] & 0xff) << 10;
143 if (tail == 2) n |= (src[++si] & 0xff) << 2;
144
145 dst[di++] = table[(n >>> 12) & 0x3f];
146 dst[di++] = table[(n >>> 6) & 0x3f];
147 if (tail == 2) dst[di++] = table[n & 0x3f];
148
149 if (pad != 0) {
150 if (tail == 1) dst[di++] = pad;
151 dst[di] = pad;
152 }
153 }
154
155 return dst;
156 }
157}