1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*/
// SPDX-License-Identifier: Apache-2.0
#include "QRDataBlock.h"
#include "QRErrorCorrectionLevel.h"
#include "QRVersion.h"
#include "ZXAlgorithms.h"
namespace ZXing::QRCode {
std::vector<DataBlock> DataBlock::GetDataBlocks(const ByteArray& rawCodewords, const Version& version, ErrorCorrectionLevel ecLevel)
{
if (Size(rawCodewords) != version.totalCodewords())
return {};
// Figure out the number and size of data blocks used by this version and
// error correction level
auto& ecBlocks = version.ecBlocksForLevel(ecLevel);
// First count the total number of data blocks
int totalBlocks = ecBlocks.numBlocks();
if (totalBlocks == 0)
return {};
std::vector<DataBlock> result(totalBlocks);
// Now establish DataBlocks of the appropriate size and number of data codewords
int numResultBlocks = 0;
for (auto& ecBlock : ecBlocks.blockArray()) {
for (int i = 0; i < ecBlock.count; i++) {
auto& item = result[numResultBlocks++];
item._numDataCodewords = ecBlock.dataCodewords;
item._codewords.resize(ecBlocks.codewordsPerBlock + ecBlock.dataCodewords);
}
}
// 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 = Size(result[0]._codewords);
int longerBlocksStartAt = Size(result) - 1;
while (longerBlocksStartAt >= 0) {
int numCodewords = Size(result[longerBlocksStartAt]._codewords);
if (numCodewords == shorterBlocksTotalCodewords) {
break;
}
longerBlocksStartAt--;
}
longerBlocksStartAt++;
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.codewordsPerBlock;
// The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have
int rawCodewordsOffset = 0;
if (version.isModel1()) {
// in Model 1 symbols the data blocks are concatenated back to back
for (int j = 0; j < numResultBlocks; j++)
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
result[j]._codewords[i] = rawCodewords[rawCodewordsOffset++];
} else {
// in all others, the data blocks are interleaved
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 = Size(result[0]._codewords);
if (version.isModel1()) {
for (int j = 0; j < numResultBlocks; j++) {
for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
int iOffset = j < longerBlocksStartAt ? i : i + 1;
result[j]._codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}
} else {
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++];
}
}
}
return result;
}
} // namespace ZXing::QRCode
|