diff options
Diffstat (limited to 'vendor/chillerlan/php-qrcode/src/Data/Number.php')
-rw-r--r-- | vendor/chillerlan/php-qrcode/src/Data/Number.php | 135 |
1 files changed, 109 insertions, 26 deletions
diff --git a/vendor/chillerlan/php-qrcode/src/Data/Number.php b/vendor/chillerlan/php-qrcode/src/Data/Number.php index 0a905b13e..3e4238fdc 100644 --- a/vendor/chillerlan/php-qrcode/src/Data/Number.php +++ b/vendor/chillerlan/php-qrcode/src/Data/Number.php @@ -2,9 +2,7 @@ /** * Class Number * - * @filesource Number.php * @created 26.11.2015 - * @package chillerlan\QRCode\Data * @author Smiley <smiley@chillerlan.net> * @copyright 2015 Smiley * @license MIT @@ -12,9 +10,8 @@ namespace chillerlan\QRCode\Data; -use chillerlan\QRCode\QRCode; - -use function ord, sprintf, str_split, substr; +use chillerlan\QRCode\Common\{BitBuffer, Mode}; +use function ceil, intdiv, substr, unpack; /** * Numeric mode: decimal digits 0 to 9 @@ -22,56 +19,142 @@ use function ord, sprintf, str_split, substr; * ISO/IEC 18004:2000 Section 8.3.2 * ISO/IEC 18004:2000 Section 8.4.2 */ -final class Number extends QRDataAbstract{ +final class Number extends QRDataModeAbstract{ - protected int $datamode = QRCode::DATA_NUMBER; + /** + * @inheritDoc + */ + public const DATAMODE = Mode::NUMBER; + + /** + * @inheritDoc + */ + public function getLengthInBits():int{ + return (int)ceil($this->getCharCount() * (10 / 3)); + } - protected array $lengthBits = [10, 12, 14]; + /** + * @inheritDoc + */ + public static function validateString(string $string):bool{ + return (bool)preg_match('/^\d+$/', $string); + } /** - * @inheritdoc + * @inheritDoc */ - protected function write(string $data):void{ + public function write(BitBuffer $bitBuffer, int $versionNumber):QRDataModeInterface{ + $len = $this->getCharCount(); + + $bitBuffer + ->put(self::DATAMODE, 4) + ->put($len, $this::getLengthBits($versionNumber)) + ; + $i = 0; - while($i + 2 < $this->strlen){ - $this->bitBuffer->put($this->parseInt(substr($data, $i, 3)), 10); + // encode numeric triplets in 10 bits + while(($i + 2) < $len){ + $bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10); $i += 3; } - if($i < $this->strlen){ + if($i < $len){ - if($this->strlen - $i === 1){ - $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 1)), 4); + // encode 2 remaining numbers in 7 bits + if(($len - $i) === 2){ + $bitBuffer->put($this->parseInt(substr($this->data, $i, 2)), 7); } - elseif($this->strlen - $i === 2){ - $this->bitBuffer->put($this->parseInt(substr($data, $i, $i + 2)), 7); + // encode one remaining number in 4 bits + elseif(($len - $i) === 1){ + $bitBuffer->put($this->parseInt(substr($this->data, $i, 1)), 4); } } + return $this; } /** * get the code for the given numeric string * - * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence + * @throws \chillerlan\QRCode\Data\QRCodeDataException */ - protected function parseInt(string $string):int{ + private function parseInt(string $string):int{ $num = 0; - foreach(str_split($string) as $chr){ - $c = ord($chr); + $ords = unpack('C*', $string); - if(!isset($this::CHAR_MAP_NUMBER[$chr])){ - throw new QRCodeDataException(sprintf('illegal char: "%s" [%d]', $chr, $c)); - } + if($ords === false){ + throw new QRCodeDataException('unpack() error'); + } - $c = $c - 48; // ord('0') - $num = $num * 10 + $c; + foreach($ords as $ord){ + $num = ($num * 10 + $ord - 48); } return $num; } + /** + * @inheritDoc + * + * @throws \chillerlan\QRCode\Data\QRCodeDataException + */ + public static function decodeSegment(BitBuffer $bitBuffer, int $versionNumber):string{ + $length = $bitBuffer->read(self::getLengthBits($versionNumber)); + $result = ''; + // Read three digits at a time + while($length >= 3){ + // Each 10 bits encodes three digits + if($bitBuffer->available() < 10){ + throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore + } + + $threeDigitsBits = $bitBuffer->read(10); + + if($threeDigitsBits >= 1000){ + throw new QRCodeDataException('error decoding numeric value'); + } + + $result .= intdiv($threeDigitsBits, 100); + $result .= (intdiv($threeDigitsBits, 10) % 10); + $result .= ($threeDigitsBits % 10); + + $length -= 3; + } + + if($length === 2){ + // Two digits left over to read, encoded in 7 bits + if($bitBuffer->available() < 7){ + throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore + } + + $twoDigitsBits = $bitBuffer->read(7); + + if($twoDigitsBits >= 100){ + throw new QRCodeDataException('error decoding numeric value'); + } + + $result .= intdiv($twoDigitsBits, 10); + $result .= ($twoDigitsBits % 10); + } + elseif($length === 1){ + // One digit left over to read + if($bitBuffer->available() < 4){ + throw new QRCodeDataException('not enough bits available'); // @codeCoverageIgnore + } + + $digitBits = $bitBuffer->read(4); + + if($digitBits >= 10){ + throw new QRCodeDataException('error decoding numeric value'); + } + + $result .= $digitBits; + } + + return $result; + } + } |