# woocommerce-pos/1.10.20/vendor_prefixed/chillerlan/php-qrcode/src/Data/QRData.php

WCPOS – Point of Sale (POS) plugin for WooCommerce, version 1.10.20. 222 lines.

- Page: https://pluginprobe.com/plugins/woocommerce-pos/1.10.20/code/vendor_prefixed/chillerlan/php-qrcode/src/Data/QRData.php
- Raw: https://pluginprobe.com/plugins/woocommerce-pos/1.10.20/raw/vendor_prefixed/chillerlan/php-qrcode/src/Data/QRData.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.20/code/vendor_prefixed/chillerlan/php-qrcode/src/Data/QRData.php#L10-L20`.

```php
<?php

/**
 * Class QRData
 *
 * @created      25.11.2015
 * @author       Smiley <smiley@chillerlan.net>
 * @copyright    2015 Smiley
 * @license      MIT
 */
namespace WCPOS\Vendor\chillerlan\QRCode\Data;

use WCPOS\Vendor\chillerlan\QRCode\Common\BitBuffer;
use WCPOS\Vendor\chillerlan\QRCode\Common\EccLevel;
use WCPOS\Vendor\chillerlan\QRCode\Common\Mode;
use WCPOS\Vendor\chillerlan\QRCode\Common\Version;
use WCPOS\Vendor\chillerlan\Settings\SettingsContainerInterface;
use function count, sprintf;
/**
 * Processes the binary data and maps it on a QRMatrix which is then being returned
 */
final class QRData
{
    /**
     * the options instance
     *
     * @var \chillerlan\Settings\SettingsContainerInterface|\chillerlan\QRCode\QROptions
     */
    private SettingsContainerInterface $options;
    /**
     * a BitBuffer instance
     */
    private BitBuffer $bitBuffer;
    /**
     * an EccLevel instance
     */
    private EccLevel $eccLevel;
    /**
     * current QR Code version
     */
    private Version $version;
    /**
     * @var \chillerlan\QRCode\Data\QRDataModeInterface[]
     */
    private array $dataSegments = [];
    /**
     * Max bits for the current ECC mode
     *
     * @var int[]
     */
    private array $maxBitsForEcc;
    /**
     * QRData constructor.
     */
    public function __construct(SettingsContainerInterface $options, array $dataSegments = [])
    {
        $this->options = $options;
        $this->bitBuffer = new BitBuffer();
        $this->eccLevel = new EccLevel($this->options->eccLevel);
        $this->maxBitsForEcc = $this->eccLevel->getMaxBits();
        $this->setData($dataSegments);
    }
    /**
     * Sets the data string (internally called by the constructor)
     *
     * Subsequent calls will overwrite the current state - use the QRCode::add*Segement() method instead
     *
     * @param \chillerlan\QRCode\Data\QRDataModeInterface[] $dataSegments
     */
    public function setData(array $dataSegments) : self
    {
        $this->dataSegments = $dataSegments;
        $this->version = $this->getMinimumVersion();
        $this->bitBuffer->clear();
        $this->writeBitBuffer();
        return $this;
    }
    /**
     * Returns the current BitBuffer instance
     *
     * @codeCoverageIgnore
     */
    public function getBitBuffer() : BitBuffer
    {
        return $this->bitBuffer;
    }
    /**
     * Sets a BitBuffer object
     *
     * This can be used instead of setData(), however, the version auto-detection is not available in this case.
     * The version needs to match the length bits range for the data mode the data has been encoded with,
     * additionally the bit array needs to contain enough pad bits.
     *
     * @throws \chillerlan\QRCode\Data\QRCodeDataException
     */
    public function setBitBuffer(BitBuffer $bitBuffer) : self
    {
        if ($this->options->version === Version::AUTO) {
            throw new QRCodeDataException('version auto detection is not available');
        }
        if ($bitBuffer->getLength() === 0) {
            throw new QRCodeDataException('the given BitBuffer is empty');
        }
        $this->dataSegments = [];
        $this->bitBuffer = $bitBuffer;
        $this->version = new Version($this->options->version);
        return $this;
    }
    /**
     * returns a fresh matrix object with the data written and masked with the given $maskPattern
     */
    public function writeMatrix() : QRMatrix
    {
        return (new QRMatrix($this->version, $this->eccLevel))->initFunctionalPatterns()->writeCodewords($this->bitBuffer);
    }
    /**
     * estimates the total length of the several mode segments in order to guess the minimum version
     *
     * @throws \chillerlan\QRCode\Data\QRCodeDataException
     */
    public function estimateTotalBitLength() : int
    {
        $length = 0;
        foreach ($this->dataSegments as $segment) {
            // data length of the current segment
            $length += $segment->getLengthInBits();
            // +4 bits for the mode descriptor
            $length += 4;
            // Hanzi mode sets an additional 4 bit long subset identifier
            if ($segment instanceof Hanzi) {
                $length += 4;
            }
        }
        $provisionalVersion = null;
        foreach ($this->maxBitsForEcc as $version => $maxBits) {
            if ($length <= $maxBits) {
                $provisionalVersion = $version;
            }
        }
        if ($provisionalVersion !== null) {
            // add character count indicator bits for the provisional version
            foreach ($this->dataSegments as $segment) {
                $length += Mode::getLengthBitsForVersion($segment::DATAMODE, $provisionalVersion);
            }
            // it seems that in some cases the estimated total length is not 100% accurate,
            // so we substract 4 bits from the total when not in mixed mode
            if (count($this->dataSegments) <= 1) {
                $length -= 4;
            }
            // we've got a match!
            // or let's see if there's a higher version number available
            if ($length <= $this->maxBitsForEcc[$provisionalVersion] || isset($this->maxBitsForEcc[$provisionalVersion + 1])) {
                return $length;
            }
        }
        throw new QRCodeDataException(sprintf('estimated data exceeds %d bits', $length));
    }
    /**
     * returns the minimum version number for the given string
     *
     * @throws \chillerlan\QRCode\Data\QRCodeDataException
     */
    public function getMinimumVersion() : Version
    {
        if ($this->options->version !== Version::AUTO) {
            return new Version($this->options->version);
        }
        $total = $this->estimateTotalBitLength();
        // guess the version number within the given range
        for ($version = $this->options->versionMin; $version <= $this->options->versionMax; $version++) {
            if ($total <= $this->maxBitsForEcc[$version] - 4) {
                return new Version($version);
            }
        }
        // it's almost impossible to run into this one as $this::estimateTotalBitLength() would throw first
        throw new QRCodeDataException('failed to guess minimum version');
        // @codeCoverageIgnore
    }
    /**
     * creates a BitBuffer and writes the string data to it
     *
     * @throws \chillerlan\QRCode\Data\QRCodeDataException on data overflow
     */
    private function writeBitBuffer() : void
    {
        $MAX_BITS = $this->eccLevel->getMaxBitsForVersion($this->version);
        foreach ($this->dataSegments as $segment) {
            $segment->write($this->bitBuffer, $this->version->getVersionNumber());
        }
        // overflow, likely caused due to invalid version setting
        if ($this->bitBuffer->getLength() > $MAX_BITS) {
            throw new QRCodeDataException(sprintf('code length overflow. (%d > %d bit)', $this->bitBuffer->getLength(), $MAX_BITS));
        }
        // add terminator (ISO/IEC 18004:2000 Table 2)
        if ($this->bitBuffer->getLength() + 4 <= $MAX_BITS) {
            $this->bitBuffer->put(Mode::TERMINATOR, 4);
        }
        // Padding: ISO/IEC 18004:2000 8.4.9 Bit stream to codeword conversion
        // if the final codeword is not exactly 8 bits in length, it shall be made 8 bits long
        // by the addition of padding bits with binary value 0
        while ($this->bitBuffer->getLength() % 8 !== 0) {
            if ($this->bitBuffer->getLength() === $MAX_BITS) {
                break;
            }
            $this->bitBuffer->putBit(\false);
        }
        // The message bit stream shall then be extended to fill the data capacity of the symbol
        // corresponding to the Version and Error Correction Level, by the addition of the Pad
        // Codewords 11101100 and 00010001 alternately.
        $alternate = \false;
        while ($this->bitBuffer->getLength() + 8 <= $MAX_BITS) {
            $this->bitBuffer->put($alternate ? 0b10001 : 0b11101100, 8);
            $alternate = !$alternate;
        }
        // In certain versions of symbol, it may be necessary to add 3, 4 or 7 Remainder Bits (all zeros)
        // to the end of the message in order exactly to fill the symbol capacity
        while ($this->bitBuffer->getLength() <= $MAX_BITS) {
            $this->bitBuffer->putBit(\false);
        }
    }
}

```
