readData function

QrContent? readData(
  1. Uint8ClampedList data,
  2. int version
)

Reads the content of QR code encoded data, according to its version.

Implementation

QrContent? readData(Uint8ClampedList data, int version) {
  final stream = _BitStream(data);

  // There are 3 'sizes' based on the version. 1-9 is small (0), 10-26 is medium (1) and 27-40 is large (2).
  final size = version <= 9
      ? 0
      : version <= 26
          ? 1
          : 2;

  String text = "";
  List<int> bytes = [];
  List<Chunk> chunks = [];

  while (stream.available() >= 4) {
    final mode = stream.readBits(4);
    if (mode == _modeByteIndex[_ModeByte.terminator]) {
      return QrContent(
        text: text,
        bytes: bytes,
        chunks: chunks,
        version: version,
      );
    } else if (mode == _modeByteIndex[_ModeByte.eci]) {
      if (stream.readBits(1) == 0) {
        chunks.add(Chunk(
          type: ChunkMode.eci,
          assignmentNumber: stream.readBits(7),
        ));
      } else if (stream.readBits(1) == 0) {
        chunks.add(Chunk(
          type: ChunkMode.eci,
          assignmentNumber: stream.readBits(14),
        ));
      } else if (stream.readBits(1) == 0) {
        chunks.add(Chunk(
          type: ChunkMode.eci,
          assignmentNumber: stream.readBits(21),
        ));
      } else {
        // ECI data seems corrupted
        chunks.add(Chunk(
          type: ChunkMode.eci,
          assignmentNumber: -1,
        ));
      }
    } else if (mode == _modeByteIndex[_ModeByte.numeric]) {
      final numericResult = decodeNumeric(stream, size);
      text += numericResult.text;
      bytes.addAll(numericResult.bytes);
      chunks.add(Chunk(
        type: ChunkMode.numeric,
        text: numericResult.text,
      ));
    } else if (mode == _modeByteIndex[_ModeByte.alphanumeric]) {
      final alphanumericResult = _decodeAlphanumeric(stream, size);
      text += alphanumericResult.text;
      bytes.addAll(alphanumericResult.bytes);
      chunks.add(Chunk(
        type: ChunkMode.alphanumeric,
        text: alphanumericResult.text,
      ));
    } else if (mode == _modeByteIndex[_ModeByte.byte]) {
      final byteResult = _decodeByte(stream, size);
      text += byteResult.text;
      bytes.addAll(byteResult.bytes);
      chunks.add(
        Chunk(
          type: ChunkMode.byte,
          bytes: byteResult.bytes,
          text: byteResult.text,
        ),
      );
    } else if (mode == _modeByteIndex[_ModeByte.kanji]) {
      final kanjiResult = _decodeKanji(stream, size);
      text += kanjiResult.text;
      bytes.addAll(kanjiResult.bytes);
      chunks.add(Chunk(
        type: ChunkMode.kanji,
        bytes: kanjiResult.bytes,
        text: kanjiResult.text,
      ));
    }
  }

  // If there is no data left, or the remaining bits are all 0, then that counts as a termination marker
  if (stream.available() == 0 || stream.readBits(stream.available()) == 0) {
    return QrContent(
      text: text,
      bytes: bytes,
      chunks: chunks,
      version: version,
    );
  }
  return null;
}