Version::Version(int versionNumber, int symbolSizeRows, int symbolSizeColumns, int dataRegionSizeRows, int dataRegionSizeColumns, ECBlocks* ecBlocks) : versionNumber_(versionNumber), symbolSizeRows_(symbolSizeRows), symbolSizeColumns_(symbolSizeColumns), dataRegionSizeRows_(dataRegionSizeRows), dataRegionSizeColumns_(dataRegionSizeColumns), ecBlocks_(ecBlocks), totalCodewords_(0) { // Calculate the total number of codewords int total = 0; int ecCodewords = ecBlocks_->getECCodewords(); vector<ECB*> &ecbArray = ecBlocks_->getECBlocks(); for (unsigned int i = 0; i < ecbArray.size(); i++) { ECB *ecBlock = ecbArray[i]; total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords); } totalCodewords_ = total; }
std::vector<Ref<DataBlock> > DataBlock::getDataBlocks(ArrayRef<unsigned char> rawCodewords, Version *version) { // Figure out the number and size of data blocks used by this version and // error correction level ECBlocks* ecBlocks = version->getECBlocks(); // First count the total number of data blocks int totalBlocks = 0; vector<ECB*> ecBlockArray = ecBlocks->getECBlocks(); for (size_t i = 0; i < ecBlockArray.size(); i++) { totalBlocks += ecBlockArray[i]->getCount(); } // Now establish DataBlocks of the appropriate size and number of data codewords std::vector<Ref<DataBlock> > result(totalBlocks); int numResultBlocks = 0; for (size_t j = 0; j < ecBlockArray.size(); j++) { ECB *ecBlock = ecBlockArray[j]; for (int i = 0; i < ecBlock->getCount(); i++) { int numDataCodewords = ecBlock->getDataCodewords(); int numBlockCodewords = ecBlocks->getECCodewords() + numDataCodewords; ArrayRef<unsigned char> buffer(numBlockCodewords); Ref<DataBlock> blockRef(new DataBlock(numDataCodewords, buffer)); result[numResultBlocks++] = blockRef; } } // All blocks have the same amount of data, except that the last n // (where n may be 0) have 1 more byte. Figure out where these start. int shorterBlocksTotalCodewords = (int)result[0]->codewords_.size(); int longerBlocksStartAt = (int)(result.size() - 1); while (longerBlocksStartAt >= 0) { int numCodewords = (int)(result[longerBlocksStartAt]->codewords_.size()); if (numCodewords == shorterBlocksTotalCodewords) { break; } if (numCodewords != shorterBlocksTotalCodewords + 1) { throw IllegalArgumentException("Data block sizes differ by more than 1"); } longerBlocksStartAt--; } longerBlocksStartAt++; int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks->getECCodewords(); // The last elements of result may be 1 element longer; // first fill out as many elements as all of them have int rawCodewordsOffset = 0; for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { for (int j = 0; j < numResultBlocks; j++) { result[j]->codewords_[i] = rawCodewords[rawCodewordsOffset++]; } } // Fill out the last data block in the longer ones for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { result[j]->codewords_[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; } // Now add in error correction blocks int max = (int)result[0]->codewords_.size(); for (int i = shorterBlocksNumDataCodewords; i < max; i++) { for (int j = 0; j < numResultBlocks; j++) { int iOffset = j < longerBlocksStartAt ? i : i + 1; result[j]->codewords_[iOffset] = rawCodewords[rawCodewordsOffset++]; } } if ((size_t)rawCodewordsOffset != rawCodewords.size()) { throw IllegalArgumentException("rawCodewordsOffset != rawCodewords.length"); } return result; }