Completed
Push — master ( 7ba8ec...9ff756 )
by smiley
02:49
created

QRCode::setupPositionAdjustPattern()   C

Complexity

Conditions 11
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 22
rs 5.9012
cc 11
eloc 13
nc 4
nop 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Class QRCode
4
 *
5
 * @filesource   QRCode.php
6
 * @created      26.11.2015
7
 * @package      chillerlan\QRCode
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2015 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\QRCode;
14
15
use chillerlan\QRCode\Data\AlphaNum;
16
use chillerlan\QRCode\Data\Byte;
17
use chillerlan\QRCode\Data\Kanji;
18
use chillerlan\QRCode\Data\Number;
19
use chillerlan\QRCode\Output\QROutputInterface;
20
21
/**
22
 * @link https://github.com/kazuhikoarase/qrcode-generator/tree/master/php
23
 * @link http://www.thonky.com/qr-code-tutorial/
24
 */
25
class QRCode{
26
27
	/**
28
	 * API constants
29
	 */
30
	const OUTPUT_STRING_TEXT = 0;
31
	const OUTPUT_STRING_JSON = 1;
32
	const OUTPUT_STRING_HTML = 2;
33
34
	const OUTPUT_IMAGE_PNG = 'png';
35
	const OUTPUT_IMAGE_JPG = 'jpg';
36
	const OUTPUT_IMAGE_GIF = 'gif';
37
38
	const ERROR_CORRECT_LEVEL_L = 1; // 7%.
39
	const ERROR_CORRECT_LEVEL_M = 0; // 15%.
40
	const ERROR_CORRECT_LEVEL_Q = 3; // 25%.
41
	const ERROR_CORRECT_LEVEL_H = 2; // 30%.
42
43
	// max bits @ ec level L:07 M:15 Q:25 H:30 %
44
	const TYPE_01 =  1; //  152  128  104   72
45
	const TYPE_02 =  2; //  272  224  176  128
46
	const TYPE_03 =  3; //  440  352  272  208
47
	const TYPE_04 =  4; //  640  512  384  288
48
	const TYPE_05 =  5; //  864  688  496  368
49
	const TYPE_06 =  6; // 1088  864  608  480
50
	const TYPE_07 =  7; // 1248  992  704  528
51
	const TYPE_08 =  8; // 1552 1232  880  688
52
	const TYPE_09 =  9; // 1856 1456 1056  800
53
	const TYPE_10 = 10; // 2192 1728 1232  976
54
55
	/**
56
	 * @var array
57
	 */
58
	protected $matrix = [];
59
60
	/**
61
	 * @var int
62
	 */
63
	protected $pixelCount = 0;
64
65
	/**
66
	 * @var int
67
	 */
68
	protected $typeNumber;
69
70
	/**
71
	 * @var int
72
	 */
73
	protected $errorCorrectLevel;
74
75
	/**
76
	 * @var \chillerlan\QRCode\BitBuffer
77
	 */
78
	protected $bitBuffer;
79
80
	/**
81
	 * @var \chillerlan\QRCode\Data\QRDataInterface
82
	 */
83
	protected $qrDataInterface;
84
85
	/**
86
	 * @var \chillerlan\QRCode\Output\QROutputInterface
87
	 */
88
	protected $qrOutputInterface;
89
90
	/**
91
	 * QRCode constructor.
92
	 *
93
	 * @param string                                      $data
94
	 * @param \chillerlan\QRCode\Output\QROutputInterface $output
95
	 * @param \chillerlan\QRCode\QROptions|null           $options
96
	 */
97
	public function __construct($data, QROutputInterface $output, QROptions $options = null){
98
		$this->qrOutputInterface = $output;
99
		$this->bitBuffer = new BitBuffer;
100
		$this->setData($data, $options);
101
	}
102
103
	/**
104
	 * @param string                            $data
105
	 * @param \chillerlan\QRCode\QROptions|null $options
106
	 *
107
	 * @return $this
108
	 * @throws \chillerlan\QRCode\QRCodeException
109
	 */
110
	public function setData($data, QROptions $options = null){
111
		$data = trim($data);
112
113
		if(empty($data)){
114
			throw new QRCodeException('No data given.');
115
		}
116
117
		if(!$options instanceof QROptions){
118
			$options = new QROptions;
119
		}
120
121
		if(!in_array($options->errorCorrectLevel, QRConst::RSBLOCK, true)){
122
			throw new QRCodeException('Invalid error correct level: '.$options->errorCorrectLevel);
123
		}
124
125
		$this->errorCorrectLevel = $options->errorCorrectLevel;
126
127
		switch(true){
128
			case Util::isAlphaNum($data):
129
				$mode = Util::isNumber($data) ? QRConst::MODE_NUMBER : QRConst::MODE_ALPHANUM;
130
				break;
131
			case Util::isKanji($data):
132
				$mode = QRConst::MODE_KANJI;
133
				break;
134
			default:
135
				$mode = QRConst::MODE_BYTE;
136
				break;
137
		}
138
139
		$qrDataInterface = [
140
			QRConst::MODE_ALPHANUM => AlphaNum::class,
141
			QRConst::MODE_BYTE     => Byte::class,
142
			QRConst::MODE_KANJI    => Kanji::class,
143
			QRConst::MODE_NUMBER   => Number::class,
144
		][$mode];
145
146
		$this->qrDataInterface = new $qrDataInterface($data);
147
		$this->typeNumber = intval($options->typeNumber);
148
149
		if($this->typeNumber < 1 || $this->typeNumber > 10){
150
			$this->typeNumber = $this->getTypeNumber($mode);
151
		}
152
153
		return $this;
154
	}
155
156
	/**
157
	 * @param $mode
158
	 *
159
	 * @return int
160
	 * @throws \chillerlan\QRCode\QRCodeException
161
	 */
162
	protected function getTypeNumber($mode){
163
		$length = $this->qrDataInterface->dataLength;
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
164
165
		if($this->qrDataInterface->mode === QRConst::MODE_KANJI){
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
166
			$length = floor($this->qrDataInterface->dataLength / 2);
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
167
		}
168
169
		foreach(range(1, 10) as $type){
170
			if($length <= Util::getMaxLength($type, $mode, $this->errorCorrectLevel)){
171
				return $type;
172
			}
173
		}
174
175
		throw new QRCodeException('Unable to determine type number.'); // @codeCoverageIgnore
176
	}
177
178
	/**
179
	 * @return mixed
180
	 */
181
	public function output(){
182
		$this->qrOutputInterface->setMatrix($this->getRawData());
183
		return $this->qrOutputInterface->dump();
184
	}
185
186
	/**
187
	 * @return array
188
	 */
189
	public function getRawData(){
190
		$minLostPoint = 0;
191
		$maskPattern = 0;
192
193
		foreach(range(0, 7) as $pattern){
194
			$this->getMatrix(true, $pattern);
195
			$lostPoint = 0;
196
			$darkCount = 0;
197
198
			$range1 = range(0, $this->pixelCount-1);
199
			$range2 = range(0, $this->pixelCount-2);
200
			$range3 = range(0, $this->pixelCount-7);
201
202
			// LEVEL1
203
			foreach($range1 as $row){
204
				foreach($range1 as $col){
205
					$sameCount = 0;
206
207
					foreach([-1, 0, 1] as $rr){
208
						if($row + $rr < 0 || $this->pixelCount <= $row + $rr){
209
							continue;
210
						}
211
212
						foreach([-1, 0, 1] as $cr){
213
214
							if(($rr === 0 && $cr === 0) || ($col + $cr < 0 || $this->pixelCount <= $col + $cr)){
215
								continue;
216
							}
217
218
							if($this->matrix[$row + $rr][$col + $cr] === $this->matrix[$row][$col]){
219
								$sameCount++;
220
							}
221
						}
222
					}
223
224
					if($sameCount > 5){
225
						$lostPoint += (3 + $sameCount - 5);
226
					}
227
				}
228
			}
229
230
			// LEVEL2
231
			foreach($range2 as $row){
232
				foreach($range2 as $col){
233
					$count = 0;
234
235
					if(
236
						   $this->matrix[$row    ][$col    ]
237
						|| $this->matrix[$row    ][$col + 1]
238
						|| $this->matrix[$row + 1][$col    ]
239
						|| $this->matrix[$row + 1][$col + 1]
240
					){
241
						$count++;
242
					}
243
244
					if($count === 0 || $count === 4){
245
						$lostPoint += 3;
246
					}
247
				}
248
			}
249
250
			// LEVEL3
251 View Code Duplication
			foreach($range1 as $row){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
				foreach($range3 as $col){
253
					if(
254
						    $this->matrix[$row][$col    ]
255
						&& !$this->matrix[$row][$col + 1]
256
						&&  $this->matrix[$row][$col + 2]
257
						&&  $this->matrix[$row][$col + 3]
258
						&&  $this->matrix[$row][$col + 4]
259
						&& !$this->matrix[$row][$col + 5]
260
						&&  $this->matrix[$row][$col + 6]
261
					){
262
						$lostPoint += 40;
263
					}
264
				}
265
			}
266
267 View Code Duplication
			foreach($range1 as $col){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
268
				foreach($range3 as $row){
269
					if(
270
						    $this->matrix[$row    ][$col]
271
						&& !$this->matrix[$row + 1][$col]
272
						&&  $this->matrix[$row + 2][$col]
273
						&&  $this->matrix[$row + 3][$col]
274
						&&  $this->matrix[$row + 4][$col]
275
						&& !$this->matrix[$row + 5][$col]
276
						&&  $this->matrix[$row + 6][$col]
277
					){
278
						$lostPoint += 40;
279
					}
280
				}
281
			}
282
283
			// LEVEL4
284
			foreach($range1 as $col){
285
				foreach($range1 as $row){
286
					if($this->matrix[$row][$col]){
287
						$darkCount++;
288
					}
289
				}
290
			}
291
292
			$lostPoint += (abs(100 * $darkCount / $this->pixelCount / $this->pixelCount - 50) / 5) * 10;
293
294
			if($pattern === 0 || $minLostPoint > $lostPoint){
295
				$minLostPoint = $lostPoint;
296
				$maskPattern = $pattern;
297
			}
298
299
		}
300
301
		$this->getMatrix(false, $maskPattern);
302
303
		return $this->matrix;
304
	}
305
306
	/**
307
	 * @param bool $test
308
	 */
309
	protected function setTypeNumber($test){
310
		$bits = Util::getBCHTypeNumber($this->typeNumber);
311
		$i = 0;
312
		while($i < 18){
313
			$a = (int)floor($i / 3);
314
			$b = $i % 3 + $this->pixelCount - 8 - 3;
315
316
			$this->matrix[$a][$b] = $this->matrix[$b][$a] = !$test && (($bits >> $i) & 1) === 1;
317
			$i++;
318
		}
319
320
	}
321
322
	/**
323
	 * @param bool $test
324
	 * @param int  $pattern
325
	 */
326
	protected function setTypeInfo($test, $pattern){
327
		$this->setPattern();
328
		$bits = Util::getBCHTypeInfo(($this->errorCorrectLevel << 3) | $pattern);
329
		$i = 0;
330
		while($i < 15){
331
			$mod = !$test && (($bits >> $i) & 1) === 1;
332
333
			switch(true){
334
				case $i < 6: $this->matrix[$i    ][8] = $mod; break;
2 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
335
				case $i < 8: $this->matrix[$i + 1][8] = $mod; break;
2 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
336
				default:
337
					$this->matrix[$this->pixelCount - 15 + $i][8] = $mod;
338
			}
339
340
			switch(true){
341 View Code Duplication
				case $i < 8: $this->matrix[8][$this->pixelCount - $i - 1] = $mod; break;
2 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
342 View Code Duplication
				case $i < 9: $this->matrix[8][           15 + 1 - $i - 1] = $mod; break;
2 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
343
				default:
344
					$this->matrix[8][15 - $i - 1] = $mod;
345
			}
346
			$i++;
347
		}
348
349
		$this->matrix[$this->pixelCount - 8][8] = !$test;
350
	}
351
352
	/**
353
	 * @throws \chillerlan\QRCode\QRCodeException
354
	 */
355
	protected function createData(){
356
		$this->bitBuffer->clear();
357
		$this->bitBuffer->put($this->qrDataInterface->mode, 4);
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
358
		$this->bitBuffer->put(
359
			$this->qrDataInterface->mode === QRConst::MODE_KANJI
0 ignored issues
show
Bug introduced by
Accessing mode on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
360
				? floor($this->qrDataInterface->dataLength / 2)
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
361
				: $this->qrDataInterface->dataLength,
0 ignored issues
show
Bug introduced by
Accessing dataLength on the interface chillerlan\QRCode\Data\QRDataInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
362
			$this->qrDataInterface->getLengthInBits($this->typeNumber)
363
		);
364
365
		$this->qrDataInterface->write($this->bitBuffer);
366
367
		$MAX_BITS = QRConst::MAX_BITS[$this->typeNumber][$this->errorCorrectLevel];
368
369
		if($this->bitBuffer->length > $MAX_BITS){
370
			throw new QRCodeException('code length overflow. ('.$this->bitBuffer->length.' > '.$MAX_BITS.'bit)');
371
		}
372
373
		// end code.
374
		if($this->bitBuffer->length + 4 <= $MAX_BITS){
375
			$this->bitBuffer->put(0, 4);
376
		}
377
378
		// padding
379
		while($this->bitBuffer->length % 8 !== 0){
380
			$this->bitBuffer->putBit(false);
381
		}
382
383
		// padding
384
		while(true){
385
386
			if($this->bitBuffer->length >= $MAX_BITS){
387
				break;
388
			}
389
390
			$this->bitBuffer->put(QRConst::PAD0, 8);
391
392
			if($this->bitBuffer->length >= $MAX_BITS){
393
				break;
394
			}
395
396
			$this->bitBuffer->put(QRConst::PAD1, 8);
397
		}
398
399
	}
400
401
	/**
402
	 * @return array
403
	 * @throws \chillerlan\QRCode\QRCodeException
404
	 */
405
	protected function createBytes(){
406
		$totalCodeCount = $maxDcCount = $maxEcCount = $offset = $index = 0;
407
		$rsBlocks = Util::getRSBlocks($this->typeNumber, $this->errorCorrectLevel);
408
		$rsBlockCount = count($rsBlocks);
409
		$dcdata = $ecdata = array_fill(0, $rsBlockCount, null);
410
411
		foreach($rsBlocks as $key => $value){
412
			$rsBlockTotal = $value[0];
413
			$rsBlockDataCount = $value[1];
414
415
			$maxDcCount = max($maxDcCount, $rsBlockDataCount);
416
			$maxEcCount = max($maxEcCount, $rsBlockTotal - $rsBlockDataCount);
417
418
			$dcdata[$key] = array_fill(0, $rsBlockDataCount, null);
419
420
			foreach($dcdata[$key] as $i => &$_dcdata){
421
				$bdata = $this->bitBuffer->buffer;
422
				$_dcdata = 0xff & $bdata[$i + $offset];
423
			}
424
425
			$offset += $rsBlockDataCount;
426
427
			$rsPoly = new Polynomial;
428
			$modPoly = new Polynomial;
429
430
			$i = 0;
431
			while($i < $rsBlockTotal - $rsBlockDataCount){
432
				$modPoly->setNum([1, $modPoly->gexp($i)]);
433
				$rsPoly->multiply($modPoly->num);
434
				$i++;
435
			}
436
437
			$rsPolyCount = count($rsPoly->num);
438
			$modPoly->setNum($dcdata[$key], $rsPolyCount - 1)->mod($rsPoly->num);
439
			$ecdata[$key] = array_fill(0, $rsPolyCount - 1, null);
440
			$add = count($modPoly->num) - count($ecdata[$key]);
441
442
			foreach($ecdata[$key] as $i => &$_ecdata){
443
				$modIndex = $i + $add;
444
				$_ecdata = $modIndex >= 0 ? $modPoly->num[$modIndex] : 0;
445
			}
446
447
			$totalCodeCount += $rsBlockTotal;
448
		}
449
450
		$data = array_fill(0, $totalCodeCount, null);
451
		$rsrange = range(0, $rsBlockCount - 1);
452
453
		$i = 0;
454 View Code Duplication
		while($i < $maxDcCount){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
455
			foreach($rsrange as $key){
456
				if($i < count($dcdata[$key])){
457
					$data[$index++] = $dcdata[$key][$i];
458
				}
459
			}
460
			$i++;
461
		}
462
463
		$i = 0;
464 View Code Duplication
		while($i < $maxEcCount){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
465
			foreach($rsrange as $key){
466
				if($i < count($ecdata[$key])){
467
					$data[$index++] = $ecdata[$key][$i];
468
				}
469
			}
470
			$i++;
471
		}
472
473
		return $data;
474
	}
475
476
	/**
477
	 * @param int $pattern
478
	 *
479
	 * @throws \chillerlan\QRCode\QRCodeException
480
	 */
481
	protected function mapData($pattern){
482
		$this->createData();
483
		$data = $this->createBytes();
484
		$inc = -1;
485
		$row = $this->pixelCount - 1;
486
		$bitIndex = 7;
487
		$byteIndex = 0;
488
		$dataCount = count($data);
489
490
		for($col = $this->pixelCount - 1; $col > 0; $col -= 2){
491
			if($col === 6){
492
				$col--;
493
			}
494
495
			while(true){
496
				$c = 0;
497
				while($c < 2){
498
					$_col = $col - $c;
499
500
					if($this->matrix[$row][$_col] === null){
501
						$dark = false;
502
503
						if($byteIndex < $dataCount){
504
							$dark = (($data[$byteIndex] >> $bitIndex) & 1) === 1;
505
						}
506
507
						$a = $row + $_col;
508
						$m = $row * $_col;
509
						$MASK_PATTERN = [
510
							QRConst::MASK_PATTERN000 => $a % 2,
511
							QRConst::MASK_PATTERN001 => $row % 2,
512
							QRConst::MASK_PATTERN010 => $_col % 3,
513
							QRConst::MASK_PATTERN011 => $a % 3,
514
							QRConst::MASK_PATTERN100 => (floor($row / 2) + floor($_col / 3)) % 2,
515
							QRConst::MASK_PATTERN101 => $m % 2 + $m % 3,
516
							QRConst::MASK_PATTERN110 => ($m % 2 + $m % 3) % 2,
517
							QRConst::MASK_PATTERN111 => ($m % 3 + $a % 2) % 2,
518
						][$pattern];
519
520
						if($MASK_PATTERN === 0){
521
							$dark = !$dark;
522
						}
523
524
						$this->matrix[$row][$_col] = $dark;
525
526
						$bitIndex--;
527
						if($bitIndex === -1){
528
							$byteIndex++;
529
							$bitIndex = 7;
530
						}
531
					}
532
					$c++;
533
				}
534
535
				$row += $inc;
536
				if($row < 0 || $this->pixelCount <= $row){
537
					$row -= $inc;
538
					$inc = -$inc;
539
					break;
540
				}
541
			}
542
		}
543
544
	}
545
546
	/**
547
	 *
548
	 */
549
	protected function setupPositionProbePattern(){
550
		$range = range(-1, 7);
551
552
		foreach([[0, 0], [$this->pixelCount - 7, 0], [0, $this->pixelCount - 7]] as $grid){
553
			$row = $grid[0];
554
			$col = $grid[1];
555
556
			$r = -1;
557
			while($r < 8){
558
				foreach($range as $c){
559
560
					if($row + $r <= -1 || $this->pixelCount <= $row + $r || $col + $c <= -1 || $this->pixelCount <= $col + $c){
561
						continue;
562
					}
563
564
					$this->matrix[$row + $r][$col + $c] =
565
						(0 <= $r && $r <= 6 && ($c === 0 || $c === 6))
566
						|| (0 <= $c && $c <= 6 && ($r === 0 || $r === 6))
567
						|| (2 <= $c && $c <= 4 &&  2 <= $r && $r <= 4);
568
				}
569
				$r++;
570
			}
571
		}
572
573
	}
574
575
	/**
576
	 *
577
	 */
578
	protected function setupPositionAdjustPattern(){
579
		$range = QRConst::PATTERN_POSITION[$this->typeNumber - 1];
580
581
		foreach($range as $i => $posI){
582
			foreach($range as $j => $posJ){
583
				if($this->matrix[$posI][$posJ] !== null){
584
					continue;
585
				}
586
587
				$row = $col = -2;
588
				while($row < 3){
589
					while($col < 3){
590
						$this->matrix[$posI + $row][$posJ + $col] =
591
							$row === -2 || $row ===  2 || $col === -2 || $col ===  2 ||($row ===  0 && $col === 0);
592
						$col++;
593
					}
594
					$row++;
595
				}
596
			}
597
		}
598
599
	}
600
601
	/**
602
	 * @throws \chillerlan\QRCode\QRCodeException
603
	 */
604
	protected function setPattern(){
605
		$this->setupPositionProbePattern();
606
		$this->setupPositionAdjustPattern();
607
608
		// setupTimingPattern
609
		for($i = 8; $i < $this->pixelCount - 8; $i++){
610
			if($this->matrix[$i][6] !== null){
611
				continue; // @codeCoverageIgnore
612
			}
613
614
			$this->matrix[$i][6] = $this->matrix[6][$i] = $i % 2 === 0;
615
		}
616
617
	}
618
619
	/**
620
	 * @param bool $test
621
	 * @param int  $maskPattern
622
	 *
623
	 * @throws \chillerlan\QRCode\QRCodeException
624
	 */
625
	protected function getMatrix($test, $maskPattern){
626
		$this->pixelCount = $this->typeNumber * 4 + 17;
627
		$this->matrix = array_fill(0, $this->pixelCount, array_fill(0, $this->pixelCount, null));
628
		$this->setTypeInfo($test, $maskPattern);
629
630
		if($this->typeNumber >= 7){
631
			$this->setTypeNumber($test);
632
		}
633
634
		$this->mapData($maskPattern);
635
	}
636
637
}
638