/// <summary> Interleave "bits" with corresponding error correction bytes. On success, store the result in /// "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. /// </summary> internal static void interleaveWithECBytes(BitVector bits, int numTotalBytes, int numDataBytes, int numRSBlocks, BitVector result) { // "bits" must have "getNumDataBytes" bytes of data. if (bits.sizeInBytes() != numDataBytes) { throw new WriterException("Number of bits and data bytes does not match"); } // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll // store the divided data bytes blocks and error correction bytes blocks into "blocks". int dataBytesOffset = 0; int maxNumDataBytes = 0; int maxNumEcBytes = 0; // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. System.Collections.ArrayList blocks = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(numRSBlocks)); for (int i = 0; i < numRSBlocks; ++i) { int[] numDataBytesInBlock = new int[1]; int[] numEcBytesInBlock = new int[1]; getNumDataBytesAndNumECBytesForBlockID(numTotalBytes, numDataBytes, numRSBlocks, i, numDataBytesInBlock, numEcBytesInBlock); ByteArray dataBytes = new ByteArray(); dataBytes.set_Renamed(bits.Array, dataBytesOffset, numDataBytesInBlock[0]); ByteArray ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); blocks.Add(new BlockPair(dataBytes, ecBytes)); maxNumDataBytes = System.Math.Max(maxNumDataBytes, dataBytes.size()); maxNumEcBytes = System.Math.Max(maxNumEcBytes, ecBytes.size()); dataBytesOffset += numDataBytesInBlock[0]; } if (numDataBytes != dataBytesOffset) { throw new WriterException("Data bytes does not match offset"); } // First, place data blocks. for (int i = 0; i < maxNumDataBytes; ++i) { for (int j = 0; j < blocks.Count; ++j) { ByteArray dataBytes = ((BlockPair) blocks[j]).DataBytes; if (i < dataBytes.size()) { result.appendBits(dataBytes.at(i), 8); } } } // Then, place error correction blocks. for (int i = 0; i < maxNumEcBytes; ++i) { for (int j = 0; j < blocks.Count; ++j) { ByteArray ecBytes = ((BlockPair) blocks[j]).ErrorCorrectionBytes; if (i < ecBytes.size()) { result.appendBits(ecBytes.at(i), 8); } } } if (numTotalBytes != result.sizeInBytes()) { // Should be same. throw new WriterException("Interleaving error: " + numTotalBytes + " and " + result.sizeInBytes() + " differ."); } }
internal static ByteArray generateECBytes(ByteArray dataBytes, int numEcBytesInBlock) { int numDataBytes = dataBytes.size(); int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; for (int i = 0; i < numDataBytes; i++) { toEncode[i] = dataBytes.at(i); } new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, numEcBytesInBlock); ByteArray ecBytes = new ByteArray(numEcBytesInBlock); for (int i = 0; i < numEcBytesInBlock; i++) { ecBytes.set_Renamed(i, toEncode[numDataBytes + i]); } return ecBytes; }