![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/spomky-labs/pki-framework/src/ASN1/Util/ |
<?php declare(strict_types=1); namespace SpomkyLabs\Pki\ASN1\Util; use function assert; use Brick\Math\BigInteger; use function count; use function is_array; use function ord; use OutOfBoundsException; use RuntimeException; use SpomkyLabs\Pki\ASN1\Type\Primitive\BitString; /** * Class to handle a bit string as a field of flags. */ final class Flags { /** * Flag octets. */ private string $_flags; /** * @param BigInteger|int|string $flags Flags * @param int $_width The number of flags. If width is larger than * number of bits in $flags, zeroes are prepended * to flag field. */ private function __construct( BigInteger|int|string $flags, private readonly int $_width ) { if ($_width === 0) { $this->_flags = ''; return; } // calculate number of unused bits in last octet $last_octet_bits = $_width % 8; $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; // mask bits outside bitfield width $num = BigInteger::of($flags); $mask = BigInteger::of(1)->shiftedLeft($_width)->minus(1); $num = $num->and($mask); // shift towards MSB if needed $data = $num->shiftedLeft($unused_bits) ->toBytes(false); $octets = unpack('C*', $data); assert(is_array($octets), new RuntimeException('unpack() failed')); $bits = count($octets) * 8; // pad with zeroes while ($bits < $_width) { array_unshift($octets, 0); $bits += 8; } $this->_flags = pack('C*', ...$octets); } public static function create(BigInteger|int|string $flags, int $_width): self { return new self($flags, $_width); } /** * Initialize from `BitString`. */ public static function fromBitString(BitString $bs, int $width): self { $num_bits = $bs->numBits(); $data = $bs->string(); $num = $data === '' ? BigInteger::of(0) : BigInteger::fromBytes($bs->string(), false); $num = $num->shiftedRight($bs->unusedBits()); if ($num_bits < $width) { $num = $num->shiftedLeft($width - $num_bits); } return self::create($num, $width); } /** * Check whether a bit at given index is set. * * Index 0 is the leftmost bit. */ public function test(int $idx): bool { if ($idx >= $this->_width) { throw new OutOfBoundsException('Index is out of bounds.'); } // octet index $oi = (int) floor($idx / 8); $byte = $this->_flags[$oi]; // bit index $bi = $idx % 8; // index 0 is the most significant bit in byte $mask = 0x01 << (7 - $bi); return (ord($byte) & $mask) > 0; } /** * Get flags as an octet string. * * Zeroes are appended to the last octet if width is not divisible by 8. */ public function string(): string { return $this->_flags; } /** * Get flags as a base 10 integer. * * @return string Integer as a string */ public function number(): string { $num = BigInteger::fromBytes($this->_flags, false); $last_octet_bits = $this->_width % 8; $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; $num = $num->shiftedRight($unused_bits); return $num->toBase(10); } /** * Get flags as an integer. */ public function intNumber(): int { $num = BigInt::create($this->number()); return $num->toInt(); } /** * Get flags as a `BitString` object. * * Unused bits are set accordingly. Trailing zeroes are not stripped. */ public function bitString(): BitString { $last_octet_bits = $this->_width % 8; $unused_bits = $last_octet_bits !== 0 ? 8 - $last_octet_bits : 0; return BitString::create($this->_flags, $unused_bits); } }