internal static DecoderResult decode(byte[] bytes,
Version version,
ErrorCorrectionLevel ecLevel,
IDictionary <DecodeHintType, object> hints)
{
var bits = new BitSource(bytes);
var result = new StringBuilder(50);
var byteSegments = new List <byte[]> (1);
var symbolSequence = -1;
var parityData = -1;
try {
CharacterSetECI currentCharacterSetECI = null;
bool fc1InEffect = false;
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
{
try {
mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits
} catch (ArgumentException) {
return(null);
}
}
if (mode != Mode.TERMINATOR)
{
if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION)
{
// We do little with FNC1 except alter the parsed result a bit according to the spec
fc1InEffect = true;
}
else if (mode == Mode.STRUCTURED_APPEND)
{
if (bits.available() < 16)
{
return(null);
}
// not really supported; but 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);
}
else if (mode == Mode.ECI)
{
// Count doesn't apply to ECI
int value = parseECIValue(bits);
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
if (currentCharacterSetECI == null)
{
return(null);
}
}
else
{
// First handle Hanzi mode which does not start with character count
if (mode == Mode.HANZI)
{
//chinese mode contains a sub set indicator right after mode indicator
int subset = bits.readBits(4);
int countHanzi = bits.readBits(mode.getCharacterCountBits(version));
if (subset == GB2312_SUBSET)
{
if (!decodeHanziSegment(bits, result, countHanzi))
{
return(null);
}
}
}
else
{
// "Normal" QR code modes:
// How many characters will follow, encoded in this mode?
int count = bits.readBits(mode.getCharacterCountBits(version));
if (mode == Mode.NUMERIC)
{
if (!decodeNumericSegment(bits, result, count))
{
return(null);
}
}
else if (mode == Mode.ALPHANUMERIC)
{
if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect))
{
return(null);
}
}
else if (mode == Mode.BYTE)
{
if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints))
{
return(null);
}
}
else if (mode == Mode.KANJI)
{
if (!decodeKanjiSegment(bits, result, count))
{
return(null);
}
}
else
{
return(null);
}
}
}
}
} while (mode != Mode.TERMINATOR);
} catch (ArgumentException) {
// from readBits() calls
return(null);
}
#if WindowsCE
var resultString = result.ToString().Replace("\n", "\r\n");
#else
var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine);
#endif
return(new DecoderResult(bytes,
resultString,
byteSegments.Count == 0 ? null : byteSegments,
ecLevel == null ? null : ecLevel.ToString(),
symbolSequence, parityData));
}