1 package net.pterodactylus.fcp;
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
7 * Freenet-specific Base64 implementation.
9 * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe’ Roden</a>
11 public class FreenetBase64 {
13 private static final char[] FREENET_BASE64_ALPHABET =
14 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~-".toCharArray();
15 private static final int[] REVERSE_FREENET_BASE64_ALPHABET = reverse(FREENET_BASE64_ALPHABET);
17 private static int[] reverse(char[] alphabet) {
18 String alphabetString = new String(alphabet);
19 int[] reversedAlphabet = new int[128];
20 for (int i = 0; i < 128; i++) {
21 if (alphabetString.indexOf(i) > -1) {
22 reversedAlphabet[i] = alphabetString.indexOf(i);
24 reversedAlphabet[i] = -1;
27 return reversedAlphabet;
30 public String encode(byte[] data) {
31 StringBuilder result = new StringBuilder();
34 while (index < data.length) {
35 currentValue = (currentValue << 8) | data[index];
37 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 18) & 0b111111]);
38 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 12) & 0b111111]);
39 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 6) & 0b111111]);
40 result.append(FREENET_BASE64_ALPHABET[currentValue & 0b111111]);
45 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 2) & 0b111111]);
46 result.append(FREENET_BASE64_ALPHABET[(currentValue << 4) & 0b111111]);
48 } else if (index % 3 == 2) {
49 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 10) & 0b111111]);
50 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 4) & 0b111111]);
51 result.append(FREENET_BASE64_ALPHABET[(currentValue << 2) & 0b111111]);
54 return result.toString();
57 public byte[] decode(String data) {
58 try (ByteArrayOutputStream dataOutput = new ByteArrayOutputStream(data.length() * 3 / 4)) {
61 for (char c : data.toCharArray()) {
65 currentValue = (currentValue << 6) | REVERSE_FREENET_BASE64_ALPHABET[c];
67 dataOutput.write((currentValue >> 16) & 0b11111111);
68 dataOutput.write((currentValue >> 8) & 0b11111111);
69 dataOutput.write(currentValue & 0b11111111);
74 dataOutput.write((currentValue >> 4) & 0b11111111);
75 } else if (index % 4 == 3) {
76 dataOutput.write((currentValue >> 10) & 0b11111111);
77 dataOutput.write((currentValue >> 2) & 0b11111111);
79 return dataOutput.toByteArray();
80 } catch (IOException e) {
81 throw new RuntimeException(e);