codemasher 5 лет назад
Родитель
Сommit
8bd573ddfd

+ 13 - 8
src/Data/AlphaNum.php

@@ -12,6 +12,7 @@
 
 namespace chillerlan\QRCode\Data;
 
+use chillerlan\QRCode\Helpers\BitBuffer;
 use chillerlan\QRCode\QRCode;
 
 use function ceil, ord, sprintf, str_split;
@@ -38,15 +39,13 @@ final class AlphaNum extends QRDataModeAbstract{
 		'+' => 40, '-' => 41, '.' => 42, '/' => 43, ':' => 44,
 	];
 
-	protected int $datamode = QRCode::DATA_ALPHANUM;
-
 	protected array $lengthBits = [9, 11, 13];
 
 	/**
 	 * @inheritdoc
 	 */
 	public function getLengthInBits():int{
-		return (int)ceil($this->getLength() * (11 / 2));
+		return (int)ceil($this->getCharCount() * (11 / 2));
 	}
 
 	/**
@@ -66,16 +65,22 @@ final class AlphaNum extends QRDataModeAbstract{
 	/**
 	 * @inheritdoc
 	 */
-	public function write(int $version):void{
-		$this->writeSegmentHeader($version);
-		$len = $this->getLength();
+	public function write(BitBuffer $bitBuffer, int $version):void{
+		$len = $this->getCharCount();
+
+		$bitBuffer
+			->put(QRCode::DATA_ALPHANUM, 4)
+			->put($len, $this->getLengthBitsForVersion($version))
+		;
 
+		// encode 2 characters in 11 bits
 		for($i = 0; $i + 1 < $len; $i += 2){
-			$this->bitBuffer->put($this->getCharCode($this->data[$i]) * 45 + $this->getCharCode($this->data[$i + 1]), 11);
+			$bitBuffer->put($this->getCharCode($this->data[$i]) * 45 + $this->getCharCode($this->data[$i + 1]), 11);
 		}
 
+		// encode a remaining character in 6 bits
 		if($i < $len){
-			$this->bitBuffer->put($this->getCharCode($this->data[$i]), 6);
+			$bitBuffer->put($this->getCharCode($this->data[$i]), 6);
 		}
 
 	}

+ 12 - 8
src/Data/Byte.php

@@ -12,6 +12,7 @@
 
 namespace chillerlan\QRCode\Data;
 
+use chillerlan\QRCode\Helpers\BitBuffer;
 use chillerlan\QRCode\QRCode;
 
 use function ord;
@@ -24,15 +25,13 @@ use function ord;
  */
 final class Byte extends QRDataModeAbstract{
 
-	protected int $datamode = QRCode::DATA_BYTE;
-
 	protected array $lengthBits = [8, 16, 16];
 
 	/**
 	 * @inheritdoc
 	 */
 	public function getLengthInBits():int{
-		return $this->getLength() * 8;
+		return $this->getCharCount() * 8;
 	}
 
 	/**
@@ -45,13 +44,18 @@ final class Byte extends QRDataModeAbstract{
 	/**
 	 * @inheritdoc
 	 */
-	public function write(int $version):void{
-		$this->writeSegmentHeader($version);
-		$len = $this->getLength();
-		$i   = 0;
+	public function write(BitBuffer $bitBuffer, int $version):void{
+		$len = $this->getCharCount();
+
+		$bitBuffer
+			->put(QRCode::DATA_BYTE, 4)
+			->put($len, $this->getLengthBitsForVersion($version))
+		;
+
+		$i = 0;
 
 		while($i < $len){
-			$this->bitBuffer->put(ord($this->data[$i]), 8);
+			$bitBuffer->put(ord($this->data[$i]), 8);
 			$i++;
 		}
 

+ 13 - 11
src/Data/Kanji.php

@@ -25,12 +25,10 @@ use function mb_convert_encoding, mb_detect_encoding, mb_strlen, ord, sprintf, s
  */
 final class Kanji extends QRDataModeAbstract{
 
-	protected int $datamode = QRCode::DATA_KANJI;
-
 	protected array $lengthBits = [8, 10, 12];
 
-	public function __construct(BitBuffer $bitBuffer, string $data){
-		parent::__construct($bitBuffer, $data);
+	public function __construct(string $data){
+		parent::__construct($data);
 
 		/** @noinspection PhpFieldAssignmentTypeMismatchInspection */
 		$this->data = mb_convert_encoding($this->data, 'SJIS', mb_detect_encoding($this->data));
@@ -39,7 +37,7 @@ final class Kanji extends QRDataModeAbstract{
 	/**
 	 * @inheritdoc
 	 */
-	protected function getLength():int{
+	protected function getCharCount():int{
 		return mb_strlen($this->data, 'SJIS');
 	}
 
@@ -47,7 +45,7 @@ final class Kanji extends QRDataModeAbstract{
 	 * @inheritdoc
 	 */
 	public function getLengthInBits():int{
-		return $this->getLength() * 13;
+		return $this->getCharCount() * 13;
 	}
 
 	/**
@@ -75,9 +73,14 @@ final class Kanji extends QRDataModeAbstract{
 	 *
 	 * @throws \chillerlan\QRCode\Data\QRCodeDataException on an illegal character occurence
 	 */
-	public function write(int $version):void{
-		$this->writeSegmentHeader($version);
-		$len = strlen($this->data); // not self::getLength() - we need 8-bit length
+	public function write(BitBuffer $bitBuffer, int $version):void{
+
+		$bitBuffer
+			->put(QRCode::DATA_KANJI, 4)
+			->put($this->getCharCount(), $this->getLengthBitsForVersion($version))
+		;
+
+		$len = strlen($this->data);
 
 		for($i = 0; $i + 1 < $len; $i += 2){
 			$c = ((0xff & ord($this->data[$i])) << 8) | (0xff & ord($this->data[$i + 1]));
@@ -92,8 +95,7 @@ final class Kanji extends QRDataModeAbstract{
 				throw new QRCodeDataException(sprintf('illegal char at %d [%d]', $i + 1, $c));
 			}
 
-			$this->bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13);
-
+			$bitBuffer->put(((($c >> 8) & 0xff) * 0xC0) + ($c & 0xff), 13);
 		}
 
 		if($i < $len){

+ 19 - 12
src/Data/Number.php

@@ -12,6 +12,7 @@
 
 namespace chillerlan\QRCode\Data;
 
+use chillerlan\QRCode\Helpers\BitBuffer;
 use chillerlan\QRCode\QRCode;
 
 use function ceil, ord, sprintf, str_split, substr;
@@ -31,15 +32,13 @@ 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 int $datamode = QRCode::DATA_NUMBER;
-
 	protected array $lengthBits = [10, 12, 14];
 
 	/**
 	 * @inheritdoc
 	 */
 	public function getLengthInBits():int{
-		return (int)ceil($this->getLength() * (10 / 3));
+		return (int)ceil($this->getCharCount() * (10 / 3));
 	}
 
 	/**
@@ -59,23 +58,31 @@ final class Number extends QRDataModeAbstract{
 	/**
 	 * @inheritdoc
 	 */
-	public function write(int $version):void{
-		$this->writeSegmentHeader($version);
-		$len = $this->getLength();
-		$i   = 0;
+	public function write(BitBuffer $bitBuffer, int $version):void{
+		$len = $this->getCharCount();
+
+		$bitBuffer
+			->put(QRCode::DATA_NUMBER, 4)
+			->put($len, $this->getLengthBitsForVersion($version))
+		;
+
+		$i = 0;
 
+		// encode numeric triplets in 10 bits
 		while($i + 2 < $len){
-			$this->bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10);
+			$bitBuffer->put($this->parseInt(substr($this->data, $i, 3)), 10);
 			$i += 3;
 		}
 
 		if($i < $len){
 
-			if($len - $i === 1){
-				$this->bitBuffer->put($this->parseInt(substr($this->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($len - $i === 2){
-				$this->bitBuffer->put($this->parseInt(substr($this->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);
 			}
 
 		}

+ 2 - 2
src/Data/QRData.php

@@ -188,7 +188,7 @@ class QRData{
 		foreach($dataSegments as $segment){
 			[$class, $data] = $segment;
 
-			$this->dataSegments[] = new $class($this->bitBuffer, $data);
+			$this->dataSegments[] = new $class($data);
 		}
 
 		$this->version = $this->options->version === QRCode::VERSION_AUTO
@@ -271,7 +271,7 @@ class QRData{
 		$MAX_BITS = $this->maxBitsForEcc[$this->version];
 
 		foreach($this->dataSegments as $segment){
-			$segment->write($this->version);
+			$segment->write($this->bitBuffer, $this->version);
 		}
 
 		// overflow, likely caused due to invalid version setting

+ 2 - 32
src/Data/QRDataModeAbstract.php

@@ -18,11 +18,6 @@ use chillerlan\QRCode\Helpers\BitBuffer;
  */
 abstract class QRDataModeAbstract implements QRDataModeInterface{
 
-	/**
-	 * the current data mode: Num, Alphanum, Kanji, Byte
-	 */
-	protected int $datamode;
-
 	/**
 	 * mode length bits for the version breakpoints 1-9, 10-26 and 27-40
 	 *
@@ -35,30 +30,17 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
 	 */
 	protected string $data;
 
-	/**
-	 * a BitBuffer instance
-	 */
-	protected BitBuffer $bitBuffer;
-
 	/**
 	 * QRDataModeAbstract constructor.
-	 *
-	 * @throws \chillerlan\QRCode\Data\QRCodeDataException
 	 */
-	public function __construct(BitBuffer $bitBuffer, string $data){
-		// do we need this here? we check during write anyways.
-#		if(!static::validateString($data)){
-#			throw new QRCodeDataException('invalid data string');
-#		}
-
-		$this->bitBuffer = $bitBuffer;
+	public function __construct(string $data){
 		$this->data      = $data;
 	}
 
 	/**
 	 * returns the character count of the $data string
 	 */
-	protected function getLength():int{
+	protected function getCharCount():int{
 		return strlen($this->data);
 	}
 
@@ -86,16 +68,4 @@ abstract class QRDataModeAbstract implements QRDataModeInterface{
 		throw new QRCodeDataException(sprintf('invalid version number: %d', $version));
 	}
 
-	/**
-	 *
-	 */
-	protected function writeSegmentHeader(int $version):void{
-
-		$this->bitBuffer
-			->put($this->datamode, 4)
-			->put($this->getLength(), $this->getLengthBitsForVersion($version))
-		;
-
-	}
-
 }

+ 3 - 1
src/Data/QRDataModeInterface.php

@@ -12,6 +12,8 @@
 
 namespace chillerlan\QRCode\Data;
 
+use chillerlan\QRCode\Helpers\BitBuffer;
+
 /**
  * Specifies the methods reqired for the data modules (Number, Alphanum, Byte and Kanji)
  * and holds version information in several constants
@@ -38,6 +40,6 @@ interface QRDataModeInterface{
 	 *
 	 * @see \chillerlan\QRCode\Data\QRData::writeBitBuffer()
 	 */
-	public function write(int $version):void;
+	public function write(BitBuffer $bitBuffer, int $version):void;
 
 }