scanChatBase64 function

ChatBase64ScanResult scanChatBase64(
  1. String encoded, {
  2. required int maxDecodedBytes,
  3. required String resource,
})

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);
}