Passed
Push — v5 ( 92f563...26536d )
by smiley
02:19
created

EccLevel::getRSBlocks()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
/**
3
 * Class EccLevel
4
 *
5
 * @filesource   EccLevel.php
6
 * @created      19.11.2020
7
 * @package      chillerlan\QRCode\Common
8
 * @author       smiley <[email protected]>
9
 * @copyright    2020 smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode\Common;
14
15
use chillerlan\QRCode\QRCodeException;
16
17
use function array_column, array_combine, array_keys;
18
19
/**
20
 *
21
 */
22
final class EccLevel{
23
24
	// ISO/IEC 18004:2000 Tables 12, 25
25
26
	/** @var int */
27
	public const L = 0b01; // 7%.
28
	/** @var int */
29
	public const M = 0b00; // 15%.
30
	/** @var int */
31
	public const Q = 0b11; // 25%.
32
	/** @var int */
33
	public const H = 0b10; // 30%.
34
35
	/**
36
	 * References to the keys of the following tables:
37
	 *
38
	 * @see \chillerlan\QRCode\Common\Version::MAX_BITS
39
	 * @see \chillerlan\QRCode\Common\EccLevel::RSBLOCKS
40
	 * @see \chillerlan\QRCode\Common\EccLevel::formatPattern
41
	 *
42
	 * @var int[]
43
	 */
44
	public const MODES = [
45
		self::L => 0,
46
		self::M => 1,
47
		self::Q => 2,
48
		self::H => 3,
49
	];
50
51
	public const MODES_STRING = [
52
		self::L => 'L',
53
		self::M => 'M',
54
		self::Q => 'Q',
55
		self::H => 'H',
56
	];
57
58
	/**
59
	 * ISO/IEC 18004:2000 Tables 7-11 - Number of symbol characters and input data capacity for versions 1 to 40
60
	 *
61
	 * @var int [][]
62
	 */
63
	private const MAX_BITS = [
64
	//  v  => [    L,     M,     Q,     H]  // modules
65
		1  => [  152,   128,   104,    72], //  21
66
		2  => [  272,   224,   176,   128], //  25
67
		3  => [  440,   352,   272,   208], //  29
68
		4  => [  640,   512,   384,   288], //  33
69
		5  => [  864,   688,   496,   368], //  37
70
		6  => [ 1088,   864,   608,   480], //  41
71
		7  => [ 1248,   992,   704,   528], //  45
72
		8  => [ 1552,  1232,   880,   688], //  49
73
		9  => [ 1856,  1456,  1056,   800], //  53
74
		10 => [ 2192,  1728,  1232,   976], //  57
75
		11 => [ 2592,  2032,  1440,  1120], //  61
76
		12 => [ 2960,  2320,  1648,  1264], //  65
77
		13 => [ 3424,  2672,  1952,  1440], //  69 NICE!
78
		14 => [ 3688,  2920,  2088,  1576], //  73
79
		15 => [ 4184,  3320,  2360,  1784], //  77
80
		16 => [ 4712,  3624,  2600,  2024], //  81
81
		17 => [ 5176,  4056,  2936,  2264], //  85
82
		18 => [ 5768,  4504,  3176,  2504], //  89
83
		19 => [ 6360,  5016,  3560,  2728], //  93
84
		20 => [ 6888,  5352,  3880,  3080], //  97
85
		21 => [ 7456,  5712,  4096,  3248], // 101
86
		22 => [ 8048,  6256,  4544,  3536], // 105
87
		23 => [ 8752,  6880,  4912,  3712], // 109
88
		24 => [ 9392,  7312,  5312,  4112], // 113
89
		25 => [10208,  8000,  5744,  4304], // 117
90
		26 => [10960,  8496,  6032,  4768], // 121
91
		27 => [11744,  9024,  6464,  5024], // 125
92
		28 => [12248,  9544,  6968,  5288], // 129
93
		29 => [13048, 10136,  7288,  5608], // 133
94
		30 => [13880, 10984,  7880,  5960], // 137
95
		31 => [14744, 11640,  8264,  6344], // 141
96
		32 => [15640, 12328,  8920,  6760], // 145
97
		33 => [16568, 13048,  9368,  7208], // 149
98
		34 => [17528, 13800,  9848,  7688], // 153
99
		35 => [18448, 14496, 10288,  7888], // 157
100
		36 => [19472, 15312, 10832,  8432], // 161
101
		37 => [20528, 15936, 11408,  8768], // 165
102
		38 => [21616, 16816, 12016,  9136], // 169
103
		39 => [22496, 17728, 12656,  9776], // 173
104
		40 => [23648, 18672, 13328, 10208], // 177
105
	];
106
107
	/**
108
	 * ISO/IEC 18004:2000 Section 8.9 - Format Information
109
	 *
110
	 * ECC level -> mask pattern
111
	 *
112
	 * @var int[][]
113
	 */
114
	private const FORMAT_PATTERN = [
115
		[ // L
116
		  0b111011111000100,
117
		  0b111001011110011,
118
		  0b111110110101010,
119
		  0b111100010011101,
120
		  0b110011000101111,
121
		  0b110001100011000,
122
		  0b110110001000001,
123
		  0b110100101110110,
124
		],
125
		[ // M
126
		  0b101010000010010,
127
		  0b101000100100101,
128
		  0b101111001111100,
129
		  0b101101101001011,
130
		  0b100010111111001,
131
		  0b100000011001110,
132
		  0b100111110010111,
133
		  0b100101010100000,
134
		],
135
		[ // Q
136
		  0b011010101011111,
137
		  0b011000001101000,
138
		  0b011111100110001,
139
		  0b011101000000110,
140
		  0b010010010110100,
141
		  0b010000110000011,
142
		  0b010111011011010,
143
		  0b010101111101101,
144
		],
145
		[ // H
146
		  0b001011010001001,
147
		  0b001001110111110,
148
		  0b001110011100111,
149
		  0b001100111010000,
150
		  0b000011101100010,
151
		  0b000001001010101,
152
		  0b000110100001100,
153
		  0b000100000111011,
154
		],
155
	];
156
157
	private int $eccLevel;
158
159
	/**
160
	 * @param int $eccLevel containing the two bits encoding a QR Code's error correction level
161
	 *
162
	 * @throws \chillerlan\QRCode\QRCodeException
163
	 */
164
	public function __construct(int $eccLevel){
165
166
		if((0b11 & $eccLevel) !== $eccLevel){
167
			throw new QRCodeException('invalid ECC level');
168
		}
169
170
		$this->eccLevel = $eccLevel;
171
	}
172
173
	/**
174
	 * returns the string representation of the current ECC level
175
	 */
176
	public function __toString():string{
177
		return self::MODES_STRING[$this->eccLevel];
178
	}
179
180
	/**
181
	 * returns the current ECC level
182
	 */
183
	public function getLevel():int{
184
		return $this->eccLevel;
185
	}
186
187
	/**
188
	 * returns the ordinal value of the current ECC level
189
	 */
190
	public function getOrdinal():int{
191
		return self::MODES[$this->eccLevel];
192
	}
193
194
	/**
195
	 * returns the format pattern for the given $eccLevel and $maskPattern
196
	 *
197
	 * @throws \chillerlan\QRCode\QRCodeException
198
	 */
199
	public function getformatPattern(int $maskPattern):int{
200
201
		if((0b111 & $maskPattern) !== $maskPattern){
202
			throw new QRCodeException('invalid mask pattern');
203
		}
204
205
		return self::FORMAT_PATTERN[self::MODES[$this->eccLevel]][$maskPattern];
206
	}
207
208
	/**
209
	 * returns an array wit the max bit lengths for version 1-40 and the current ECC level
210
	 */
211
	public function getMaxBits():array{
212
		return array_combine(
213
			array_keys(self::MAX_BITS),
214
			array_column(self::MAX_BITS, self::MODES[$this->eccLevel])
215
		);
216
	}
217
218
}
219