🛀 extract Mode

This commit is contained in:
codemasher
2020-11-21 21:52:19 +01:00
parent cbf8a990ca
commit 37a40571e6
11 changed files with 124 additions and 78 deletions
+88
View File
@@ -0,0 +1,88 @@
<?php
/**
* Class Mode
*
* @filesource Mode.php
* @created 19.11.2020
* @package chillerlan\QRCode\Common
* @author smiley <smiley@chillerlan.net>
* @copyright 2020 smiley
* @license MIT
*/
namespace chillerlan\QRCode\Common;
use chillerlan\QRCode\Data\{AlphaNum, Byte, Kanji, Number};
use chillerlan\QRCode\QRCodeException;
/**
* ISO 18004:2006, 6.4.1, Tables 2 and 3
*/
class Mode{
// ISO/IEC 18004:2000 Table 2
/** @var int */
public const DATA_TERMINATOR = 0b0000;
/** @var int */
public const DATA_NUMBER = 0b0001;
/** @var int */
public const DATA_ALPHANUM = 0b0010;
/** @var int */
public const DATA_BYTE = 0b0100;
/** @var int */
public const DATA_KANJI = 0b1000;
/** @var int */
public const DATA_STRCTURED_APPEND = 0b0011;
/** @var int */
public const DATA_FNC1_FIRST = 0b0101;
/** @var int */
public const DATA_FNC1_SECOND = 0b1001;
/** @var int */
public const DATA_ECI = 0b0111;
/**
* mode length bits for the version breakpoints 1-9, 10-26 and 27-40
*
* ISO/IEC 18004:2000 Table 3 - Number of bits in Character Count Indicator
*/
public const LENGTH_BITS = [
self::DATA_NUMBER => [10, 12, 14],
self::DATA_ALPHANUM => [9, 11, 13],
self::DATA_BYTE => [8, 16, 16],
self::DATA_KANJI => [8, 10, 12],
];
/**
* Map of data mode => interface (detection order)
*
* @var string[]
*/
public const DATA_INTERFACES = [
Mode::DATA_NUMBER => Number::class,
Mode::DATA_ALPHANUM => AlphaNum::class,
Mode::DATA_KANJI => Kanji::class,
Mode::DATA_BYTE => Byte::class,
];
/**
* returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
*
* @throws \chillerlan\QRCode\QRCodeException
*/
public static function getLengthBitsForVersion(int $mode, int $version):int{
if(!isset(self::LENGTH_BITS[$mode])){
throw new QRCodeException('invalid mode given');
}
foreach([9, 26, 40] as $key => $breakpoint){
if($version <= $breakpoint){
return self::LENGTH_BITS[$mode][$key];
}
}
throw new QRCodeException(sprintf('invalid version number: %d', $version));
}
}
+4 -4
View File
@@ -13,7 +13,7 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Common\Mode;
use function ceil, ord, sprintf, str_split;
@@ -39,7 +39,7 @@ final class AlphaNum extends QRDataModeAbstract{
'+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44,
];
protected array $lengthBits = [9, 11, 13];
protected int $datamode = Mode::DATA_ALPHANUM;
/**
* @inheritdoc
@@ -69,8 +69,8 @@ final class AlphaNum extends QRDataModeAbstract{
$len = $this->getCharCount();
$bitBuffer
->put(QRCode::DATA_ALPHANUM, 4)
->put($len, $this->getLengthBitsForVersion($version))
->put($this->datamode, 4)
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
;
// encode 2 characters in 11 bits
+4 -4
View File
@@ -13,7 +13,7 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Common\Mode;
use function ord;
@@ -25,7 +25,7 @@ use function ord;
*/
final class Byte extends QRDataModeAbstract{
protected array $lengthBits = [8, 16, 16];
protected int $datamode = Mode::DATA_BYTE;
/**
* @inheritdoc
@@ -48,8 +48,8 @@ final class Byte extends QRDataModeAbstract{
$len = $this->getCharCount();
$bitBuffer
->put(QRCode::DATA_BYTE, 4)
->put($len, $this->getLengthBitsForVersion($version))
->put($this->datamode, 4)
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
;
$i = 0;
+4 -2
View File
@@ -13,7 +13,7 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Common\Mode;
/**
* Adds an ECI Designator
@@ -59,6 +59,8 @@ class ECI extends QRDataModeAbstract{
*/
protected int $encoding;
protected int $datamode = Mode::DATA_ECI;
/**
* @inheritDoc
*/
@@ -87,7 +89,7 @@ class ECI extends QRDataModeAbstract{
*/
public function write(BitBuffer $bitBuffer, int $version):void{
$bitBuffer
->put(QRCode::DATA_ECI, 4)
->put($this->datamode, 4)
->put($this->encoding, 8)
;
}
+4 -4
View File
@@ -13,7 +13,7 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Common\Mode;
use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, strlen;
@@ -25,7 +25,7 @@ use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, s
*/
final class Kanji extends QRDataModeAbstract{
protected array $lengthBits = [8, 10, 12];
protected int $datamode = Mode::DATA_KANJI;
public function __construct(string $data){
parent::__construct($data);
@@ -76,8 +76,8 @@ final class Kanji extends QRDataModeAbstract{
public function write(BitBuffer $bitBuffer, int $version):void{
$bitBuffer
->put(QRCode::DATA_KANJI, 4)
->put($this->getCharCount(), $this->getLengthBitsForVersion($version))
->put($this->datamode, 4)
->put($this->getCharCount(), Mode::getLengthBitsForVersion($this->datamode, $version))
;
$len = strlen($this->data);
+4 -4
View File
@@ -13,7 +13,7 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Common\Mode;
use function ceil, ord, sprintf, str_split, substr;
@@ -32,7 +32,7 @@ final class Number extends QRDataModeAbstract{
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
];
protected array $lengthBits = [10, 12, 14];
protected int $datamode = Mode::DATA_NUMBER;
/**
* @inheritdoc
@@ -62,8 +62,8 @@ final class Number extends QRDataModeAbstract{
$len = $this->getCharCount();
$bitBuffer
->put(QRCode::DATA_NUMBER, 4)
->put($len, $this->getLengthBitsForVersion($version))
->put($this->datamode, 4)
->put($len, Mode::getLengthBitsForVersion($this->datamode, $version))
;
$i = 0;
+2 -1
View File
@@ -14,6 +14,7 @@ namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Helpers\{BitBuffer, Polynomial};
use chillerlan\QRCode\Common\Mode;
use chillerlan\Settings\SettingsContainerInterface;
use function array_column, array_combine, array_fill, array_keys, array_merge, count, max, range, sprintf;
@@ -221,7 +222,7 @@ class QRData{
foreach($this->dataSegments as $segment){
// data length in bits of the current segment +4 bits for each mode descriptor
$length += ($segment->getLengthInBits() + $segment->getLengthBits(0) + 4);
$length += ($segment->getLengthInBits() + Mode::LENGTH_BITS[$segment->getDataMode()][0] + 4);
if(!$segment instanceof ECI){
// mode length bits margin to the next breakpoint
+5 -26
View File
@@ -12,18 +12,14 @@
namespace chillerlan\QRCode\Data;
use chillerlan\QRCode\Helpers\BitBuffer;
/**
*/
abstract class QRDataModeAbstract implements QRDataModeInterface{
/**
* mode length bits for the version breakpoints 1-9, 10-26 and 27-40
*
* ISO/IEC 18004:2000 Table 3 - Number of bits in Character Count Indicator
* the current data mode: Num, Alphanum, Kanji, Byte
*/
protected array $lengthBits = [0, 0, 0];
protected int $datamode;
/**
* The data to write
@@ -34,7 +30,7 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
* QRDataModeAbstract constructor.
*/
public function __construct(string $data){
$this->data = $data;
$this->data = $data;
}
/**
@@ -47,25 +43,8 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
/**
* @inheritDoc
*/
public function getLengthBits(int $k):int{
return $this->lengthBits[$k] ?? 0;
}
/**
* returns the length bits for the version breakpoints 1-9, 10-26 and 27-40
*
* @throws \chillerlan\QRCode\Data\QRCodeDataException
* @codeCoverageIgnore
*/
protected function getLengthBitsForVersion(int $version):int{
foreach([9, 26, 40] as $key => $breakpoint){
if($version <= $breakpoint){
return $this->getLengthBits($key);
}
}
throw new QRCodeDataException(sprintf('invalid version number: %d', $version));
public function getDataMode():int{
return $this->datamode;
}
}
+2 -2
View File
@@ -21,9 +21,9 @@ use chillerlan\QRCode\Helpers\BitBuffer;
interface QRDataModeInterface{
/**
* returns the length bits for the given breakpoint [0,1,2]
* returns the current data mode constant
*/
public function getLengthBits(int $k):int;
public function getDataMode():int;
/**
* retruns the length in bits of the data string
+2 -26
View File
@@ -13,6 +13,7 @@
namespace chillerlan\QRCode;
use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, MaskPatternTester, Number, QRData, QRCodeDataException, QRMatrix};
use chillerlan\QRCode\Common\Mode;
use chillerlan\QRCode\Output\{
QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString
};
@@ -36,19 +37,6 @@ class QRCode{
/** @var int */
public const MASK_PATTERN_AUTO = -1;
// ISO/IEC 18004:2000 Table 2
/** @var int */
public const DATA_NUMBER = 0b0001;
/** @var int */
public const DATA_ALPHANUM = 0b0010;
/** @var int */
public const DATA_BYTE = 0b0100;
/** @var int */
public const DATA_KANJI = 0b1000;
/** @var int */
public const DATA_ECI = 0b0111;
// ISO/IEC 18004:2000 Tables 12, 25
/** @var int */
@@ -124,18 +112,6 @@ class QRCode{
],
];
/**
* Map of data mode => interface (detection order)
*
* @var string[]
*/
protected const DATA_INTERFACES = [
self::DATA_NUMBER => Number::class,
self::DATA_ALPHANUM => AlphaNum::class,
self::DATA_KANJI => Kanji::class,
self::DATA_BYTE => Byte::class,
];
/**
* A collection of one or more data segments of [classname, data] to write
*
@@ -175,7 +151,7 @@ class QRCode{
if($data !== null){
/** @var \chillerlan\QRCode\Data\QRDataModeInterface $dataInterface */
foreach($this::DATA_INTERFACES as $dataInterface){
foreach(Mode::DATA_INTERFACES as $dataInterface){
if($dataInterface::validateString($data)){
$this->addSegment($data, $dataInterface);
+5 -5
View File
@@ -12,8 +12,8 @@
namespace chillerlan\QRCodeTest\Helpers;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\Helpers\BitBuffer;
use chillerlan\QRCode\Common\Mode;
use PHPUnit\Framework\TestCase;
/**
@@ -29,10 +29,10 @@ final class BitBufferTest extends TestCase{
public function bitProvider():array{
return [
'number' => [QRCode::DATA_NUMBER, 16],
'alphanum' => [QRCode::DATA_ALPHANUM, 32],
'byte' => [QRCode::DATA_BYTE, 64],
'kanji' => [QRCode::DATA_KANJI, 128],
'number' => [Mode::DATA_NUMBER, 16],
'alphanum' => [Mode::DATA_ALPHANUM, 32],
'byte' => [Mode::DATA_BYTE, 64],
'kanji' => [Mode::DATA_KANJI, 128],
];
}