Exemple #1
0
        private static void testEncodeDecodeRandom(GenericGF field, int dataSize, int ecSize)
        {
            Assert.IsTrue(dataSize > 0 && dataSize <= field.Size - 3, "Invalid data size for " + field);
            Assert.IsTrue(ecSize > 0 && ecSize + dataSize <= field.Size, "Invalid ECC size for " + field);
            ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);

            int[]  message    = new int[dataSize + ecSize];
            int[]  dataWords  = new int[dataSize];
            int[]  ecWords    = new int[ecSize];
            Random random     = getPseudoRandom();
            int    iterations = field.Size > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;

            for (int i = 0; i < iterations; i++)
            {
                // generate random data
                for (int k = 0; k < dataSize; k++)
                {
                    dataWords[k] = random.Next(field.Size);
                }
                // generate ECC words
                Array.Copy(dataWords, 0, message, 0, dataWords.Length);
                encoder.encode(message, ecWords.Length);
                Array.Copy(message, dataSize, ecWords, 0, ecSize);
                // check to see if Decoder can fix up to ecWords/2 random errors
                testDecoder(field, dataWords, ecWords);
            }
        }
Exemple #2
0
        public static BitList GenerateCheckWords(BitList bits, int totalBits, int wordSize)
        {
            var rs = new ReedSolomonEncoder(GetGaloisField(wordSize));

            // bits is guaranteed to be a multiple of the wordSize, so no padding needed
            int messageWordCount = bits.Length / wordSize;
            int totalWordCount   = totalBits / wordSize;
            int eccWordCount     = totalWordCount - messageWordCount;

            int[] messageWords = BitsToWords(bits, wordSize, messageWordCount);
            int[] eccWords     = rs.Encode(messageWords, eccWordCount);
            int   startPad     = totalBits % wordSize;

            var messageBits = new BitList();

            messageBits.AddBits(0, (byte)startPad);

            foreach (var messageWord in messageWords)
            {
                messageBits.AddBits((uint)messageWord, (byte)wordSize);
            }

            foreach (var eccWord in eccWords)
            {
                messageBits.AddBits((uint)eccWord, (byte)wordSize);
            }

            return(messageBits);
        }
Exemple #3
0
        private static BitArray generateCheckWords(BitArray bitArray, int totalBits, int wordSize)
        {
            if (bitArray.Size % wordSize != 0)
            {
                throw new InvalidOperationException("size of bit array is not a multiple of the word size");
            }

            // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
            int messageSizeInWords = bitArray.Size / wordSize;

            var rs           = new ReedSolomonEncoder(getGF(wordSize));
            var totalWords   = totalBits / wordSize;
            var messageWords = bitsToWords(bitArray, wordSize, totalWords);

            rs.encode(messageWords, totalWords - messageSizeInWords);

            var startPad    = totalBits % wordSize;
            var messageBits = new BitArray();

            messageBits.appendBits(0, startPad);
            foreach (var messageWord in messageWords)
            {
                messageBits.appendBits(messageWord, wordSize);
            }
            return(messageBits);
        }
        public void testQRCodeVersusDecoder()
        {
            var random  = getRandom();
            var encoder = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256);
            var decoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);

            for (var i = 0; i < 100; i++)
            {
                var size     = 2 + random.Next(254);
                var toEncode = new int[size];
                var ecBytes  = 1 + random.Next(2 * (1 + size / 8));
                ecBytes = Math.Min(ecBytes, size - 1);
                var dataBytes = size - ecBytes;
                for (int j = 0; j < dataBytes; j++)
                {
                    toEncode[j] = random.Next(256);
                }
                var original = new int[dataBytes];
                Array.Copy(toEncode, 0, original, 0, dataBytes);
                encoder.encode(toEncode, ecBytes);
                corrupt(toEncode, ecBytes / 2, random);
                Assert.IsTrue(decoder.decode(toEncode, ecBytes));
                assertArraysEqual(original, 0, toEncode, 0, dataBytes);
            }
        }
