2 * jFCPlib - FreenetBase64.java - Copyright © 2015–2016 David Roden
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package net.pterodactylus.fcp;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
24 * Freenet-specific Base64 implementation.
26 * @author <a href="mailto:bombe@freenetproject.org">David ‘Bombe’ Roden</a>
28 public class FreenetBase64 {
30 private static final char[] FREENET_BASE64_ALPHABET =
31 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~-".toCharArray();
32 private static final int[] REVERSE_FREENET_BASE64_ALPHABET = reverse(FREENET_BASE64_ALPHABET);
34 private static int[] reverse(char[] alphabet) {
35 String alphabetString = new String(alphabet);
36 int[] reversedAlphabet = new int[128];
37 for (int i = 0; i < 128; i++) {
38 if (alphabetString.indexOf(i) > -1) {
39 reversedAlphabet[i] = alphabetString.indexOf(i);
41 reversedAlphabet[i] = -1;
44 return reversedAlphabet;
47 public String encode(byte[] data) {
48 StringBuilder result = new StringBuilder();
51 while (index < data.length) {
52 currentValue = (currentValue << 8) | data[index];
54 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 18) & 0x3f]);
55 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 12) & 0x3f]);
56 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 6) & 0x3f]);
57 result.append(FREENET_BASE64_ALPHABET[currentValue & 0x3f]);
62 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 2) & 0x3f]);
63 result.append(FREENET_BASE64_ALPHABET[(currentValue << 4) & 0x3f]);
65 } else if (index % 3 == 2) {
66 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 10) & 0x3f]);
67 result.append(FREENET_BASE64_ALPHABET[(currentValue >> 4) & 0x3f]);
68 result.append(FREENET_BASE64_ALPHABET[(currentValue << 2) & 0x3f]);
71 return result.toString();
74 public byte[] decode(String data) {
75 ByteArrayOutputStream dataOutput = new ByteArrayOutputStream(data.length() * 3 / 4);
79 for (char c : data.toCharArray()) {
83 currentValue = (currentValue << 6) | REVERSE_FREENET_BASE64_ALPHABET[c];
85 dataOutput.write((currentValue >> 16) & 0xff);
86 dataOutput.write((currentValue >> 8) & 0xff);
87 dataOutput.write(currentValue & 0xff);
92 dataOutput.write((currentValue >> 4) & 0xff);
93 } else if (index % 4 == 3) {
94 dataOutput.write((currentValue >> 10) & 0xff);
95 dataOutput.write((currentValue >> 2) & 0xff);
97 return dataOutput.toByteArray();
101 } catch (IOException e) {
102 throw new RuntimeException(e);