# woocommerce-pos/1.10.19/vendor_prefixed/chillerlan/php-qrcode/src/Decoder/Decoder.php

WCPOS – Point of Sale (POS) plugin for WooCommerce, version 1.10.19. 154 lines.

- Page: https://pluginprobe.com/plugins/woocommerce-pos/1.10.19/code/vendor_prefixed/chillerlan/php-qrcode/src/Decoder/Decoder.php
- Raw: https://pluginprobe.com/plugins/woocommerce-pos/1.10.19/raw/vendor_prefixed/chillerlan/php-qrcode/src/Decoder/Decoder.php
- Modified: 2026-06-09T13:55:26+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/woocommerce-pos/1.10.19/code/vendor_prefixed/chillerlan/php-qrcode/src/Decoder/Decoder.php#L10-L20`.

```php
<?php

/**
 * Class Decoder
 *
 * @created      17.01.2021
 * @author       ZXing Authors
 * @author       Smiley <smiley@chillerlan.net>
 * @copyright    2021 Smiley
 * @license      Apache-2.0
 */
namespace WCPOS\Vendor\chillerlan\QRCode\Decoder;

use WCPOS\Vendor\chillerlan\QRCode\Common\BitBuffer;
use WCPOS\Vendor\chillerlan\QRCode\Common\EccLevel;
use WCPOS\Vendor\chillerlan\QRCode\Common\LuminanceSourceInterface;
use WCPOS\Vendor\chillerlan\QRCode\Common\MaskPattern;
use WCPOS\Vendor\chillerlan\QRCode\Common\Mode;
use WCPOS\Vendor\chillerlan\QRCode\Common\Version;
use WCPOS\Vendor\chillerlan\QRCode\Data\AlphaNum;
use WCPOS\Vendor\chillerlan\QRCode\Data\Byte;
use WCPOS\Vendor\chillerlan\QRCode\Data\ECI;
use WCPOS\Vendor\chillerlan\QRCode\Data\Hanzi;
use WCPOS\Vendor\chillerlan\QRCode\Data\Kanji;
use WCPOS\Vendor\chillerlan\QRCode\Data\Number;
use WCPOS\Vendor\chillerlan\QRCode\Detector\Detector;
use Throwable;
use function chr, str_replace;
/**
 * The main class which implements QR Code decoding -- as opposed to locating and extracting
 * the QR Code from an image.
 *
 * @author Sean Owen
 */
final class Decoder
{
    private ?Version $version = null;
    private ?EccLevel $eccLevel = null;
    private ?MaskPattern $maskPattern = null;
    private BitBuffer $bitBuffer;
    private Detector $detector;
    /**
     * Decodes a QR Code represented as a BitMatrix.
     * A 1 or "true" is taken to mean a black module.
     *
     * @throws \Throwable|\chillerlan\QRCode\Decoder\QRCodeDecoderException
     */
    public function decode(LuminanceSourceInterface $source) : DecoderResult
    {
        $this->detector = new Detector($source);
        $matrix = $this->detector->detect();
        try {
            // clone the BitMatrix to avoid errors in case we run into mirroring
            return $this->decodeMatrix(clone $matrix);
        } catch (Throwable $e) {
            try {
                /*
                 * Prepare for a mirrored reading.
                 *
                 * Since we're here, this means we have successfully detected some kind
                 * of version and format information when mirrored. This is a good sign,
                 * that the QR code may be mirrored, and we should try once more with a
                 * mirrored content.
                 */
                return $this->decodeMatrix($matrix->resetVersionInfo()->mirrorDiagonal());
            } catch (Throwable $f) {
                // Throw the exception from the original reading
                throw $e;
            }
        }
    }
    /**
     * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
     */
    private function decodeMatrix(BitMatrix $matrix) : DecoderResult
    {
        // Read raw codewords
        $rawCodewords = $matrix->readCodewords();
        $this->version = $matrix->getVersion();
        $this->eccLevel = $matrix->getEccLevel();
        $this->maskPattern = $matrix->getMaskPattern();
        if ($this->version === null || $this->eccLevel === null || $this->maskPattern === null) {
            throw new QRCodeDecoderException('unable to read version or format info');
            // @codeCoverageIgnore
        }
        $resultBytes = (new ReedSolomonDecoder($this->version, $this->eccLevel))->decode($rawCodewords);
        return $this->decodeBitStream($resultBytes);
    }
    /**
     * Decode the contents of that stream of bytes
     *
     * @throws \chillerlan\QRCode\Decoder\QRCodeDecoderException
     */
    private function decodeBitStream(BitBuffer $bitBuffer) : DecoderResult
    {
        $this->bitBuffer = $bitBuffer;
        $versionNumber = $this->version->getVersionNumber();
        $symbolSequence = -1;
        $parityData = -1;
        $fc1InEffect = \false;
        $result = '';
        // While still another segment to read...
        while ($this->bitBuffer->available() >= 4) {
            $datamode = $this->bitBuffer->read(4);
            // mode is encoded by 4 bits
            // OK, assume we're done
            if ($datamode === Mode::TERMINATOR) {
                break;
            } elseif ($datamode === Mode::NUMBER) {
                $result .= Number::decodeSegment($this->bitBuffer, $versionNumber);
            } elseif ($datamode === Mode::ALPHANUM) {
                $result .= $this->decodeAlphanumSegment($versionNumber, $fc1InEffect);
            } elseif ($datamode === Mode::BYTE) {
                $result .= Byte::decodeSegment($this->bitBuffer, $versionNumber);
            } elseif ($datamode === Mode::KANJI) {
                $result .= Kanji::decodeSegment($this->bitBuffer, $versionNumber);
            } elseif ($datamode === Mode::STRCTURED_APPEND) {
                if ($this->bitBuffer->available() < 16) {
                    throw new QRCodeDecoderException('structured append: not enough bits left');
                }
                // sequence number and parity is added later to the result metadata
                // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
                $symbolSequence = $this->bitBuffer->read(8);
                $parityData = $this->bitBuffer->read(8);
            } elseif ($datamode === Mode::FNC1_FIRST || $datamode === Mode::FNC1_SECOND) {
                // We do little with FNC1 except alter the parsed result a bit according to the spec
                $fc1InEffect = \true;
            } elseif ($datamode === Mode::ECI) {
                $result .= ECI::decodeSegment($this->bitBuffer, $versionNumber);
            } elseif ($datamode === Mode::HANZI) {
                $result .= Hanzi::decodeSegment($this->bitBuffer, $versionNumber);
            } else {
                throw new QRCodeDecoderException('invalid data mode');
            }
        }
        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]);
    }
    /**
     *
     */
    private function decodeAlphanumSegment(int $versionNumber, bool $fc1InEffect) : string
    {
        $str = AlphaNum::decodeSegment($this->bitBuffer, $versionNumber);
        // See section 6.4.8.1, 6.4.8.2
        if ($fc1InEffect) {
            // ???
            // We need to massage the result a bit if in an FNC1 mode:
            $str = str_replace(chr(0x1d), '%', $str);
            $str = str_replace('%%', '%', $str);
        }
        return $str;
    }
}

```
