PluginProbe ʕ •ᴥ•ʔ
WP 2FA – Two-factor authentication for WordPress / 2.9.0
WP 2FA – Two-factor authentication for WordPress v2.9.0
4.0.0 1.7.1 2.0.0 2.0.1 2.1.0 2.2.0 2.2.1 2.3.0 2.4.0 2.4.1 2.4.2 2.5.0 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.8.0 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0 3.0.1 3.1.0 3.1.1 3.1.1.2 trunk 1.2.0 1.3.0 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.1 1.6.2 1.7.0
wp-2fa / includes / classes / bacon / bacon-qr-code / src / Common / FormatInformation.php
wp-2fa / includes / classes / bacon / bacon-qr-code / src / Common Last commit date
BitArray.php 11 months ago BitMatrix.php 11 months ago BitUtils.php 11 months ago CharacterSetEci.php 11 months ago EcBlock.php 11 months ago EcBlocks.php 11 months ago ErrorCorrectionLevel.php 11 months ago FormatInformation.php 11 months ago Mode.php 11 months ago ReedSolomonCodec.php 11 months ago Version.php 11 months ago
FormatInformation.php
133 lines
1 <?php
2
3 /**
4 * BaconQrCode
5 *
6 * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
7 * @copyright 2013 Ben 'DASPRiD' Scholzen
8 * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
9 */
10 namespace WP2FA_Vendor\BaconQrCode\Common;
11
12 /**
13 * Encapsulates a QR Code's format information, including the data mask used and error correction level.
14 */
15 class FormatInformation
16 {
17 /**
18 * Mask for format information.
19 */
20 private const FORMAT_INFO_MASK_QR = 0x5412;
21 /**
22 * Lookup table for decoding format information.
23 *
24 * See ISO 18004:2006, Annex C, Table C.1
25 */
26 private const FORMAT_INFO_DECODE_LOOKUP = [[0x5412, 0x0], [0x5125, 0x1], [0x5e7c, 0x2], [0x5b4b, 0x3], [0x45f9, 0x4], [0x40ce, 0x5], [0x4f97, 0x6], [0x4aa0, 0x7], [0x77c4, 0x8], [0x72f3, 0x9], [0x7daa, 0xa], [0x789d, 0xb], [0x662f, 0xc], [0x6318, 0xd], [0x6c41, 0xe], [0x6976, 0xf], [0x1689, 0x10], [0x13be, 0x11], [0x1ce7, 0x12], [0x19d0, 0x13], [0x762, 0x14], [0x255, 0x15], [0xd0c, 0x16], [0x83b, 0x17], [0x355f, 0x18], [0x3068, 0x19], [0x3f31, 0x1a], [0x3a06, 0x1b], [0x24b4, 0x1c], [0x2183, 0x1d], [0x2eda, 0x1e], [0x2bed, 0x1f]];
27 /**
28 * Offset i holds the number of 1 bits in the binary representation of i.
29 *
30 * @var int[]
31 */
32 private const BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
33 /**
34 * Error correction level.
35 *
36 * @var ErrorCorrectionLevel
37 */
38 private $ecLevel;
39 /**
40 * Data mask.
41 *
42 * @var int
43 */
44 private $dataMask;
45 protected function __construct(int $formatInfo)
46 {
47 $this->ecLevel = ErrorCorrectionLevel::forBits($formatInfo >> 3 & 0x3);
48 $this->dataMask = $formatInfo & 0x7;
49 }
50 /**
51 * Checks how many bits are different between two integers.
52 */
53 public static function numBitsDiffering(int $a, int $b) : int
54 {
55 $a ^= $b;
56 return self::BITS_SET_IN_HALF_BYTE[$a & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 4) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 8) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 12) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 16) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 20) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 24) & 0xf] + self::BITS_SET_IN_HALF_BYTE[BitUtils::unsignedRightShift($a, 28) & 0xf];
57 }
58 /**
59 * Decodes format information.
60 */
61 public static function decodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self
62 {
63 $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2);
64 if (null !== $formatInfo) {
65 return $formatInfo;
66 }
67 // Should return null, but, some QR codes apparently do not mask this info. Try again by actually masking the
68 // pattern first.
69 return self::doDecodeFormatInformation($maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR, $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR);
70 }
71 /**
72 * Internal method for decoding format information.
73 */
74 private static function doDecodeFormatInformation(int $maskedFormatInfo1, int $maskedFormatInfo2) : ?self
75 {
76 $bestDifference = \PHP_INT_MAX;
77 $bestFormatInfo = 0;
78 foreach (self::FORMAT_INFO_DECODE_LOOKUP as $decodeInfo) {
79 $targetInfo = $decodeInfo[0];
80 if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) {
81 // Found an exact match
82 return new self($decodeInfo[1]);
83 }
84 $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo);
85 if ($bitsDifference < $bestDifference) {
86 $bestFormatInfo = $decodeInfo[1];
87 $bestDifference = $bitsDifference;
88 }
89 if ($maskedFormatInfo1 !== $maskedFormatInfo2) {
90 // Also try the other option
91 $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo);
92 if ($bitsDifference < $bestDifference) {
93 $bestFormatInfo = $decodeInfo[1];
94 $bestDifference = $bitsDifference;
95 }
96 }
97 }
98 // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match.
99 if ($bestDifference <= 3) {
100 return new self($bestFormatInfo);
101 }
102 return null;
103 }
104 /**
105 * Returns the error correction level.
106 */
107 public function getErrorCorrectionLevel() : ErrorCorrectionLevel
108 {
109 return $this->ecLevel;
110 }
111 /**
112 * Returns the data mask.
113 */
114 public function getDataMask() : int
115 {
116 return $this->dataMask;
117 }
118 /**
119 * Hashes the code of the EC level.
120 */
121 public function hashCode() : int
122 {
123 return $this->ecLevel->getBits() << 3 | $this->dataMask;
124 }
125 /**
126 * Verifies if this instance equals another one.
127 */
128 public function equals(self $other) : bool
129 {
130 return $this->ecLevel === $other->ecLevel && $this->dataMask === $other->dataMask;
131 }
132 }
133