#include "QRDataBlock.h"
#include "ByteArray.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 {};
auto& ecBlocks = version.ecBlocksForLevel(ecLevel);
int totalBlocks = ecBlocks.numBlocks();
if (totalBlocks == 0)
return {};
std::vector<DataBlock> result(totalBlocks);
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);
}
}
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;
int rawCodewordsOffset = 0;
if (version.isModel1()) {
for (int j = 0; j < numResultBlocks; j++)
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
result[j]._codewords[i] = rawCodewords[rawCodewordsOffset++];
} else {
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
for (int j = 0; j < numResultBlocks; j++)
result[j]._codewords[i] = rawCodewords[rawCodewordsOffset++];
}
for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
result[j]._codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
}
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;
}
}