decode static method
DecoderResult
decode(
- Uint8List bytes,
- Version version,
- ErrorCorrectionLevel? ecLevel,
- DecodeHint? hints,
Implementation
static DecoderResult decode(
Uint8List bytes,
Version version,
ErrorCorrectionLevel? ecLevel,
DecodeHint? 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.fnc1FirstPosition:
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.fnc1SecondPosition:
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.structuredAppend:
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,
);
}