package com.lanremote.watch; /** * 自带的 Base64 实现。 * * 不用 android.util.Base64(桌面 JVM 上没有),也不用 java.util.Base64 * (Android 8.0 / API 26 才提供,手表可能更老)。 * 这样整个协议层保持纯 Java,可在桌面直接联调。 */ public final class B64 { private static final char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); private static final int[] LOOKUP = new int[128]; static { for (int i = 0; i < LOOKUP.length; i++) { LOOKUP[i] = -1; } for (int i = 0; i < ALPHABET.length; i++) { LOOKUP[ALPHABET[i]] = i; } } private B64() { } public static String encode(byte[] data) { if (data == null) { return ""; } StringBuilder sb = new StringBuilder(((data.length + 2) / 3) * 4); int i = 0; while (i + 2 < data.length) { int triple = ((data[i] & 0xFF) << 16) | ((data[i + 1] & 0xFF) << 8) | (data[i + 2] & 0xFF); sb.append(ALPHABET[(triple >>> 18) & 0x3F]); sb.append(ALPHABET[(triple >>> 12) & 0x3F]); sb.append(ALPHABET[(triple >>> 6) & 0x3F]); sb.append(ALPHABET[triple & 0x3F]); i += 3; } int remaining = data.length - i; if (remaining == 1) { int chunk = (data[i] & 0xFF) << 16; sb.append(ALPHABET[(chunk >>> 18) & 0x3F]); sb.append(ALPHABET[(chunk >>> 12) & 0x3F]); sb.append("=="); } else if (remaining == 2) { int chunk = ((data[i] & 0xFF) << 16) | ((data[i + 1] & 0xFF) << 8); sb.append(ALPHABET[(chunk >>> 18) & 0x3F]); sb.append(ALPHABET[(chunk >>> 12) & 0x3F]); sb.append(ALPHABET[(chunk >>> 6) & 0x3F]); sb.append('='); } return sb.toString(); } public static byte[] decode(String text) { if (text == null || text.isEmpty()) { return new byte[0]; } int length = text.length(); while (length > 0 && text.charAt(length - 1) == '=') { length--; } int outLength = (length * 3) / 4; byte[] out = new byte[outLength]; int buffer = 0; int bits = 0; int index = 0; for (int i = 0; i < length; i++) { char c = text.charAt(i); if (c >= 128) { continue; } int value = LOOKUP[c]; if (value < 0) { continue; // 跳过换行/空白等 } buffer = (buffer << 6) | value; bits += 6; if (bits >= 8) { bits -= 8; if (index < outLength) { out[index++] = (byte) ((buffer >>> bits) & 0xFF); } } } if (index == outLength) { return out; } byte[] trimmed = new byte[index]; System.arraycopy(out, 0, trimmed, 0, index); return trimmed; } }