Exemple #5
0
        private static BitArray generateCheckWords(BitArray stuffedBits, int totalSymbolBits, int wordSize)
        {
            var messageSizeInWords = (stuffedBits.Size + wordSize - 1) / wordSize;

            for (var i = messageSizeInWords * wordSize - stuffedBits.Size; i > 0; i--)
            {
                stuffedBits.appendBit(true);
            }

            var rs = new ReedSolomonEncoder(getGF(wordSize));
            var totalSizeInFullWords = totalSymbolBits / wordSize;
            var messageWords         = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords);

            rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords);

            var startPad    = totalSymbolBits % wordSize;
            var messageBits = new BitArray();

            messageBits.appendBits(0, startPad);
            foreach (var messageWord in messageWords)
            {
                messageBits.appendBits(messageWord, wordSize);
            }
            return(messageBits);
        }
Exemple #6
0
 public ReedSolomon(GenericGF galoisField, int correctionBytes)
 {
     _messageLength      = galoisField.Size - 1;
     _correctionLength   = correctionBytes;
     _informationLength  = _messageLength - _correctionLength;
     _reedSolomonEncoder = new ReedSolomonEncoder(galoisField);
     _reedSolomonDecoder = new ReedSolomonDecoder(galoisField);
     _simpleRsDecoder    = new SimpleRSDecoder();
 }
Exemple #7
0
        private void TestOneCase(byte[] data, int ecLength, byte[] expectResult)
        {
            byte[] result = ReedSolomonEncoder.Encode(data, ecLength, m_cacheGeneratorPoly);

            if (!PolynomialExtensions.isEqual(result, expectResult))
            {
                Assert.Fail("Remainder not same. result {0}, expect {1}", result.Length, expectResult.Length);
            }
        }
Exemple #8
0
        public ReedSolomon(int correctionBytes)
        {
            var galoisField = GenericGF.DATA_MATRIX_FIELD_256;

            _messageLength      = galoisField.Size - 1;
            _correctionLength   = correctionBytes;
            _informationLength  = _messageLength - _correctionLength;
            _reedSolomonEncoder = new ReedSolomonEncoder(galoisField);
            _reedSolomonDecoder = new ReedSolomonDecoder(galoisField);
            _simpleRsDecoder    = new SimpleRSDecoder();
        }
Exemple #9
0
        private static void testEncoder(GenericGF field, int[] dataWords, int[] ecWords)
        {
            ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);

            int[] messageExpected = new int[dataWords.Length + ecWords.Length];
            int[] message         = new int[dataWords.Length + ecWords.Length];
            Array.Copy(dataWords, 0, messageExpected, 0, dataWords.Length);
            Array.Copy(ecWords, 0, messageExpected, dataWords.Length, ecWords.Length);
            Array.Copy(dataWords, 0, message, 0, dataWords.Length);
            encoder.encode(message, ecWords.Length);
            assertDataEquals("Encode in " + field + " (" + dataWords.Length + ',' + ecWords.Length + ") failed",
                             messageExpected, message);
        }
Exemple #10
0
        public static bool[] MarshallInt(uint value)
        {
            int[] byteArray = new int[32];
            byteArray[0] = (byte)(value % 256);
            byteArray[1] = (byte)((value >> 8) % 256);
            byteArray[2] = (byte)((value >> 16) % 256);
            byteArray[3] = (byte)((value >> 24) % 256);

            ReedSolomonEncoder rse = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256);

            rse.encode(byteArray, 28);

            return(UnpackByteArray(byteArray));
        }
Exemple #11
0
        public void PerformanceTest()
        {
            Random randomizer = new Random();

            sbyte[] zxTestCase = PolynomialExtensions.GenerateSbyteArray(40, randomizer);
            int     ecBytes    = 50;

            byte[] testCase = PolynomialExtensions.ToByteArray(zxTestCase);

            Stopwatch sw          = new Stopwatch();
            int       timesofTest = 10000;

            string[] timeElapsed = new string[2];

            sw.Start();
            GaloisField256      gf256     = GaloisField256.QRCodeGaloisField;
            GeneratorPolynomial generator = new GeneratorPolynomial(gf256);

            for (int i = 0; i < timesofTest; i++)
            {
                ReedSolomonEncoder.Encode(testCase, ecBytes, generator);
            }

            sw.Stop();

            timeElapsed[0] = sw.ElapsedMilliseconds.ToString();

            sw.Reset();

            sw.Start();

            for (int i = 0; i < timesofTest; i++)
            {
                EncoderInternal.generateECBytes(zxTestCase, ecBytes);
            }
            sw.Stop();

            timeElapsed[1] = sw.ElapsedMilliseconds.ToString();


            Assert.Pass("ReedSolomon performance {0} Tests~ QrCode.Net: {1} ZXing: {2}", timesofTest, timeElapsed[0], timeElapsed[1]);
        }
