payDecode function

PayDataModel payDecode(
  1. String qr
)

Decodes a Base32Hex qr string into a PayDataModel.

Throws BysquareDecodeError if the input is malformed, the CRC32 checksum does not match, or the format version is not supported.

Implementation

PayDataModel payDecode(String qr) {
  final bytes = base32hexDecode(qr);

  if (bytes.length < 4) {
    throw const BysquareDecodeError('Input too short');
  }

  final header = decodeHeader(bytes.sublist(0, 2));

  if (header.version > Version.v120) {
    throw BysquareDecodeError(
      'Unsupported version',
      {'version': header.version},
    );
  }

  final payloadLength = bytes[2] | (bytes[3] << 8);
  final lzmaBody = bytes.sublist(4);

  late Uint8List decompressed;
  try {
    decompressed = lzmaDecompress(lzmaBody, payloadLength);
  } catch (e) {
    throw BysquareDecodeError(
      'LZMA decompression failed',
      {'error': e.toString()},
    );
  }

  if (decompressed.length < 4) {
    throw const BysquareDecodeError('Decompressed payload too short');
  }

  final storedChecksum = ByteData.view(
    decompressed.buffer,
    decompressed.offsetInBytes,
    4,
  ).getUint32(0, Endian.little);

  final body = decompressed.sublist(4);
  final decoded = utf8.decode(body);

  final computedChecksum = crc32(decoded);
  if (storedChecksum != computedChecksum) {
    throw BysquareDecodeError(
      'CRC32 checksum mismatch',
      {'stored': storedChecksum, 'computed': computedChecksum},
    );
  }

  return payDeserialize(decoded);
}