PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.19
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.19
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
woocommerce-pos / vendor_prefixed / chillerlan / php-qrcode / src / Decoder / Decoder.php

Decoder.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.19, at vendor_prefixed/chillerlan/php-qrcode/src/Decoder/Decoder.php

154 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class Decoder
5 *
6 * @created 17.01.2021
7 * @author ZXing Authors
8 * @author Smiley <smiley@chillerlan.net>
9 * @copyright 2021 Smiley
10 * @license Apache-2.0
11 */
12 namespace WCPOS\Vendor\chillerlan\QRCode\Decoder;
13
14 use WCPOS\Vendor\chillerlan\QRCode\Common\BitBuffer;
15 use WCPOS\Vendor\chillerlan\QRCode\Common\EccLevel;
16 use WCPOS\Vendor\chillerlan\QRCode\Common\LuminanceSourceInterface;
17 use WCPOS\Vendor\chillerlan\QRCode\Common\MaskPattern;
18 use WCPOS\Vendor\chillerlan\QRCode\Common\Mode;
19 use WCPOS\Vendor\chillerlan\QRCode\Common\Version;
20 use WCPOS\Vendor\chillerlan\QRCode\Data\AlphaNum;
21 use WCPOS\Vendor\chillerlan\QRCode\Data\Byte;
22 use WCPOS\Vendor\chillerlan\QRCode\Data\ECI;
23 use WCPOS\Vendor\chillerlan\QRCode\Data\Hanzi;
24 use WCPOS\Vendor\chillerlan\QRCode\Data\Kanji;
25 use WCPOS\Vendor\chillerlan\QRCode\Data\Number;
26 use WCPOS\Vendor\chillerlan\QRCode\Detector\Detector;
27 use Throwable;
28 use function chr, str_replace;
29 /**
30 * The main class which implements QR Code decoding -- as opposed to locating and extracting
31 * the QR Code from an image.
32 *
33 * @author Sean Owen
34 */
35 final class Decoder
36 {
37 private ?Version $version = null;
38 private ?EccLevel $eccLevel = null;
39 private ?MaskPattern $maskPattern = null;
40 private BitBuffer $bitBuffer;
41 private Detector $detector;
42 /**
43 * Decodes a QR Code represented as a BitMatrix.
44 * A 1 or "true" is taken to mean a black module.
45 *
46 * @throws \Throwable|\chillerlan\QRCode\Decoder\QRCodeDecoderException
47 */
48 public function decode(LuminanceSourceInterface $source) : DecoderResult
49 {
50 $this->detector = new Detector($source);
51 $matrix = $this->detector->detect();
52 try {
53 // clone the BitMatrix to avoid errors in case we run into mirroring
54 return $this->decodeMatrix(clone $matrix);
55 } catch (Throwable $e) {
56 try {
57 /*
58 * Prepare for a mirrored reading.
59 *
60 * Since we're here, this means we have successfully detected some kind
61 * of version and format information when mirrored. This is a good sign,
62 * that the QR code may be mirrored, and we should try once more with a
63 * mirrored content.
64 */
65 return $this->decodeMatrix($matrix->resetVersionInfo()->mirrorDiagonal());
66 } catch (Throwable $f) {
67 // Throw the exception from the original reading
68 throw $e;
69 }
70 }
71 }
72 /**
73 * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
74 */
75 private function decodeMatrix(BitMatrix $matrix) : DecoderResult
76 {
77 // Read raw codewords
78 $rawCodewords = $matrix->readCodewords();
79 $this->version = $matrix->getVersion();
80 $this->eccLevel = $matrix->getEccLevel();
81 $this->maskPattern = $matrix->getMaskPattern();
82 if ($this->version === null || $this->eccLevel === null || $this->maskPattern === null) {
83 throw new QRCodeDecoderException('unable to read version or format info');
84 // @codeCoverageIgnore
85 }
86 $resultBytes = (new ReedSolomonDecoder($this->version, $this->eccLevel))->decode($rawCodewords);
87 return $this->decodeBitStream($resultBytes);
88 }
89 /**
90 * Decode the contents of that stream of bytes
91 *
92 * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
93 */
94 private function decodeBitStream(BitBuffer $bitBuffer) : DecoderResult
95 {
96 $this->bitBuffer = $bitBuffer;
97 $versionNumber = $this->version->getVersionNumber();
98 $symbolSequence = -1;
99 $parityData = -1;
100 $fc1InEffect = \false;
101 $result = '';
102 // While still another segment to read...
103 while ($this->bitBuffer->available() >= 4) {
104 $datamode = $this->bitBuffer->read(4);
105 // mode is encoded by 4 bits
106 // OK, assume we're done
107 if ($datamode === Mode::TERMINATOR) {
108 break;
109 } elseif ($datamode === Mode::NUMBER) {
110 $result .= Number::decodeSegment($this->bitBuffer, $versionNumber);
111 } elseif ($datamode === Mode::ALPHANUM) {
112 $result .= $this->decodeAlphanumSegment($versionNumber, $fc1InEffect);
113 } elseif ($datamode === Mode::BYTE) {
114 $result .= Byte::decodeSegment($this->bitBuffer, $versionNumber);
115 } elseif ($datamode === Mode::KANJI) {
116 $result .= Kanji::decodeSegment($this->bitBuffer, $versionNumber);
117 } elseif ($datamode === Mode::STRCTURED_APPEND) {
118 if ($this->bitBuffer->available() < 16) {
119 throw new QRCodeDecoderException('structured append: not enough bits left');
120 }
121 // sequence number and parity is added later to the result metadata
122 // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
123 $symbolSequence = $this->bitBuffer->read(8);
124 $parityData = $this->bitBuffer->read(8);
125 } elseif ($datamode === Mode::FNC1_FIRST || $datamode === Mode::FNC1_SECOND) {
126 // We do little with FNC1 except alter the parsed result a bit according to the spec
127 $fc1InEffect = \true;
128 } elseif ($datamode === Mode::ECI) {
129 $result .= ECI::decodeSegment($this->bitBuffer, $versionNumber);
130 } elseif ($datamode === Mode::HANZI) {
131 $result .= Hanzi::decodeSegment($this->bitBuffer, $versionNumber);
132 } else {
133 throw new QRCodeDecoderException('invalid data mode');
134 }
135 }
136 return new DecoderResult(['rawBytes' => $this->bitBuffer, 'data' => $result, 'version' => $this->version, 'eccLevel' => $this->eccLevel, 'finderPatterns' => $this->detector->getFinderPatterns(), 'maskPattern' => $this->maskPattern, 'structuredAppendParity' => $parityData, 'structuredAppendSequence' => $symbolSequence]);
137 }
138 /**
139 *
140 */
141 private function decodeAlphanumSegment(int $versionNumber, bool $fc1InEffect) : string
142 {
143 $str = AlphaNum::decodeSegment($this->bitBuffer, $versionNumber);
144 // See section 6.4.8.1, 6.4.8.2
145 if ($fc1InEffect) {
146 // ???
147 // We need to massage the result a bit if in an FNC1 mode:
148 $str = str_replace(chr(0x1d), '%', $str);
149 $str = str_replace('%%', '%', $str);
150 }
151 return $str;
152 }
153 }
154