Exemple #12
0
        /// <summary>
        /// Encode using Reed-Solomon error correction (with n bytes added to the end of bits). </summary>
        public static Bits bitsReedSolomonEncode(Bits bits, int n)
        {
            int tmpSize = (bits.size() + 7) / 8 + n;

            int[] data = new int[tmpSize];
            if (tmpSize > bits.Bytes.Length)
            {
                tmpSize = bits.Bytes.Length;
            }
            Array.Copy(bits.Bytes, 0, data, 0, tmpSize);

            ReedSolomonEncoder enc = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256);

            enc.encode(data, n);

            Bits result = new Bits(bits);

            for (int i = data.Length - n; i < data.Length; i++)
            {
                result.addValue(data[i], 8);
            }
            return(result);
        }
Exemple #13
0
        /// <summary>
        /// Generate error correction blocks. Then out put with codewords BitList
        /// ISO/IEC 18004/2006 P45, 46. Chapter 6.6 Constructing final message codewords sequence.
        /// </summary>
        /// <param name="dataCodewords">Datacodewords from DataEncodation.DataEncode</param>
        /// <param name="numTotalBytes">Total number of bytes</param>
        /// <param name="numDataBytes">Number of data bytes</param>
        /// <param name="numECBlocks">Number of Error Correction blocks</param>
        /// <returns>codewords BitList contain datacodewords and ECCodewords</returns>
        internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd)
        {
            List <byte> dataCodewordsByte  = dataCodewords.List;
            int         ecBlockGroup2      = vd.ECBlockGroup2;
            int         ecBlockGroup1      = vd.ECBlockGroup1;
            int         numDataBytesGroup1 = vd.NumDataBytesGroup1;
            int         numDataBytesGroup2 = vd.NumDataBytesGroup2;

            int ecBytesPerBlock = vd.NumECBytesPerBlock;

            int dataBytesOffset = 0;

            byte[][] dByteJArray  = new byte[vd.NumECBlocks][];
            byte[][] ecByteJArray = new byte[vd.NumECBlocks][];

            GaloisField256      gf256     = GaloisField256.QRCodeGaloisField;
            GeneratorPolynomial generator = new GeneratorPolynomial(gf256);

            for (int blockID = 0; blockID < vd.NumECBlocks; blockID++)
            {
                if (blockID < ecBlockGroup1)
                {
                    dByteJArray[blockID] = new byte[numDataBytesGroup1];
                    for (int index = 0; index < numDataBytesGroup1; index++)
                    {
                        dByteJArray[blockID][index] = dataCodewordsByte[dataBytesOffset + index];
                    }
                    dataBytesOffset += numDataBytesGroup1;
                }
                else
                {
                    dByteJArray[blockID] = new byte[numDataBytesGroup2];
                    for (int index = 0; index < numDataBytesGroup2; index++)
                    {
                        dByteJArray[blockID][index] = dataCodewordsByte[dataBytesOffset + index];
                    }
                    dataBytesOffset += numDataBytesGroup2;
                }

                ecByteJArray[blockID] = ReedSolomonEncoder.Encode(dByteJArray[blockID], ecBytesPerBlock, generator);
            }
            if (vd.NumDataBytes != dataBytesOffset)
            {
                throw new ArgumentException("Data bytes does not match offset");
            }

            BitList codewords = new BitList();

            int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2;

            for (int dataID = 0; dataID < maxDataLength; dataID++)
            {
                for (int blockID = 0; blockID < vd.NumECBlocks; blockID++)
                {
                    if (!(dataID == numDataBytesGroup1 && blockID < ecBlockGroup1))
                    {
                        codewords.Add((int)dByteJArray[blockID][dataID], 8);
                    }
                }
            }

            for (int ECID = 0; ECID < ecBytesPerBlock; ECID++)
            {
                for (int blockID = 0; blockID < vd.NumECBlocks; blockID++)
                {
                    codewords.Add((int)ecByteJArray[blockID][ECID], 8);
                }
            }

            if (vd.NumTotalBytes != codewords.Count >> 3)
            {
                throw new ArgumentException(string.Format("total bytes: {0}, actual bits: {1}", vd.NumTotalBytes, codewords.Count));
            }

            return(codewords);
        }
 private static void testEncoder(GenericGF field, int[] dataWords, int[] ecWords)
 {
    ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);
    int[] messageExpected = new int[dataWords.Length + ecWords.Length];
    int[] message = new int[dataWords.Length + ecWords.Length];
    Array.Copy(dataWords, 0, messageExpected, 0, dataWords.Length);
    Array.Copy(ecWords, 0, messageExpected, dataWords.Length, ecWords.Length);
    Array.Copy(dataWords, 0, message, 0, dataWords.Length);
    encoder.encode(message, ecWords.Length);
    assertDataEquals("Encode in " + field + " (" + dataWords.Length + ',' + ecWords.Length + ") failed",
                     messageExpected, message);
 }
 private static void testEncodeDecodeRandom(GenericGF field, int dataSize, int ecSize)
 {
    Assert.IsTrue(dataSize > 0 && dataSize <= field.Size - 3, "Invalid data size for " + field);
    Assert.IsTrue(ecSize > 0 && ecSize + dataSize <= field.Size, "Invalid ECC size for " + field);
    ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);
    int[] message = new int[dataSize + ecSize];
    int[] dataWords = new int[dataSize];
    int[] ecWords = new int[ecSize];
    Random random = getPseudoRandom();
    int iterations = field.Size > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;
    for (int i = 0; i < iterations; i++)
    {
       // generate random data
       for (int k = 0; k < dataSize; k++)
       {
          dataWords[k] = random.Next(field.Size);
       }
       // generate ECC words
       Array.Copy(dataWords, 0, message, 0, dataWords.Length);
       encoder.encode(message, ecWords.Length);
       Array.Copy(message, dataSize, ecWords, 0, ecSize);
       // check to see if Decoder can fix up to ecWords/2 random errors
       testDecoder(field, dataWords, ecWords);
    }
 }
Exemple #16
0
 public ReedSolomon()
 {
     field   = GenericGF.DATA_MATRIX_FIELD_256;
     encoder = new ReedSolomonEncoder(field);
     decoder = new ReedSolomonDecoder(field);
 }
Exemple #17
0
        public void Encode(int[] plainData, int erasures)
        {
            var rse = new ReedSolomonEncoder(_field);

            rse.Encode(plainData, erasures);
        }
Exemple #18
0
        /// <summary>
        /// Encodes the given binary content as an Aztec symbol
        /// </summary>
        /// <param name="data">input data string</param>
        /// <param name="minECCPercent">minimal percentange of error check words (According to ISO/IEC 24778:2008,
        /// a minimum of 23% + 3 words is recommended)</param>
        /// <returns>Aztec symbol matrix with metadata</returns>
        public static AztecCode encode(byte[] data, int minECCPercent)
        {
            // High-level encode
            var bits = highLevelEncode(data);

            // stuff bits and choose symbol size
            int      eccBits       = bits.Size * minECCPercent / 100 + 11;
            int      totalSizeBits = bits.Size + eccBits;
            int      layers;
            int      wordSize        = 0;
            int      totalSymbolBits = 0;
            BitArray stuffedBits     = null;

            for (layers = 1; layers < NB_BITS_COMPACT.Length; layers++)
            {
                if (NB_BITS_COMPACT[layers] >= totalSizeBits)
                {
                    if (wordSize != WORD_SIZE[layers])
                    {
                        wordSize    = WORD_SIZE[layers];
                        stuffedBits = stuffBits(bits, wordSize);
                    }
                    totalSymbolBits = NB_BITS_COMPACT[layers];
                    if (stuffedBits.Size + eccBits <= NB_BITS_COMPACT[layers])
                    {
                        break;
                    }
                }
            }
            bool compact = true;

            if (layers == NB_BITS_COMPACT.Length)
            {
                compact = false;
                for (layers = 1; layers < NB_BITS.Length; layers++)
                {
                    if (NB_BITS[layers] >= totalSizeBits)
                    {
                        if (wordSize != WORD_SIZE[layers])
                        {
                            wordSize    = WORD_SIZE[layers];
                            stuffedBits = stuffBits(bits, wordSize);
                        }
                        totalSymbolBits = NB_BITS[layers];
                        if (stuffedBits.Size + eccBits <= NB_BITS[layers])
                        {
                            break;
                        }
                    }
                }
            }
            if (layers == NB_BITS.Length)
            {
                throw new ArgumentException("Data too large for an Aztec code");
            }

            // pad the end
            int messageSizeInWords = (stuffedBits.Size + wordSize - 1) / wordSize;

            for (int i = messageSizeInWords * wordSize - stuffedBits.Size; i > 0; i--)
            {
                stuffedBits.appendBit(true);
            }

            // generate check words
            var rs = new ReedSolomonEncoder(getGF(wordSize));
            var totalSizeInFullWords = totalSymbolBits / wordSize;
            var messageWords         = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords);

            rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords);

            // convert to bit array and pad in the beginning
            var startPad    = totalSymbolBits % wordSize;
            var messageBits = new BitArray();

            messageBits.appendBits(0, startPad);
            foreach (var messageWord in messageWords)
            {
                messageBits.appendBits(messageWord, wordSize);
            }

            // generate mode message
            var modeMessage = generateModeMessage(compact, layers, messageSizeInWords);

            // allocate symbol
            var baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines
            var alignmentMap   = new int[baseMatrixSize];
            int matrixSize;

            if (compact)
            {
                // no alignment marks in compact mode, alignmentMap is a no-op
                matrixSize = baseMatrixSize;
                for (int i = 0; i < alignmentMap.Length; i++)
                {
                    alignmentMap[i] = i;
                }
            }
            else
            {
                matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
                int origCenter = baseMatrixSize / 2;
                int center     = matrixSize / 2;
                for (int i = 0; i < origCenter; i++)
                {
                    int newOffset = i + i / 15;
                    alignmentMap[origCenter - i - 1] = center - newOffset - 1;
                    alignmentMap[origCenter + i]     = center + newOffset + 1;
                }
            }
            var matrix = new BitMatrix(matrixSize);

            // draw mode and data bits
            for (int i = 0, rowOffset = 0; i < layers; i++)
            {
                int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12;
                for (int j = 0; j < rowSize; j++)
                {
                    int columnOffset = j * 2;
                    for (int k = 0; k < 2; k++)
                    {
                        if (messageBits[rowOffset + columnOffset + k])
                        {
                            matrix[alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 2 + columnOffset + k])
                        {
                            matrix[alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 4 + columnOffset + k])
                        {
                            matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 6 + columnOffset + k])
                        {
                            matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]] = true;
                        }
                    }
                }
                rowOffset += rowSize * 8;
            }
            drawModeMessage(matrix, compact, matrixSize, modeMessage);

            // draw alignment marks
            if (compact)
            {
                drawBullsEye(matrix, matrixSize / 2, 5);
            }
            else
            {
                drawBullsEye(matrix, matrixSize / 2, 7);
                for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16)
                {
                    for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2)
                    {
                        matrix[matrixSize / 2 - j, k] = true;
                        matrix[matrixSize / 2 + j, k] = true;
                        matrix[k, matrixSize / 2 - j] = true;
                        matrix[k, matrixSize / 2 + j] = true;
                    }
                }
            }

            return(new AztecCode
            {
                isCompact = compact,
                Size = matrixSize,
                Layers = layers,
                CodeWords = messageSizeInWords,
                Matrix = matrix
            });
        }