GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — php70 ( e15417...9941dc )
by Joni
03:18
created

BitString::unusedBits()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types = 1);
3
4
namespace ASN1\Type\Primitive;
5
6
use ASN1\Component\Identifier;
7
use ASN1\Component\Length;
8
use ASN1\Exception\DecodeException;
9
use ASN1\Feature\ElementBase;
10
use ASN1\Type\PrimitiveType;
11
use ASN1\Type\StringType;
12
use ASN1\Type\UniversalClass;
13
14
/**
15
 * Implements <i>BIT STRING</i> type.
16
 */
17
class BitString extends StringType
18
{
19
    use UniversalClass;
20
    use PrimitiveType;
21
    
22
    /**
23
     * Number of unused bits in the last octet.
24
     *
25
     * @var int $_unusedBits
26
     */
27
    protected $_unusedBits;
28
    
29
    /**
30
     * Constructor.
31
     *
32
     * @param string $string Content octets
33
     * @param int $unused_bits Number of unused bits in the last octet
34
     */
35 50
    public function __construct(string $string, int $unused_bits = 0)
36
    {
37 50
        $this->_typeTag = self::TYPE_BIT_STRING;
38 50
        parent::__construct($string);
39 50
        $this->_unusedBits = $unused_bits;
40 50
    }
41
    
42
    /**
43
     * Get the number of bits in the string.
44
     *
45
     * @return int
46
     */
47 17
    public function numBits(): int
48
    {
49 17
        return strlen($this->_string) * 8 - $this->_unusedBits;
50
    }
51
    
52
    /**
53
     * Get the number of unused bits in the last octet of the string.
54
     *
55
     * @return int
56
     */
57 18
    public function unusedBits(): int
58
    {
59 18
        return $this->_unusedBits;
60
    }
61
    
62
    /**
63
     * Test whether bit is set.
64
     *
65
     * @param int $idx Bit index.
66
     *        Most significant bit of the first octet is index 0.
67
     * @return bool
68
     */
69 11
    public function testBit(int $idx): bool
70
    {
71
        // octet index
72 11
        $oi = (int) floor($idx / 8);
73
        // if octet is outside range
74 11
        if ($oi < 0 || $oi >= strlen($this->_string)) {
75 1
            throw new \OutOfBoundsException("Index is out of bounds.");
76
        }
77
        // bit index
78 10
        $bi = $idx % 8;
79
        // if tested bit is last octet's unused bit
80 10
        if ($oi == strlen($this->_string) - 1) {
81 7
            if ($bi >= 8 - $this->_unusedBits) {
82 1
                throw new \OutOfBoundsException(
83 1
                    "Index refers to an unused bit.");
84
            }
85
        }
86 9
        $byte = $this->_string[$oi];
87
        // index 0 is the most significant bit in byte
88 9
        $mask = 0x01 << (7 - $bi);
89 9
        return (ord($byte) & $mask) > 0;
90
    }
91
    
92
    /**
93
     * Get range of bits.
94
     *
95
     * @param int $start Index of first bit
96
     * @param int $length Number of bits in range
97
     * @throws \OutOfBoundsException
98
     * @return string Integer of $length bits
99
     */
100 9
    public function range(int $start, int $length): string
101
    {
102 9
        if (!$length) {
103 1
            return "0";
104
        }
105 8
        if ($start + $length > $this->numBits()) {
106 1
            throw new \OutOfBoundsException("Not enough bits.");
107
        }
108 7
        $bits = gmp_init(0);
109 7
        $idx = $start;
110 7
        $end = $start + $length;
111 7
        while (true) {
112 7
            $bit = $this->testBit($idx) ? 1 : 0;
113 7
            $bits |= $bit;
114 7
            if (++$idx >= $end) {
115 7
                break;
116
            }
117 7
            $bits <<= 1;
118
        }
119 7
        return gmp_strval($bits, 10);
120
    }
121
    
122
    /**
123
     * Get a copy of the bit string with trailing zeroes removed.
124
     *
125
     * @return self
126
     */
127 14
    public function withoutTrailingZeroes(): self
128
    {
129
        // if bit string was empty
130 14
        if (!strlen($this->_string)) {
131 1
            return new self("");
132
        }
133 13
        $bits = $this->_string;
134
        // count number of empty trailing octets
135 13
        $unused_octets = 0;
136 13
        for ($idx = strlen($bits) - 1; $idx >= 0; --$idx, ++$unused_octets) {
137 13
            if ($bits[$idx] != "\x0") {
138 11
                break;
139
            }
140
        }
141
        // strip trailing octets
142 13
        if ($unused_octets) {
143 7
            $bits = substr($bits, 0, -$unused_octets);
144
        }
145
        // if bit string was full of zeroes
146 13
        if (!strlen($bits)) {
147 2
            return new self("");
148
        }
149
        // count number of trailing zeroes in the last octet
150 11
        $unused_bits = 0;
151 11
        $byte = ord($bits[strlen($bits) - 1]);
152 11
        while (!($byte & 0x01)) {
153 9
            $unused_bits++;
154 9
            $byte >>= 1;
155
        }
156 11
        return new self($bits, $unused_bits);
157
    }
158
    
159
    /**
160
     *
161
     * {@inheritdoc}
162
     */
163 15
    protected function _encodedContentDER(): string
164
    {
165 15
        $der = chr($this->_unusedBits);
166 15
        $der .= $this->_string;
167 15
        if ($this->_unusedBits) {
168 9
            $octet = $der[strlen($der) - 1];
169
            // set unused bits to zero
170 9
            $octet &= chr(0xff & ~((1 << $this->_unusedBits) - 1));
171 9
            $der[strlen($der) - 1] = $octet;
172
        }
173 15
        return $der;
174
    }
175
    
176
    /**
177
     *
178
     * {@inheritdoc}
179
     * @return self
180
     */
181 11
    protected static function _decodeFromDER(Identifier $identifier,
182
        string $data, int &$offset): ElementBase
183
    {
184 11
        $idx = $offset;
185 11
        $length = Length::expectFromDER($data, $idx);
186 11
        if ($length->intLength() < 1) {
187 1
            throw new DecodeException("Bit string length must be at least 1.");
188
        }
189 10
        $unused_bits = ord($data[$idx++]);
190 10
        if ($unused_bits > 7) {
191 1
            throw new DecodeException(
192 1
                "Unused bits in a bit string must be less than 8.");
193
        }
194 9
        $str_len = $length->intLength() - 1;
195 9
        if ($str_len) {
196 8
            $str = substr($data, $idx, $str_len);
197 8
            if ($unused_bits) {
198 7
                $mask = (1 << $unused_bits) - 1;
199 7
                if (ord($str[strlen($str) - 1]) & $mask) {
200 1
                    throw new DecodeException(
201 8
                        "DER encoded bit string must have zero padding.");
202
                }
203
            }
204
        } else {
205 1
            $str = "";
206
        }
207 8
        $offset = $idx + $str_len;
208 8
        return new self($str, $unused_bits);
209
    }
210
}
211