All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.hutool.core.codec.Base32Codec Maven / Gradle / Ivy

There is a newer version: 5.8.33
Show newest version
package cn.hutool.core.codec;

import java.util.Arrays;

/**
 * Base32 - encodes and decodes RFC4648 Base32 (see https://datatracker.ietf.org/doc/html/rfc4648#section-6 )
* base32就是用32(2的5次方)个特定ASCII码来表示256个ASCII码。
* 所以,5个ASCII字符经过base32编码后会变为8个字符(公约数为40),长度增加3/5.不足8n用“=”补足。
* 根据RFC4648 Base32规范,支持两种模式: *
    *
  • Base 32 Alphabet (ABCDEFGHIJKLMNOPQRSTUVWXYZ234567)
  • *
  • "Extended Hex" Base 32 Alphabet (0123456789ABCDEFGHIJKLMNOPQRSTUV)
  • *
* * @author Looly * @since 5.8.0 */ public class Base32Codec implements Encoder, Decoder { public static Base32Codec INSTANCE = new Base32Codec(); @Override public String encode(byte[] data) { return encode(data, false); } /** * 编码数据 * * @param data 数据 * @param useHex 是否使用Hex Alphabet * @return 编码后的Base32字符串 */ public String encode(byte[] data, boolean useHex) { final Base32Encoder encoder = useHex ? Base32Encoder.HEX_ENCODER : Base32Encoder.ENCODER; return encoder.encode(data); } @Override public byte[] decode(CharSequence encoded) { return decode(encoded, false); } /** * 解码数据 * * @param encoded base32字符串 * @param useHex 是否使用Hex Alphabet * @return 解码后的内容 */ public byte[] decode(CharSequence encoded, boolean useHex) { final Base32Decoder decoder = useHex ? Base32Decoder.HEX_DECODER : Base32Decoder.DECODER; return decoder.decode(encoded); } /** * Bas32编码器 */ public static class Base32Encoder implements Encoder { private static final String DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; private static final String HEX_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; private static final Character DEFAULT_PAD = '='; private static final int[] BASE32_FILL = {-1, 4, 1, 6, 3}; public static final Base32Encoder ENCODER = new Base32Encoder(DEFAULT_ALPHABET, DEFAULT_PAD); public static final Base32Encoder HEX_ENCODER = new Base32Encoder(HEX_ALPHABET, DEFAULT_PAD); private final char[] alphabet; private final Character pad; /** * 构造 * * @param alphabet 自定义编码字母表,见 {@link #DEFAULT_ALPHABET}和 {@link #HEX_ALPHABET} * @param pad 补位字符 */ public Base32Encoder(String alphabet, Character pad) { this.alphabet = alphabet.toCharArray(); this.pad = pad; } @Override public String encode(byte[] data) { int i = 0; int index = 0; int digit; int currByte; int nextByte; int encodeLen = data.length * 8 / 5; if (encodeLen != 0) { encodeLen = encodeLen + 1 + BASE32_FILL[(data.length * 8) % 5]; } StringBuilder base32 = new StringBuilder(encodeLen); while (i < data.length) { // unsign currByte = (data[i] >= 0) ? data[i] : (data[i] + 256); /* Is the current digit going to span a byte boundary? */ if (index > 3) { if ((i + 1) < data.length) { nextByte = (data[i + 1] >= 0) ? data[i + 1] : (data[i + 1] + 256); } else { nextByte = 0; } digit = currByte & (0xFF >> index); index = (index + 5) % 8; digit <<= index; digit |= nextByte >> (8 - index); i++; } else { digit = (currByte >> (8 - (index + 5))) & 0x1F; index = (index + 5) % 8; if (index == 0) { i++; } } base32.append(alphabet[digit]); } if (null != pad) { // 末尾补充不足长度的 while (base32.length() < encodeLen) { base32.append(pad.charValue()); } } return base32.toString(); } } /** * Base32解码器 */ public static class Base32Decoder implements Decoder { private static final char BASE_CHAR = '0'; public static final Base32Decoder DECODER = new Base32Decoder(Base32Encoder.DEFAULT_ALPHABET); public static final Base32Decoder HEX_DECODER = new Base32Decoder(Base32Encoder.HEX_ALPHABET); private final byte[] lookupTable; /** * 构造 * * @param alphabet 编码字母表 */ public Base32Decoder(String alphabet) { lookupTable = new byte[128]; Arrays.fill(lookupTable, (byte) -1); final int length = alphabet.length(); char c; for (int i = 0; i < length; i++) { c = alphabet.charAt(i); lookupTable[c - BASE_CHAR] = (byte) i; // 支持小写字母解码 if(c >= 'A' && c <= 'Z'){ lookupTable[Character.toLowerCase(c) - BASE_CHAR] = (byte) i; } } } @Override public byte[] decode(CharSequence encoded) { int i, index, lookup, offset, digit; final String base32 = encoded.toString(); int len = base32.endsWith("=") ? base32.indexOf("=") * 5 / 8 : base32.length() * 5 / 8; byte[] bytes = new byte[len]; for (i = 0, index = 0, offset = 0; i < base32.length(); i++) { lookup = base32.charAt(i) - BASE_CHAR; /* Skip chars outside the lookup table */ if (lookup < 0 || lookup >= lookupTable.length) { continue; } digit = lookupTable[lookup]; /* If this digit is not in the table, ignore it */ if (digit < 0) { continue; } if (index <= 3) { index = (index + 5) % 8; if (index == 0) { bytes[offset] |= digit; offset++; if (offset >= bytes.length) { break; } } else { bytes[offset] |= digit << (8 - index); } } else { index = (index + 5) % 8; bytes[offset] |= (digit >>> index); offset++; if (offset >= bytes.length) { break; } bytes[offset] |= digit << (8 - index); } } return bytes; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy