標準庫 `java.util.Base64` (Java 8+) 解碼失敗拋 `IllegalArgumentException`,缺乏錯誤位置資訊。自定義異常攜帶非法字符與位置,便於精準定位資料損壞點。
package com.gootrip.util;
import java.io.IOException;
public class Base64DecodingException extends IOException {
private final char illegalChar;
private final int position;
public Base64DecodingException(String message, char illegalChar, int position) {
super(message);
this.illegalChar = illegalChar;
this.position = position;
}
public char getIllegalChar() { return illegalChar; }
public int getPosition() { return position; }
@Override
public String toString() {
return super.toString() + " | 非法字符: '" + illegalChar + "' (U+" + Integer.toHexString(illegalChar) + ") | 位置: " + position;
}
}
public class StrictBase64Decoder {
private static final byte[] DECODABET = new byte[256]; // -1=非法, -2=填充, >=0=值
static {
// 初始化 DECODABET (略)
}
public static byte[] decode(String s) throws Base64DecodingException {
int len = s.length();
if (len % 4 != 0) throw new Base64DecodingException("長度非 4 倍數", '\0', len);
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i = 0;
while (i < len) {
// 讀取 4 字符
int v0 = charValue(s.charAt(i++));
int v1 = charValue(s.charAt(i++));
int v2 = charValue(s.charAt(i++));
int v3 = charValue(s.charAt(i++));
// 組合 3 位元組
out.write((v0 << 2) | (v1 >> 4));
if (v2 != -2) out.write((v1 << 4) | (v2 >> 2));
if (v3 != -2) out.write((v2 << 6) | v3);
}
return out.toByteArray();
}
private static int charValue(char c) throws Base64DecodingException {
if (c >= DECODABET.length) throw new Base64DecodingException("超出 ASCII 範圍", c, 0);
byte b = DECODABET[c];
if (b < 0 && b != -2) throw new Base64DecodingException("非法 Base64 字符", c, 0);
return b;
}
}
Java 8+ `Base64.getDecoder().decode(str)` 內部已優化,效能極高。若需嚴格錯誤定位,可捕獲 `IllegalArgumentException` 並輔以正則預檢:
if (!str.matches("^[A-Za-z0-9+/]*={0,2}$")) throw new Base64DecodingException(...);