#include "QRFormatInformation.h"
#include "ZXAlgorithms.h"
#include <bit>
namespace ZXing::QRCode {
static uint32_t MirrorBits(uint32_t bits)
{
return ReverseBits32(bits) >> 17;
}
static FormatInformation FindBestFormatInfo(const std::vector<uint32_t>& masks, const std::vector<uint32_t>& bits)
{
constexpr uint32_t MODEL2_MASKED_PATTERNS[] = {
0x5412, 0x5125, 0x5E7C, 0x5B4B, 0x45F9, 0x40CE, 0x4F97, 0x4AA0, 0x77C4, 0x72F3, 0x7DAA, 0x789D, 0x662F, 0x6318, 0x6C41, 0x6976,
0x1689, 0x13BE, 0x1CE7, 0x19D0, 0x0762, 0x0255, 0x0D0C, 0x083B, 0x355F, 0x3068, 0x3F31, 0x3A06, 0x24B4, 0x2183, 0x2EDA, 0x2BED,
};
FormatInformation fi;
for (auto mask : masks)
for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex)
for (uint32_t pattern : MODEL2_MASKED_PATTERNS) {
pattern ^= FORMAT_INFO_MASK_MODEL2;
if (int hammingDist = std::popcount((bits[bitsIndex] ^ mask) ^ pattern);
hammingDist < fi.hammingDistance) {
fi.mask = mask; fi.data = pattern >> 10; fi.hammingDistance = hammingDist;
fi.bitsIndex = bitsIndex;
}
}
return fi;
}
static FormatInformation FindBestFormatInfoRMQR(const std::vector<uint32_t>& bits, const std::vector<uint32_t>& subbits)
{
constexpr uint32_t MASKED_PATTERNS[64] = { 0x1FAB2, 0x1E597, 0x1DBDD, 0x1C4F8, 0x1B86C, 0x1A749, 0x19903, 0x18626,
0x17F0E, 0x1602B, 0x15E61, 0x14144, 0x13DD0, 0x122F5, 0x11CBF, 0x1039A,
0x0F1CA, 0x0EEEF, 0x0D0A5, 0x0CF80, 0x0B314, 0x0AC31, 0x0927B, 0x08D5E,
0x07476, 0x06B53, 0x05519, 0x04A3C, 0x036A8, 0x0298D, 0x017C7, 0x008E2,
0x3F367, 0x3EC42, 0x3D208, 0x3CD2D, 0x3B1B9, 0x3AE9C, 0x390D6, 0x38FF3,
0x376DB, 0x369FE, 0x357B4, 0x34891, 0x33405, 0x32B20, 0x3156A, 0x30A4F,
0x2F81F, 0x2E73A, 0x2D970, 0x2C655, 0x2BAC1, 0x2A5E4, 0x29BAE, 0x2848B,
0x27DA3, 0x26286, 0x25CCC, 0x243E9, 0x23F7D, 0x22058, 0x21E12, 0x20137,
};
constexpr uint32_t MASKED_PATTERNS_SUB[64] = { 0x20A7B, 0x2155E, 0x22B14, 0x23431, 0x248A5, 0x25780, 0x269CA, 0x276EF,
0x28FC7, 0x290E2, 0x2AEA8, 0x2B18D, 0x2CD19, 0x2D23C, 0x2EC76, 0x2F353,
0x30103, 0x31E26, 0x3206C, 0x33F49, 0x343DD, 0x35CF8, 0x362B2, 0x37D97,
0x384BF, 0x39B9A, 0x3A5D0, 0x3BAF5, 0x3C661, 0x3D944, 0x3E70E, 0x3F82B,
0x003AE, 0x01C8B, 0x022C1, 0x03DE4, 0x04170, 0x05E55, 0x0601F, 0x07F3A,
0x08612, 0x09937, 0x0A77D, 0x0B858, 0x0C4CC, 0x0DBE9, 0x0E5A3, 0x0FA86,
0x108D6, 0x117F3, 0x129B9, 0x1369C, 0x14A08, 0x1552D, 0x16B67, 0x17442,
0x18D6A, 0x1924F, 0x1AC05, 0x1B320, 0x1CFB4, 0x1D091, 0x1EEDB, 0x1F1FE,
};
FormatInformation fi;
auto best = [&fi](const std::vector<uint32_t>& bits, const uint32_t (&patterns)[64], uint32_t mask)
{
for (int bitsIndex = 0; bitsIndex < Size(bits); ++bitsIndex)
for (uint32_t pattern : patterns) {
pattern ^= mask;
if (int hammingDist = std::popcount((bits[bitsIndex] ^ mask) ^ pattern);
hammingDist < fi.hammingDistance) {
fi.mask = mask; fi.data = pattern >> 12; fi.hammingDistance = hammingDist;
fi.bitsIndex = bitsIndex;
}
}
};
best(bits, MASKED_PATTERNS, FORMAT_INFO_MASK_RMQR);
if (Size(subbits)) best(subbits, MASKED_PATTERNS_SUB, FORMAT_INFO_MASK_RMQR_SUB);
return fi;
}
FormatInformation FormatInformation::DecodeQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2)
{
uint32_t mirroredFormatInfoBits2 = MirrorBits(((formatInfoBits2 >> 1) & 0b111111110000000) | (formatInfoBits2 & 0b1111111));
formatInfoBits2 = ((formatInfoBits2 >> 1) & 0b111111100000000) | (formatInfoBits2 & 0b11111111);
auto fi = FindBestFormatInfo({FORMAT_INFO_MASK_MODEL2, 0, FORMAT_INFO_MASK_MODEL1},
{formatInfoBits1, formatInfoBits2, MirrorBits(formatInfoBits1), mirroredFormatInfoBits2});
fi.ecLevel = ECLevelFromBits((fi.data >> 3) & 0x03);
fi.dataMask = static_cast<uint8_t>(fi.data & 0x07);
fi.isMirrored = fi.bitsIndex > 1;
return fi;
}
FormatInformation FormatInformation::DecodeMQR(uint32_t formatInfoBits)
{
auto fi = FindBestFormatInfo({FORMAT_INFO_MASK_MICRO}, {formatInfoBits, MirrorBits(formatInfoBits)});
constexpr uint8_t BITS_TO_VERSION[] = {1, 2, 2, 3, 3, 4, 4, 4};
fi.ecLevel = ECLevelFromBits((fi.data >> 2) & 0x07, true);
fi.dataMask = static_cast<uint8_t>(fi.data & 0x03);
fi.microVersion = BITS_TO_VERSION[(fi.data >> 2) & 0x07];
fi.isMirrored = fi.bitsIndex == 1;
return fi;
}
FormatInformation FormatInformation::DecodeRMQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2)
{
FormatInformation fi;
if (formatInfoBits2)
fi = FindBestFormatInfoRMQR({formatInfoBits1}, {formatInfoBits2});
else fi = FindBestFormatInfoRMQR({formatInfoBits1}, {});
fi.ecLevel = ECLevelFromBits(((fi.data >> 5) & 1) << 1); fi.dataMask = 4; fi.microVersion = (fi.data & 0x1F) + 1;
fi.isMirrored = false;
return fi;
}
}