Пример #1
0
        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
                            hints[DecodeHintType.VERSION] = mode;
                        }
                        catch (ArgumentException)
                        {
                            return(null);
                        }
                    }
                    switch (mode.Name)
                    {
                    case Mode.Names.TERMINATOR:
                        break;

                    case Mode.Names.FNC1_FIRST_POSITION:
                    case Mode.Names.FNC1_SECOND_POSITION:
                        // We do little with FNC1 except alter the parsed result a bit according to the spec
                        fc1InEffect = true;
                        break;

                    case Mode.Names.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);
                        break;

                    case Mode.Names.ECI:
                        // Count doesn't apply to ECI
                        int value = parseECIValue(bits);
                        currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value);
                        if (currentCharacterSetECI == null)
                        {
                            return(null);
                        }
                        break;

                    case Mode.Names.HANZI:
                        // First handle Hanzi mode which does not start with character count
                        //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);
                            }
                        }
                        break;

                    default:
                        // "Normal" QR code modes:
                        // How many characters will follow, encoded in this mode?
                        int count = bits.readBits(mode.GetCharacterCountBits(version));
                        switch (mode.Name)
                        {
                        case Mode.Names.NUMERIC:
                            if (!decodeNumericSegment(bits, result, count))
                            {
                                return(null);
                            }
                            break;

                        case Mode.Names.ALPHANUMERIC:
                            if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect))
                            {
                                return(null);
                            }
                            break;

                        case Mode.Names.BYTE:
                            if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints))
                            {
                                return(null);
                            }
                            break;

                        case Mode.Names.KANJI:
                            if (!decodeKanjiSegment(bits, result, count))
                            {
                                return(null);
                            }
                            break;

                        default:
                            return(null);
                        }
                        break;
                    }
                } while (mode != Mode.TERMINATOR);
            }
            catch (ArgumentException)
            {
                // from readBits() calls
                return(null);
            }

            return(new DecoderResult(bytes,
                                     result.ToString(),
                                     byteSegments.Count == 0 ? null : byteSegments,
                                     ecLevel == null ? null : ecLevel.ToString(),
                                     symbolSequence, parityData));
        }