Skip to content

Commit bb6acd3

Browse files
authored
feat: base64 algorithm implementation
1 parent 5e9d9f7 commit bb6acd3

1 file changed

Lines changed: 195 additions & 0 deletions

File tree

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package com.thealgorithms.conversions;
2+
3+
import java.util.List;
4+
import java.util.ArrayList;
5+
import java.nio.charset.StandardCharsets;
6+
7+
/**
8+
* Base64 is a group of binary-to-text encoding schemes that represent binary data
9+
* in an ASCII string format by translating it into a radix-64 representation.
10+
* Each base64 digit represents exactly 6 bits of data.
11+
*
12+
* Base64 encoding is commonly used when there is a need to encode binary data
13+
* that needs to be stored and transferred over media that are designed to deal
14+
* with textual data.
15+
*
16+
* Wikipedia Reference: https://en.wikipedia.org/wiki/Base64
17+
* Author: Nithin U.
18+
* Github: https://github.com/NithinU2802
19+
*/
20+
21+
public final class Base64 {
22+
23+
// Base64 character set
24+
private static final String BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
25+
private static final char PADDING_CHAR = '=';
26+
27+
private Base64() {
28+
29+
}
30+
31+
/**
32+
* Encodes the given byte array to a Base64 encoded string.
33+
*
34+
* @param input the byte array to encode
35+
* @return the Base64 encoded string
36+
* @throws IllegalArgumentException if input is null
37+
*/
38+
public static String encode(byte[] input) {
39+
if (input == null) {
40+
throw new IllegalArgumentException("Input cannot be null");
41+
}
42+
43+
if (input.length == 0) {
44+
return "";
45+
}
46+
47+
StringBuilder result = new StringBuilder();
48+
int padding = 0;
49+
50+
// Process input in groups of 3 bytes
51+
for (int i = 0; i < input.length; i += 3) {
52+
// Get up to 3 bytes
53+
int byte1 = input[i] & 0xFF;
54+
int byte2 = (i + 1 < input.length) ? (input[i + 1] & 0xFF) : 0;
55+
int byte3 = (i + 2 < input.length) ? (input[i + 2] & 0xFF) : 0;
56+
57+
// Calculate padding needed
58+
if (i + 1 >= input.length) {
59+
padding = 2;
60+
} else if (i + 2 >= input.length) {
61+
padding = 1;
62+
}
63+
64+
// Combine 3 bytes into a 24-bit number
65+
int combined = (byte1 << 16) | (byte2 << 8) | byte3;
66+
67+
// Extract four 6-bit groups
68+
result.append(BASE64_CHARS.charAt((combined >> 18) & 0x3F));
69+
result.append(BASE64_CHARS.charAt((combined >> 12) & 0x3F));
70+
result.append(BASE64_CHARS.charAt((combined >> 6) & 0x3F));
71+
result.append(BASE64_CHARS.charAt(combined & 0x3F));
72+
}
73+
74+
// Replace padding characters
75+
if (padding > 0) {
76+
result.setLength(result.length() - padding);
77+
for (int i = 0; i < padding; i++) {
78+
result.append(PADDING_CHAR);
79+
}
80+
}
81+
82+
return result.toString();
83+
}
84+
85+
/**
86+
* Encodes the given string to a Base64 encoded string using UTF-8 encoding.
87+
*
88+
* @param input the string to encode
89+
* @return the Base64 encoded string
90+
* @throws IllegalArgumentException if input is null
91+
*/
92+
public static String encode(String input) {
93+
if (input == null) {
94+
throw new IllegalArgumentException("Input cannot be null");
95+
}
96+
97+
return encode(input.getBytes(StandardCharsets.UTF_8));
98+
}
99+
100+
/**
101+
* Decodes the given Base64 encoded string to a byte array.
102+
*
103+
* @param input the Base64 encoded string to decode
104+
* @return the decoded byte array
105+
* @throws IllegalArgumentException if input is null or contains invalid Base64 characters
106+
*/
107+
public static byte[] decode(String input) {
108+
if (input == null) {
109+
throw new IllegalArgumentException("Input cannot be null");
110+
}
111+
112+
if (input.isEmpty()) {
113+
return new byte[0];
114+
}
115+
116+
// Remove padding for processing
117+
String cleanInput = input.replace("=", "");
118+
int padding = input.length() - cleanInput.length();
119+
120+
// Validate input length
121+
if ((cleanInput.length() % 4) + padding > 4) {
122+
throw new IllegalArgumentException("Invalid Base64 input length");
123+
}
124+
125+
List<Byte> result = new ArrayList<>();
126+
127+
// Process input in groups of 4 characters
128+
for (int i = 0; i < cleanInput.length(); i += 4) {
129+
// Get up to 4 characters
130+
int char1 = getBase64Value(cleanInput.charAt(i));
131+
int char2 = (i + 1 < cleanInput.length()) ? getBase64Value(cleanInput.charAt(i + 1)) : 0;
132+
int char3 = (i + 2 < cleanInput.length()) ? getBase64Value(cleanInput.charAt(i + 2)) : 0;
133+
int char4 = (i + 3 < cleanInput.length()) ? getBase64Value(cleanInput.charAt(i + 3)) : 0;
134+
135+
// Combine four 6-bit groups into a 24-bit number
136+
int combined = (char1 << 18) | (char2 << 12) | (char3 << 6) | char4;
137+
138+
// Extract three 8-bit bytes
139+
result.add((byte) ((combined >> 16) & 0xFF));
140+
if (i + 2 < cleanInput.length() || (i + 2 == cleanInput.length() && padding < 2)) {
141+
result.add((byte) ((combined >> 8) & 0xFF));
142+
}
143+
if (i + 3 < cleanInput.length() || (i + 3 == cleanInput.length() && padding < 1)) {
144+
result.add((byte) (combined & 0xFF));
145+
}
146+
}
147+
148+
// Convert List<Byte> to byte[]
149+
byte[] resultArray = new byte[result.size()];
150+
for (int i = 0; i < result.size(); i++) {
151+
resultArray[i] = result.get(i);
152+
}
153+
154+
return resultArray;
155+
}
156+
157+
/**
158+
* Decodes the given Base64 encoded string to a string using UTF-8 encoding.
159+
*
160+
* @param input the Base64 encoded string to decode
161+
* @return the decoded string
162+
* @throws IllegalArgumentException if input is null or contains invalid Base64 characters
163+
*/
164+
public static String decodeToString(String input) {
165+
if (input == null) {
166+
throw new IllegalArgumentException("Input cannot be null");
167+
}
168+
169+
byte[] decodedBytes = decode(input);
170+
return new String(decodedBytes, StandardCharsets.UTF_8);
171+
}
172+
173+
/**
174+
* Gets the numeric value of a Base64 character.
175+
*
176+
* @param c the Base64 character
177+
* @return the numeric value (0-63)
178+
* @throws IllegalArgumentException if character is not a valid Base64 character
179+
*/
180+
private static int getBase64Value(char c) {
181+
if (c >= 'A' && c <= 'Z') {
182+
return c - 'A';
183+
} else if (c >= 'a' && c <= 'z') {
184+
return c - 'a' + 26;
185+
} else if (c >= '0' && c <= '9') {
186+
return c - '0' + 52;
187+
} else if (c == '+') {
188+
return 62;
189+
} else if (c == '/') {
190+
return 63;
191+
} else {
192+
throw new IllegalArgumentException("Invalid Base64 character: " + c);
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)