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