scanChatBase64 function
Validates standard Base64 and counts decoded bytes without decoding it.
Implementation
ChatBase64ScanResult scanChatBase64(
String encoded, {
required int maxDecodedBytes,
required String resource,
}) {
_requirePositiveSafeBudgetInteger(maxDecodedBytes, 'maxDecodedBytes');
final encodedLength = encoded.length;
if (encodedLength % 4 != 0) _throwInvalidBase64();
var decodedBytes = 0;
for (var index = 0; index < encodedLength; index += 4) {
final first = encoded.codeUnitAt(index);
final second = encoded.codeUnitAt(index + 1);
final third = encoded.codeUnitAt(index + 2);
final fourth = encoded.codeUnitAt(index + 3);
final secondValue = _base64SextetValue(second);
if (_base64SextetValue(first) < 0 || secondValue < 0) {
_throwInvalidBase64();
}
final isLastQuartet = index + 4 == encodedLength;
final int quartetBytes;
if (third == 0x3d) {
if (fourth != 0x3d || !isLastQuartet || (secondValue & 0x0f) != 0) {
_throwInvalidBase64();
}
quartetBytes = 1;
} else {
final thirdValue = _base64SextetValue(third);
if (thirdValue < 0) _throwInvalidBase64();
if (fourth == 0x3d) {
if (!isLastQuartet || (thirdValue & 0x03) != 0) _throwInvalidBase64();
quartetBytes = 2;
} else {
if (_base64SextetValue(fourth) < 0) _throwInvalidBase64();
quartetBytes = 3;
}
}
if (quartetBytes > maxDecodedBytes - decodedBytes) {
throw ChatInputLimitExceeded(
resource: resource,
limit: maxDecodedBytes,
observedAtLeast: _safeObservedAtLeast(
decodedBytes,
quartetBytes,
maxDecodedBytes,
),
);
}
decodedBytes += quartetBytes;
}
return ChatBase64ScanResult(encodedLength, decodedBytes);
}