1<?php
2/**
3 * This file is part of the FreeDSx ASN1 package.
4 *
5 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11namespace FreeDSx\Asn1\Type;
12
13/**
14 * Represents a bit string type.
15 *
16 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
17 */
18class BitStringType extends AbstractType
19{
20    protected $tagNumber = self::TAG_TYPE_BIT_STRING;
21
22    /**
23     * @param string $value
24     */
25    public function __construct(string $value = '')
26    {
27        parent::__construct($value);
28    }
29
30    /**
31     * @return string
32     */
33    public function getValue()
34    {
35        return $this->value;
36    }
37
38    /**
39     * @param string $value
40     * @return BitStringType
41     */
42    public function setValue(string $value)
43    {
44        $this->value = $value;
45
46        return $this;
47    }
48
49    /**
50     * Get the integer representation of the bit string.
51     *
52     * @return int
53     */
54    public function toInteger() : int
55    {
56        return hexdec(bin2hex(rtrim($this->toBinary(), "\x00")));
57    }
58
59    /**
60     * Get the packed binary representation.
61     *
62     * @return string
63     */
64    public function toBinary()
65    {
66        $bytes = '';
67
68        foreach (str_split($this->value, 8) as $piece) {
69            $bytes .= chr(bindec($piece));
70        }
71
72        return $bytes;
73    }
74
75    /**
76     * Construct the bit string from a binary string value.
77     *
78     * @param string $bytes
79     * @param int|null $minLength
80     * @return BitStringType
81     */
82    public static function fromBinary($bytes, ?int $minLength = null)
83    {
84        $bitstring = '';
85
86        $length = strlen($bytes);
87        for ($i = 0; $i < $length; $i++) {
88            $bitstring .= sprintf('%08d', decbin(ord($bytes[$i])));
89        }
90        if ($minLength && strlen($bitstring) < $minLength) {
91            $bitstring = str_pad($bitstring, $minLength, '0');
92        }
93
94        return new self($bitstring);
95    }
96
97    /**
98     * Construct the bit string from an integer.
99     *
100     * @param int $int
101     * @param int|null $minLength
102     * @return BitStringType
103     */
104    public static function fromInteger(int $int, ?int $minLength = null)
105    {
106        $pieces = str_split(decbin($int), 8);
107        $num = count($pieces);
108
109        if ($num === 1 && strlen($pieces[0]) !== 8) {
110            $pieces[0] = str_pad($pieces[0], 8, '0', STR_PAD_LEFT);
111        } elseif ($num > 0 && strlen($pieces[$num - 1]) !== 8) {
112            $pieces[$num - 1] = str_pad($pieces[$num - 1], 8, '0', STR_PAD_RIGHT);
113        }
114
115        $bitstring = implode('', $pieces);
116        if ($minLength && strlen($bitstring) < $minLength) {
117            $bitstring = str_pad($bitstring, $minLength, '0');
118        }
119
120        return new self($bitstring);
121    }
122
123    /**
124     * @param string|int $tagNumber
125     * @param int $class
126     * @param bool $isConstructed
127     * @param string $value
128     * @return AbstractType
129     */
130    public static function withTag($tagNumber, int $class, bool $isConstructed, string $value = '')
131    {
132        $type = new self($value);
133        $type->taggingClass = $class;
134        $type->tagNumber = $tagNumber;
135        $type->isConstructed = $isConstructed;
136
137        return $type;
138    }
139}
140