net.freeutils.util.Base32 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jelementary Show documentation
Show all versions of jelementary Show documentation
The Java Elementary Utilities package
The newest version!
/*
* Copyright © 2003-2024 Amichai Rothman
*
* This file is part of JElementary - the Java Elementary Utilities package.
*
* JElementary is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* JElementary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JElementary. If not, see .
*
* For additional info see https://www.freeutils.net/source/jelementary/
*/
package net.freeutils.util;
import java.io.UnsupportedEncodingException;
/**
* The {@code Base32} class contains RFC 4648 compliant base32 and base32hex
* encoding and decoding methods.
*/
public class Base32 {
protected static final byte[] ENCODE, DECODE, ENCODE_HEX, DECODE_HEX;
static {
byte[][] tables = Base64.createLookupTables("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567");
byte[][] tablesHex = Base64.createLookupTables("0123456789ABCDEFGHIJKLMNOPQRSTUV");
ENCODE = tables[0];
DECODE = tables[1];
ENCODE_HEX = tablesHex[0];
DECODE_HEX = tablesHex[1];
}
/**
* Encodes the given bytes using the given encoding lookup table.
*
* @param b the bytes to encode
* @param lookup the encoding lookup table
* @return the encoded bytes
*/
public static byte[] encode(byte[] b, byte[] lookup) {
int full = b.length / 5 * 5;
int rem = b.length - full;
byte[] out = new byte[(b.length + 4) / 5 * 8];
int i = 0;
int j = 0;
// encode full byte quantums
while (i < full) {
long t = (long)(b[i++] & 0xFF) << 32 | (long)(b[i++] & 0xFF) << 24
| (b[i++] & 0xFF) << 16 | (b[i++] & 0xFF) << 8 | (b[i++] & 0xFF);
out[j++] = lookup[(int)(t >> 35)];
out[j++] = lookup[(int)(t >> 30) & 0x01F];
out[j++] = lookup[(int)(t >> 25) & 0x01F];
out[j++] = lookup[(int)(t >> 20) & 0x01F];
out[j++] = lookup[(int)(t >> 15) & 0x01F];
out[j++] = lookup[(int)(t >> 10) & 0x01F];
out[j++] = lookup[(int)(t >> 5) & 0x01F];
out[j++] = lookup[(int)t & 0x01F];
}
// encode remainder (0, 1, 2, 3 or 4 last bytes)
if (rem > 0) {
long t = (long)(b[i++] & 0xFF) << 32
| (rem <= 1 ? 0 : (long)(b[i++] & 0xFF) << 24)
| (rem <= 2 ? 0 : (b[i++] & 0xFF) << 16)
| (rem <= 3 ? 0 : (b[i] & 0xFF) << 8);
out[j++] = lookup[(int)(t >> 35)];
out[j++] = lookup[(int)(t >> 30) & 0x01F];
out[j++] = rem <= 1 ? (byte)'=' : lookup[(int)(t >> 25) & 0x01F];
out[j++] = rem <= 1 ? (byte)'=' : lookup[(int)(t >> 20) & 0x01F];
out[j++] = rem <= 2 ? (byte)'=' : lookup[(int)(t >> 15) & 0x01F];
out[j++] = rem <= 3 ? (byte)'=' : lookup[(int)(t >> 10) & 0x01F];
out[j++] = rem <= 3 ? (byte)'=' : lookup[(int)(t >> 5) & 0x01F];
out[j] = '=';
}
return out;
}
/**
* Decodes the given bytes using the given decoding lookup table.
*
* @param b the bytes to decode
* @param lookup the decoding lookup table
* @return the decoded bytes
*/
public static byte[] decode(byte[] b, byte[] lookup) {
int pad = 0;
for (int i = b.length - 1; i >= 0 && b[i] == '='; i--)
pad++;
int full = (b.length - pad) / 8 * 8;
int rem = pad == 0 ? 0 : (9 - pad) / 2 - 5;
byte[] out = new byte[b.length / 8 * 5 + rem];
int i = 0;
int j = 0;
// decode full byte quantums
while (i < full) {
long t = (long)lookup[b[i++]] << 35 | (long)lookup[b[i++]] << 30
| lookup[b[i++]] << 25 | lookup[b[i++]] << 20 | lookup[b[i++]] << 15
| lookup[b[i++]] << 10 | lookup[b[i++]] << 5 | lookup[b[i++]];
out[j++] = (byte)(t >> 32);
out[j++] = (byte)(t >> 24);
out[j++] = (byte)(t >> 16);
out[j++] = (byte)(t >> 8);
out[j++] = (byte)t;
}
// decode remainder (0, 1, 2, 3 or 4 last bytes)
if (pad > 0) {
long t = (long)lookup[b[i++]] << 35
| (long)lookup[b[i++]] << 30
| (pad <= 4 ? lookup[b[i++]] << 25 : 0)
| (pad <= 4 ? lookup[b[i++]] << 20 : 0)
| (pad <= 3 ? lookup[b[i++]] << 15 : 0)
| (pad <= 1 ? lookup[b[i++]] << 10 : 0)
| (pad <= 1 ? lookup[b[i]] << 5 : 0);
out[j++] = (byte)(t >> 32);
if (pad <= 4)
out[j++] = (byte)(t >> 24);
if (pad <= 3)
out[j++] = (byte)(t >> 16);
if (pad <= 1)
out[j] = (byte)(t >> 8);
}
return out;
}
/**
* Checks whether the given bytes are validly encoded.
*
* @param b the bytes to check
* @param lookup the decoding lookup table
* @return true if the bytes are validly encoded, false otherwise
*/
public static boolean isValid(byte[] b, byte[] lookup) {
int len = b.length;
if (len % 8 != 0)
return false;
int pad = 0;
for (int i = b.length - 1; i >= 0 && b[i] == '='; i--)
pad++;
if (pad != 0 && pad != 1 && pad != 3 && pad != 4 && pad != 6)
return false;
for (int i = 0; i < len; i++)
if (lookup[b[i]] < 0 && (i < len - pad || b[i] != '='))
return false;
return true;
}
/**
* Encodes the given bytes using standard base32 encoding.
*
* @param b the bytes to encode
* @return the encoded bytes
*/
public static byte[] encode(byte[] b) {
return encode(b, ENCODE);
}
/**
* Encodes the given bytes using base32hex encoding.
*
* @param b the bytes to encode
* @return the encoded bytes
*/
public static byte[] encodeHex(byte[] b) {
return encode(b, ENCODE_HEX);
}
/**
* Decodes the given bytes using standard base32 decoding.
* The input it assumed to be valid, as this method does not
* validate that it is indeed legal base32-encoded data.
*
* @param b the bytes to decode
* @return the decoded bytes
*/
public static byte[] decode(byte[] b) {
return decode(b, DECODE);
}
/**
* Decodes the given bytes using base32hex decoding.
* The input it assumed to be valid, as this method does not
* validate that it is indeed legal base32-encoded data.
*
* @param b the bytes to decode
* @return the decoded bytes
*/
public static byte[] decodeHex(byte[] b) {
return decode(b, DECODE_HEX);
}
/**
* Checks whether the given bytes are validly encoded in standard base32 encoding.
*
* @param b the bytes to check
* @return true if the bytes are validly encoded, false otherwise
*/
public static boolean isValid(byte[] b) {
return isValid(b, DECODE);
}
/**
* Checks whether the given bytes are validly encoded in base32hex encoding.
*
* @param b the bytes to check
* @return true if the bytes are validly encoded, false otherwise
*/
public static boolean isValidHex(byte[] b) {
return isValid(b, DECODE_HEX);
}
/**
* Decodes the given string using standard base32 decoding.
*
* @param s the string to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @return the decoded bytes
* @throws IllegalArgumentException if the given string contains non US-ASCII characters,
* or if validate is true and the given bytes are not valid base32 bytes
*/
public static byte[] decode(String s, boolean validate) {
return decode(Strings.getASCIIBytes(s), validate);
}
/**
* Decodes the given bytes using standard base32 decoding.
*
* @param b the bytes to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @return the decoded bytes
* @throws IllegalArgumentException if validate is true and the given
* bytes are not valid base32 bytes
*/
public static byte[] decode(byte[] b, boolean validate) {
if (validate && !isValid(b))
throw new IllegalArgumentException("invalid base32 bytes");
return decode(b);
}
/**
* Decodes the given string using base32hex decoding.
*
* @param s the string to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @return the decoded bytes
* @throws IllegalArgumentException if the given string contains non US-ASCII characters,
* or if validate is true and the given bytes are not valid base32 bytes
*/
public static byte[] decodeHex(String s, boolean validate) {
return decodeHex(Strings.getASCIIBytes(s), validate);
}
/**
* Decodes the given bytes using base32hex decoding.
*
* @param b the bytes to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @return the decoded bytes
* @throws IllegalArgumentException if validate is true and the given
* bytes are not valid base32 bytes
*/
public static byte[] decodeHex(byte[] b, boolean validate) {
if (validate && !isValidHex(b))
throw new IllegalArgumentException("invalid base32 bytes");
return decodeHex(b);
}
/**
* Encodes the given bytes using standard base32 encoding.
*
* @param b the bytes to encode
* @return the encoded bytes as an ASCII hex string
*/
public static String encodeString(byte[] b) {
try {
return new String(encode(b, ENCODE), "US-ASCII");
} catch (UnsupportedEncodingException uee) {
return null; // can't happen
}
}
/**
* Decodes the given string using standard base32 decoding.
*
* @param s the string to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @param charset the charset to interpret the decoded bytes in
* @return the decoded bytes as string in the given charset
* @throws IllegalArgumentException if the given string contains non US-ASCII characters,
* or if validate is true and the given bytes are not valid base32 bytes,
* or if the given charset does not exist
*/
public static String decodeString(String s, boolean validate, String charset) {
try {
return new String(decode(Strings.getASCIIBytes(s), validate), charset);
} catch (UnsupportedEncodingException uee) {
throw new IllegalArgumentException(uee);
}
}
/**
* Decodes the given string using standard base32 decoding.
*
* @param s the string to decode
* @param validate if true, the bytes are validated to be legal base32 bytes
* @return the decoded bytes as string in the ISO-8869-1 charset
* @throws IllegalArgumentException if the given string contains non US-ASCII characters,
* or if validate is true and the given bytes are not valid base32 bytes
*/
public static String decodeString(String s, boolean validate) {
return decodeString(s, validate, "ISO8859_1");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy