Beispiel #1
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);
        }
Beispiel #2
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);
        }
Beispiel #3
0
        /// <summary>
        ///     Вызов метода кодирования для текущего выбранного алгоритма коррекции ошибок
        /// </summary>
        /// <param name="input">Входной поток данных</param>
        /// <param name="output">Выходной поток данных</param>
        public void Forward(Stream input, Stream output)
        {
            int codeSize = _codeSize;
            int dataSize = _dataSize;
            int twoS     = Math.Abs(codeSize - dataSize);

            Debug.Assert(codeSize > dataSize);
            switch (_eccId)
            {
            case EccId.None:
                None.Forward(input, output);
                break;

            case EccId.ReedSolomon:
                var buffer = new byte[Math.Max(codeSize, dataSize)];
                while (input.Read(buffer, 0, dataSize) > 0)
                {
                    int[] array = buffer.Select(x => (int)x).ToArray();
                    RsEncoder.encode(array, twoS);
                    output.Write(array.Select(x => (byte)x).ToArray(), 0, codeSize);
                }
                break;

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #4
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);
            }
        }
        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);
            }
        }
Beispiel #6
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);
        }
Beispiel #7
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));
        }
Beispiel #8
0
        public byte[] Encode(byte[] data, int parity)
        {
            int[] intar = new int[data.Length + parity];
            for (int i = 0; i < data.Length; i++)
            {
                intar[i] = data[i];
            }
            encoder.encode(intar, parity);
            var result = new byte[intar.Length];

            for (int i = 0; i < intar.Length; i++)
            {
                result[i] = (byte)intar[i];
            }
            return(result);
        }
Beispiel #9
0
        public int[] EncodeRawBytesArray(int[] data)
        {
            var length = data.Length * _messageLength / _informationLength;

            length += (255 - (length % 255)) % 255;

            var modifiedData   = new int[length];
            var processedBytes = 0;

            for (var i = 0; i < data.Length; i += _informationLength)
            {
                var tempData = new int[_messageLength];

                var remainder = (data.Length - i < _informationLength) ? data.Length - i : _informationLength;

                for (var j = 0; j < remainder; j++)
                {
                    tempData[j] = data[i + j];
                }

                for (var j = remainder; j < tempData.Length; j++)
                {
                    tempData[j] = 0;
                }

                _reedSolomonEncoder.encode(tempData, _correctionLength);

                remainder = remainder >= _informationLength ? _messageLength : modifiedData.Length - processedBytes;

                for (var j = 0; j < remainder; j++)
                {
                    modifiedData[processedBytes + j] = tempData[j];
                }
                processedBytes += _messageLength;
            }

            return(modifiedData);
        }
Beispiel #10
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);
        }
 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);
    }
 }
Beispiel #13
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
            });
        }