| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- <?php
- /**
- * Class BitBuffer
- *
- * @created 25.11.2015
- * @author Smiley <smiley@chillerlan.net>
- * @copyright 2015 Smiley
- * @license MIT
- */
- namespace chillerlan\QRCode\Common;
- use InvalidArgumentException;
- use function count, floor;
- /**
- * Holds the raw binary data
- */
- final class BitBuffer{
- /**
- * The buffer content
- *
- * @var int[]
- */
- private array $buffer;
- /**
- * Length of the content (bits)
- */
- private int $length;
- private int $bytesRead = 0;
- private int $bitsRead = 0;
- /**
- * BitBuffer constructor.
- */
- public function __construct(array $bytes = null){
- $this->buffer = $bytes ?? [];
- $this->length = count($this->buffer);
- }
- /**
- * clears the buffer
- */
- public function clear():BitBuffer{
- $this->buffer = [];
- $this->length = 0;
- return $this;
- }
- /**
- * appends a sequence of bits
- */
- public function put(int $num, int $length):BitBuffer{
- for($i = 0; $i < $length; $i++){
- $this->putBit((($num >> ($length - $i - 1)) & 1) === 1);
- }
- return $this;
- }
- /**
- * appends a single bit
- */
- public function putBit(bool $bit):BitBuffer{
- $bufIndex = (int)floor($this->length / 8);
- if(count($this->buffer) <= $bufIndex){
- $this->buffer[] = 0;
- }
- if($bit === true){
- $this->buffer[$bufIndex] |= (0x80 >> ($this->length % 8));
- }
- $this->length++;
- return $this;
- }
- /**
- * returns the current buffer length
- */
- public function getLength():int{
- return $this->length;
- }
- /**
- * returns the buffer content
- */
- public function getBuffer():array{
- return $this->buffer;
- }
- /**
- * @return int number of bits that can be read successfully
- */
- public function available():int{
- return 8 * ($this->length - $this->bytesRead) - $this->bitsRead;
- }
- /**
- * @author Sean Owen, ZXing
- *
- * @param int $numBits number of bits to read
- *
- * @return int representing the bits read. The bits will appear as the least-significant
- * bits of the int
- * @throws InvalidArgumentException if numBits isn't in [1,32] or more than is available
- */
- public function read(int $numBits):int{
- if($numBits < 1 || $numBits > 32 || $numBits > $this->available()){
- throw new InvalidArgumentException('invalid $numBits: '.$numBits);
- }
- $result = 0;
- // First, read remainder from current byte
- if($this->bitsRead > 0){
- $bitsLeft = 8 - $this->bitsRead;
- $toRead = $numBits < $bitsLeft ? $numBits : $bitsLeft;
- $bitsToNotRead = $bitsLeft - $toRead;
- $mask = (0xff >> (8 - $toRead)) << $bitsToNotRead;
- $result = ($this->buffer[$this->bytesRead] & $mask) >> $bitsToNotRead;
- $numBits -= $toRead;
- $this->bitsRead += $toRead;
- if($this->bitsRead == 8){
- $this->bitsRead = 0;
- $this->bytesRead++;
- }
- }
- // Next read whole bytes
- if($numBits > 0){
- while($numBits >= 8){
- $result = ($result << 8) | ($this->buffer[$this->bytesRead] & 0xff);
- $this->bytesRead++;
- $numBits -= 8;
- }
- // Finally read a partial byte
- if($numBits > 0){
- $bitsToNotRead = 8 - $numBits;
- $mask = (0xff >> $bitsToNotRead) << $bitsToNotRead;
- $result = ($result << $numBits) | (($this->buffer[$this->bytesRead] & $mask) >> $bitsToNotRead);
- $this->bitsRead += $numBits;
- }
- }
- return $result;
- }
- }
|