private static bool DecodeNumericSegment(BitSource bits,
                                                 StringBuilder result,
                                                 int count)
        {
            // Read three digits at a time
            while (count >= 3)
            {
                // Each 10 bits encodes three digits
                if (bits.Available() < 10)
                {
                    return(false);
                }
                int threeDigitsBits = bits.ReadBits(10);
                if (threeDigitsBits >= 1000)
                {
                    return(false);
                }
                result.Append(ToAlphaNumericChar(threeDigitsBits / 100));
                result.Append(ToAlphaNumericChar((threeDigitsBits / 10) % 10));
                result.Append(ToAlphaNumericChar(threeDigitsBits % 10));

                count -= 3;
            }
            if (count == 2)
            {
                // Two digits left over to read, encoded in 7 bits
                if (bits.Available() < 7)
                {
                    return(false);
                }
                int twoDigitsBits = bits.ReadBits(7);
                if (twoDigitsBits >= 100)
                {
                    return(false);
                }
                result.Append(ToAlphaNumericChar(twoDigitsBits / 10));
                result.Append(ToAlphaNumericChar(twoDigitsBits % 10));
            }
            else if (count == 1)
            {
                // One digit left over to read
                if (bits.Available() < 4)
                {
                    return(false);
                }
                int digitBits = bits.ReadBits(4);
                if (digitBits >= 10)
                {
                    return(false);
                }
                result.Append(ToAlphaNumericChar(digitBits));
            }

            return(true);
        }
        private static bool DecodeAlphanumericSegment(BitSource bits,
                                                      StringBuilder result,
                                                      int count,
                                                      bool fc1InEffect)
        {
            // Read two characters at a time
            int start = result.Length;

            while (count > 1)
            {
                if (bits.Available() < 11)
                {
                    return(false);
                }
                int nextTwoCharsBits = bits.ReadBits(11);
                result.Append(ToAlphaNumericChar(nextTwoCharsBits / 45));
                result.Append(ToAlphaNumericChar(nextTwoCharsBits % 45));
                count -= 2;
            }
            if (count == 1)
            {
                // special case: one character left
                if (bits.Available() < 6)
                {
                    return(false);
                }
                result.Append(ToAlphaNumericChar(bits.ReadBits(6)));
            }

            // See section 6.4.8.1, 6.4.8.2
            if (fc1InEffect)
            {
                // We need to massage the result a bit if in an FNC1 mode:
                for (int i = start; i < result.Length; i++)
                {
                    if (result[i] == '%')
                    {
                        if (i < result.Length - 1 && result[i + 1] == '%')
                        {
                            // %% is rendered as %
                            result.Remove(i + 1, 1);
                        }
                        else
                        {
                            // In alpha mode, % should be converted to FNC1 separator 0x1D
                            result.Remove(i, 1);
                            result.Insert(i, new[] { (char)0x1D });
                        }
                    }
                }
            }

            return(true);
        }
        private static bool DecodeKanjiSegment(BitSource bits,
                                               StringBuilder result,
                                               int count)
        {
            // Don't crash trying to read more bits than we have available.
            if (count * 13 > bits.Available())
            {
                return(false);
            }

            // Each character will require 2 bytes. Read the characters as 2-byte pairs
            // and decode as Shift_JIS afterwards
            byte[] buffer = new byte[2 * count];
            int    offset = 0;

            while (count > 0)
            {
                // Each 13 bits encodes a 2-byte character
                int twoBytes          = bits.ReadBits(13);
                int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
                if (assembledTwoBytes < 0x01F00)
                {
                    // In the 0x8140 to 0x9FFC range
                    assembledTwoBytes += 0x08140;
                }
                else
                {
                    // In the 0xE040 to 0xEBBF range
                    assembledTwoBytes += 0x0C140;
                }
                buffer[offset]     = (byte)(assembledTwoBytes >> 8);
                buffer[offset + 1] = (byte)assembledTwoBytes;
                offset            += 2;
                count--;
            }
            // Shift_JIS may not be supported in some environments:
            try
            {
                result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length));
            }
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH)
            catch (ArgumentException)
            {
                try
                {
                    // Silverlight only supports a limited number of character sets, trying fallback to UTF-8
                    result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
                }
                catch (Exception)
                {
                    return(false);
                }
            }
