decode static method

DecoderResult decode(
  1. Uint8List bytes,
  2. Version version,
  3. ErrorCorrectionLevel? ecLevel,
  4. Map<DecodeHintType, Object>? hints,
)

Implementation

static DecoderResult decode(
  Uint8List bytes,
  Version version,
  ErrorCorrectionLevel? ecLevel,
  Map<DecodeHintType, Object>? hints,
) {
  final bits = BitSource(bytes);
  final result = StringBuilder();
  final byteSegments = <Uint8List>[]; //new ArrayList<>(1);
  int symbolSequence = -1;
  int parityData = -1;
  int symbologyModifier;

  try {
    CharacterSetECI? currentCharacterSetECI;
    bool fc1InEffect = false;
    bool hasFNC1first = false;
    bool hasFNC1second = false;
    late Mode mode;
    do {
      // While still another segment to read...
      if (bits.available() < 4) {
        // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
        mode = Mode.TERMINATOR;
      } else {
        mode = Mode.values[bits.readBits(4)]!; // mode is encoded by 4 bits
      }
      switch (mode) {
        case Mode.TERMINATOR:
          break;
        case Mode.FNC1_FIRST_POSITION:
          hasFNC1first = true; // symbology detection
          // We do little with FNC1 except alter the parsed result a bit according to the spec
          fc1InEffect = true;
          break;
        case Mode.FNC1_SECOND_POSITION:
          hasFNC1second = true; // symbology detection
          // We do little with FNC1 except alter the parsed result a bit according to the spec
          fc1InEffect = true;
          break;
        case Mode.STRUCTURED_APPEND:
          if (bits.available() < 16) {
            throw FormatsException('bits.available < 16');
          }
          // sequence number and parity is added later to the result metadata
          // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
          symbolSequence = bits.readBits(8);
          parityData = bits.readBits(8);
          break;
        case Mode.ECI:
          // Count doesn't apply to ECI
          final value = _parseECIValue(bits);
          currentCharacterSetECI =
              CharacterSetECI.getCharacterSetECIByValue(value);
          if (currentCharacterSetECI == null) {
            throw FormatsException('CharacterSet is null');
          }
          break;
        case Mode.HANZI:
          // First handle Hanzi mode which does not start with character count
          // Chinese mode contains a sub set indicator right after mode indicator
          final subset = bits.readBits(4);
          final countHanzi =
              bits.readBits(mode.getCharacterCountBits(version));
          if (subset == _gbkSubset) {
            _decodeHanziSegment(bits, result, countHanzi);
          }
          break;
        default:
          // "Normal" QR code modes:
          // How many characters will follow, encoded in this mode?
          final count = bits.readBits(mode.getCharacterCountBits(version));
          switch (mode) {
            case Mode.NUMERIC:
              _decodeNumericSegment(bits, result, count);
              break;
            case Mode.ALPHANUMERIC:
              _decodeAlphanumericSegment(bits, result, count, fc1InEffect);
              break;
            case Mode.BYTE:
              _decodeByteSegment(
                bits,
                result,
                count,
                currentCharacterSetECI,
                byteSegments,
                hints,
              );
              break;
            case Mode.KANJI:
              _decodeKanjiSegment(bits, result, count);
              break;
            default:
              throw FormatsException('mode');
          }
          break;
      }
    } while (mode != Mode.TERMINATOR);

    if (currentCharacterSetECI != null) {
      if (hasFNC1first) {
        symbologyModifier = 4;
      } else if (hasFNC1second) {
        symbologyModifier = 6;
      } else {
        symbologyModifier = 2;
      }
    } else {
      if (hasFNC1first) {
        symbologyModifier = 3;
      } else if (hasFNC1second) {
        symbologyModifier = 5;
      } else {
        symbologyModifier = 1;
      }
    }
  } on ArgumentError catch (iae) {
    // on IllegalArgumentException
    // from readBits() calls
    throw FormatsException(iae.toString());
  }

  return DecoderResult(
    bytes,
    result.toString(),
    byteSegments.isEmpty ? null : byteSegments,
    ecLevel?.toString(),
    saSequence: symbolSequence,
    saParity: parityData,
    symbologyModifier: symbologyModifier,
  );
}