openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
86 lines (85 loc) • 3.19 kB
JavaScript
//#region packages/media-core/src/base64.ts
/** Estimates decoded bytes without allocating a cleaned copy of the base64 payload. */
function estimateBase64DecodedBytes(base64) {
let effectiveLen = base64.length;
const firstWhitespace = base64.search(/[\x00-\x20]/);
if (firstWhitespace !== -1) {
for (let i = firstWhitespace; i < base64.length; i += 1) if (base64.charCodeAt(i) <= 32) effectiveLen -= 1;
}
if (effectiveLen === 0) return 0;
let padding = 0;
let end = base64.length - 1;
while (end >= 0 && base64.charCodeAt(end) <= 32) end -= 1;
if (end >= 0 && base64[end] === "=") {
padding = 1;
end -= 1;
while (end >= 0 && base64.charCodeAt(end) <= 32) end -= 1;
if (end >= 0 && base64[end] === "=") padding = 2;
}
const estimated = Math.floor(effectiveLen * 3 / 4) - padding;
return Math.max(0, estimated);
}
/** Validates the attachment dialect: padded, no whitespace, nonzero pad bits allowed. */
function isValidBase64(value) {
return inspectBase64(value, "attachment") !== void 0;
}
function base64DataValue(code) {
if (code >= 65 && code <= 90) return code - 65;
if (code >= 97 && code <= 122) return code - 97 + 26;
if (code >= 48 && code <= 57) return code - 48 + 52;
return code === 43 ? 62 : code === 47 ? 63 : -1;
}
/**
* Normalizes and validates a base64 string, returning canonical no-whitespace
* base64 only when the input has valid alphabet, padding, and length.
*/
function canonicalizeBase64(base64) {
const facts = inspectBase64(base64, "canonical");
return facts?.canonicalPadBits ? facts.base64 : void 0;
}
/** One validating pass for the canonical and strict attachment dialects. */
function inspectBase64(base64, dialect) {
if (dialect === "attachment" && (base64.length === 0 || base64.length % 4 !== 0)) return;
let out;
let outLen = 0;
let padding = 0;
let lastDataValue = 0;
for (let i = 0; i < base64.length; i += 1) {
const code = base64.charCodeAt(i);
if (code <= 32) {
if (dialect === "attachment") return;
if (out === void 0) {
out = Buffer.allocUnsafe(base64.length - 1);
for (let j = 0; j < i; j += 1) out[j] = base64.charCodeAt(j);
outLen = i;
}
continue;
}
if (code === 61) {
padding += 1;
if (padding > 2) return;
} else {
const value = base64DataValue(code);
if (padding > 0 || value < 0) return;
lastDataValue = value;
}
if (out !== void 0) {
out[outLen] = code;
outLen += 1;
}
}
const cleanedLength = out === void 0 ? base64.length : outLen;
if (cleanedLength === 0) return;
const remainder = cleanedLength % 4;
if (remainder !== 0 && (padding > 0 || remainder === 1)) return;
const effectivePadding = remainder === 0 ? padding : 4 - remainder;
const padBitMask = effectivePadding === 2 ? 15 : effectivePadding === 1 ? 3 : 0;
const cleaned = out === void 0 ? base64 : out.subarray(0, outLen).toString("latin1");
return {
base64: remainder === 0 ? cleaned : cleaned + "=".repeat(4 - remainder),
decodedBytes: Math.floor(cleanedLength * 3 / 4) - padding,
canonicalPadBits: (lastDataValue & padBitMask) === 0
};
}
//#endregion
export { isValidBase64 as i, estimateBase64DecodedBytes as n, inspectBase64 as r, canonicalizeBase64 as t };