#endif
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
示例#4
0
        private static void DecodeByteSegment(BitSource bits, StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, System.Collections.ArrayList byteSegments)
        {
            sbyte[] readBytes = new sbyte[count];
            if (count << 3 > bits.Available())
            {
                throw ReaderException.Instance;
            }
            for (int i = 0; i < count; i++)
            {
                readBytes[i] = (sbyte)bits.ReadBits(8);
            }

            // The spec isn't clear on this mode; see
            // section 6.4.5: t does not say which encoding to assuming
            // upon decoding. I have seen ISO-8859-1 used as well as
            // Shift_JIS -- without anything like an ECI designator to
            // give a hint.
            var encoding = currentCharacterSetECI == null?GuessEncoding(readBytes) : currentCharacterSetECI.EncodingName;

            try
            {
                //UPGRADE_TODO: The differences in the Format  of parameters for constructor 'java.lang.String.String'  may cause compilation errors.  "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"
                result.Append(Encoding.GetEncoding(encoding).GetString(SupportClass.ToByteArray(readBytes)));
            }
            catch (IOException)
            {
                throw ReaderException.Instance;
            }
            byteSegments.Add(SupportClass.ToByteArray(readBytes));
        }
        /// <summary>
        /// See specification GBT 18284-2000
        /// </summary>
        /// <param name="bits">The bits.</param>
        /// <param name="result">The result.</param>
        /// <param name="count">The count.</param>
        /// <returns></returns>
        private static bool DecodeHanziSegment(BitSource bits,
                                               StringBuilder result,
                                               int count)
        {
            // Don't crash trying to read more bits than we have available.
            if (count * 13 > bits.Available())
            {
                return(false);
            }

            // Each character will require 2 bytes. Read the characters as 2-byte pairs
            // and decode as GB2312 afterwards
            byte[] buffer = new byte[2 * count];
            int    offset = 0;

            while (count > 0)
            {
                // Each 13 bits encodes a 2-byte character
                int twoBytes          = bits.ReadBits(13);
                int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
                if (assembledTwoBytes < 0x003BF)
                {
                    // In the 0xA1A1 to 0xAAFE range
                    assembledTwoBytes += 0x0A1A1;
                }
                else
                {
                    // In the 0xB0A1 to 0xFAFE range
                    assembledTwoBytes += 0x0A6A1;
                }
                buffer[offset]     = (byte)((assembledTwoBytes >> 8) & 0xFF);
                buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF);
                offset            += 2;
                count--;
            }

            try
            {
                result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length));
            }
            catch (ArgumentException)
            {
                try
                {
                    // Silverlight only supports a limited number of character sets, trying fallback to UTF-8
                    result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length));
                }
                catch (Exception)
                {
                    return(false);
                }
            }
            catch (Exception)
            {
                return(false);
            }

            return(true);
        }
        private static bool DecodeByteSegment(BitSource bits,
                                              StringBuilder result,
                                              int count,
                                              CharacterSetECI currentCharacterSetECI,
                                              IList <byte[]> byteSegments)
        {
            // Don't crash trying to read more bits than we have available.
            if (count << 3 > bits.Available())
            {
                return(false);
            }

            byte[] readBytes = new byte[count];
            for (int i = 0; i < count; i++)
            {
                readBytes[i] = (byte)bits.ReadBits(8);
            }
            String encoding;

            if (currentCharacterSetECI == null)
            {
                // The spec isn't clear on this mode; see
                // section 6.4.5: t does not say which encoding to assuming
                // upon decoding. I have seen ISO-8859-1 used as well as
                // Shift_JIS -- without anything like an ECI designator to
                // give a hint.
                encoding = StringUtils.GuessEncoding(readBytes);
            }
            else
            {
                encoding = currentCharacterSetECI.EncodingName;
            }
            try
            {
                result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length));
            }
            catch (ArgumentException)
            {
                try
                {
                    // Silverlight only supports a limited number of character sets, trying fallback to UTF-8
                    result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length));
                }
                catch (Exception)
                {
                    return(false);
                }
            }
            catch (Exception)
            {
                return(false);
            }
            byteSegments.Add(readBytes);

            return(true);
        }
        internal static DecoderResult Decode(byte[] bytes,
                                             Version version,
                                             ErrorCorrectionLevel ecLevel)
        {
            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);
                        }
                    }
                    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))
                            {
                                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);
            }

            var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine);

            return(new DecoderResult(bytes, resultString));
        }
示例#8
0
        internal static DecoderResult Decode(sbyte[] bytes, Version version, ErrorCorrectionLevel ecLevel)
        {
            BitSource       bits   = new BitSource(bytes);
            StringBuilder   result = new StringBuilder(50);
            CharacterSetECI currentCharacterSetECI = null;
            bool            fc1InEffect            = false;

            System.Collections.ArrayList byteSegments = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(1));
            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)
                    {
                        throw ReaderException.Instance;
                    }
                }
                if (!mode.Equals(Mode.TERMINATOR))
                {
                    if (mode.Equals(Mode.FNC1_FIRST_POSITION) || mode.Equals(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.Equals(Mode.STRUCTURED_APPEND))
                    {
                        // not really supported; all we do is ignore it
                        // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
                        bits.ReadBits(16);
                    }
                    else if (mode.Equals(Mode.ECI))
                    {
                        // Count doesn't apply to ECI
                        int value_Renamed = ParseECIValue(bits);
                        currentCharacterSetECI = CharacterSetECI.GetCharacterSetECIByValue(value_Renamed);
                        if (currentCharacterSetECI == null)
                        {
                            throw ReaderException.Instance;
                        }
                    }
                    else
                    {
                        // How many characters will follow, encoded in this mode?
                        int count = bits.ReadBits(mode.GetCharacterCountBits(version));
                        if (mode.Equals(Mode.NUMERIC))
                        {
                            DecodeNumericSegment(bits, result, count);
                        }
                        else if (mode.Equals(Mode.ALPHANUMERIC))
                        {
                            DecodeAlphanumericSegment(bits, result, count, fc1InEffect);
                        }
                        else if (mode.Equals(Mode.BYTE))
                        {
                            DecodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments);
                        }
                        else if (mode.Equals(Mode.KANJI))
                        {
                            DecodeKanjiSegment(bits, result, count);
                        }
                        else
                        {
                            throw ReaderException.Instance;
                        }
                    }
                }
            }while (!mode.Equals(Mode.TERMINATOR));

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