internal virtual int[] correctDataBlocks(int[] blocks)
        {
            int numCorrections = 0;
            int dataCapacity   = qrCodeSymbol.DataCapacity;

            int[] dataBlocks             = new int[dataCapacity];
            int   numErrorCollectionCode = qrCodeSymbol.NumErrorCollectionCode;
            int   numRSBlocks            = qrCodeSymbol.NumRSBlocks;
            int   eccPerRSBlock          = numErrorCollectionCode / numRSBlocks;

            if (numRSBlocks == 1)
            {
                ReedSolomon corrector = new ReedSolomon(blocks, eccPerRSBlock);
                corrector.correct();
                numCorrections += corrector.NumCorrectedErrors;
                if (numCorrections > 0)
                {
                    canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
                }
                else
                {
                    canvas.println("No errors found.");
                }
                numLastCorrections  = numCorrections;
                correctionSucceeded = corrector.CorrectionSucceeded;
                return(blocks);
            }
            else
            {
                //we have to interleave data blocks because symbol has 2 or more RS blocks
                int numLongerRSBlocks = dataCapacity % numRSBlocks;
                if (numLongerRSBlocks == 0)
                {
                    //symbol has only 1 type of RS block
                    int     lengthRSBlock = dataCapacity / numRSBlocks;
                    int[][] tmpArray      = new int[numRSBlocks][];
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        tmpArray[i] = new int[lengthRSBlock];
                    }
                    int[][] RSBlocks = tmpArray;
                    //obtain RS blocks
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        for (int j = 0; j < lengthRSBlock; j++)
                        {
                            RSBlocks[i][j] = blocks[j * numRSBlocks + i];
                        }
                        ReedSolomon corrector = new ReedSolomon(RSBlocks[i], eccPerRSBlock);
                        corrector.correct();
                        numCorrections     += corrector.NumCorrectedErrors;
                        correctionSucceeded = corrector.CorrectionSucceeded;
                    }
                    //obtain only data part
                    int p = 0;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        for (int j = 0; j < lengthRSBlock - eccPerRSBlock; j++)
                        {
                            dataBlocks[p++] = RSBlocks[i][j];
                        }
                    }
                }
                else
                {
                    //symbol has 2 types of RS blocks
                    int     lengthShorterRSBlock = dataCapacity / numRSBlocks;
                    int     lengthLongerRSBlock  = dataCapacity / numRSBlocks + 1;
                    int     numShorterRSBlocks   = numRSBlocks - numLongerRSBlocks;
                    int[][] tmpArray2            = new int[numShorterRSBlocks][];
                    for (int i2 = 0; i2 < numShorterRSBlocks; i2++)
                    {
                        tmpArray2[i2] = new int[lengthShorterRSBlock];
                    }
                    int[][] shorterRSBlocks = tmpArray2;
                    int[][] tmpArray3       = new int[numLongerRSBlocks][];
                    for (int i3 = 0; i3 < numLongerRSBlocks; i3++)
                    {
                        tmpArray3[i3] = new int[lengthLongerRSBlock];
                    }
                    int[][] longerRSBlocks = tmpArray3;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        if (i < numShorterRSBlocks)
                        {
                            //get shorter RS Block(s)
                            int mod = 0;
                            for (int j = 0; j < lengthShorterRSBlock; j++)
                            {
                                if (j == lengthShorterRSBlock - eccPerRSBlock)
                                {
                                    mod = numLongerRSBlocks;
                                }
                                shorterRSBlocks[i][j] = blocks[j * numRSBlocks + i + mod];
                            }
                            ReedSolomon corrector = new ReedSolomon(shorterRSBlocks[i], eccPerRSBlock);
                            corrector.correct();
                            numCorrections     += corrector.NumCorrectedErrors;
                            correctionSucceeded = corrector.CorrectionSucceeded;
                        }
                        else
                        {
                            //get longer RS Blocks
                            int mod = 0;
                            for (int j = 0; j < lengthLongerRSBlock; j++)
                            {
                                if (j == lengthShorterRSBlock - eccPerRSBlock)
                                {
                                    mod = numShorterRSBlocks;
                                }
                                longerRSBlocks[i - numShorterRSBlocks][j] = blocks[j * numRSBlocks + i - mod];
                            }

                            ReedSolomon corrector = new ReedSolomon(longerRSBlocks[i - numShorterRSBlocks], eccPerRSBlock);
                            corrector.correct();
                            numCorrections     += corrector.NumCorrectedErrors;
                            correctionSucceeded = corrector.CorrectionSucceeded;
                        }
                    }
                    int p = 0;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        if (i < numShorterRSBlocks)
                        {
                            for (int j = 0; j < lengthShorterRSBlock - eccPerRSBlock; j++)
                            {
                                dataBlocks[p++] = shorterRSBlocks[i][j];
                            }
                        }
                        else
                        {
                            for (int j = 0; j < lengthLongerRSBlock - eccPerRSBlock; j++)
                            {
                                dataBlocks[p++] = longerRSBlocks[i - numShorterRSBlocks][j];
                            }
                        }
                    }
                }
                if (numCorrections > 0)
                {
                    canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
                }
                else
                {
                    canvas.println("No errors found.");
                }
                numLastCorrections = numCorrections;
                return(dataBlocks);
            }
        }
        internal virtual int[] correctDataBlocks(int[] blocks)
        {
            int numCorrections = 0;
            int dataCapacity = qrCodeSymbol.DataCapacity;
            int[] dataBlocks = new int[dataCapacity];
            int numErrorCollectionCode = qrCodeSymbol.NumErrorCollectionCode;
            int numRSBlocks = qrCodeSymbol.NumRSBlocks;
            int eccPerRSBlock = numErrorCollectionCode / numRSBlocks;
            if (numRSBlocks == 1)
            {
                ReedSolomon corrector = new ReedSolomon(blocks, eccPerRSBlock);
                corrector.correct();
                numCorrections += corrector.NumCorrectedErrors;
                if (numCorrections > 0)
                    canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
                else
                    canvas.println("No errors found.");
                numLastCorrections = numCorrections;
                correctionSucceeded = corrector.CorrectionSucceeded;
                return blocks;
            }
            else
            {
                //we have to interleave data blocks because symbol has 2 or more RS blocks
                int numLongerRSBlocks = dataCapacity % numRSBlocks;
                if (numLongerRSBlocks == 0)
                {
                    //symbol has only 1 type of RS block
                    int lengthRSBlock = dataCapacity / numRSBlocks;
                    int[][] tmpArray = new int[numRSBlocks][];
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        tmpArray[i] = new int[lengthRSBlock];
                    }
                    int[][] RSBlocks = tmpArray;
                    //obtain RS blocks
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        for (int j = 0; j < lengthRSBlock; j++)
                        {
                            RSBlocks[i][j] = blocks[j * numRSBlocks + i];
                        }
                        ReedSolomon corrector = new ReedSolomon(RSBlocks[i], eccPerRSBlock);
                        corrector.correct();
                        numCorrections += corrector.NumCorrectedErrors;
                        correctionSucceeded = corrector.CorrectionSucceeded;
                    }
                    //obtain only data part
                    int p = 0;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        for (int j = 0; j < lengthRSBlock - eccPerRSBlock; j++)
                        {
                            dataBlocks[p++] = RSBlocks[i][j];
                        }
                    }
                }
                else
                {
                    //symbol has 2 types of RS blocks
                    int lengthShorterRSBlock = dataCapacity / numRSBlocks;
                    int lengthLongerRSBlock = dataCapacity / numRSBlocks + 1;
                    int numShorterRSBlocks = numRSBlocks - numLongerRSBlocks;
                    int[][] tmpArray2 = new int[numShorterRSBlocks][];
                    for (int i2 = 0; i2 < numShorterRSBlocks; i2++)
                    {
                        tmpArray2[i2] = new int[lengthShorterRSBlock];
                    }
                    int[][] shorterRSBlocks = tmpArray2;
                    int[][] tmpArray3 = new int[numLongerRSBlocks][];
                    for (int i3 = 0; i3 < numLongerRSBlocks; i3++)
                    {
                        tmpArray3[i3] = new int[lengthLongerRSBlock];
                    }
                    int[][] longerRSBlocks = tmpArray3;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        if (i < numShorterRSBlocks)
                        {
                            //get shorter RS Block(s)
                            int mod = 0;
                            for (int j = 0; j < lengthShorterRSBlock; j++)
                            {
                                if (j == lengthShorterRSBlock - eccPerRSBlock)
                                    mod = numLongerRSBlocks;
                                shorterRSBlocks[i][j] = blocks[j * numRSBlocks + i + mod];
                            }
                            ReedSolomon corrector = new ReedSolomon(shorterRSBlocks[i], eccPerRSBlock);
                            corrector.correct();
                            numCorrections += corrector.NumCorrectedErrors;
                            correctionSucceeded = corrector.CorrectionSucceeded;
                        }
                        else
                        {
                            //get longer RS Blocks
                            int mod = 0;
                            for (int j = 0; j < lengthLongerRSBlock; j++)
                            {
                                if (j == lengthShorterRSBlock - eccPerRSBlock)
                                    mod = numShorterRSBlocks;
                                longerRSBlocks[i - numShorterRSBlocks][j] = blocks[j * numRSBlocks + i - mod];
                            }

                            ReedSolomon corrector = new ReedSolomon(longerRSBlocks[i - numShorterRSBlocks], eccPerRSBlock);
                            corrector.correct();
                            numCorrections += corrector.NumCorrectedErrors;
                            correctionSucceeded = corrector.CorrectionSucceeded;
                        }
                    }
                    int p = 0;
                    for (int i = 0; i < numRSBlocks; i++)
                    {
                        if (i < numShorterRSBlocks)
                        {
                            for (int j = 0; j < lengthShorterRSBlock - eccPerRSBlock; j++)
                            {
                                dataBlocks[p++] = shorterRSBlocks[i][j];
                            }
                        }
                        else
                        {
                            for (int j = 0; j < lengthLongerRSBlock - eccPerRSBlock; j++)
                            {
                                dataBlocks[p++] = longerRSBlocks[i - numShorterRSBlocks][j];
                            }
                        }
                    }
                }
                if (numCorrections > 0)
                    canvas.println(System.Convert.ToString(numCorrections) + " data errors corrected.");
                else
                    canvas.println("No errors found.");
                numLastCorrections = numCorrections;
                return dataBlocks;
            }
        }