ByteBuffer::getBase64Url()   A
last analyzed

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
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace MadWizard\WebAuthn\Format;
4
5
use InvalidArgumentException;
6
use MadWizard\WebAuthn\Exception\ByteBufferException;
7
use Serializable;
8
use function bin2hex;
9
use function hex2bin;
10
use const INF;
11
use const PHP_INT_SIZE;
12
13
class ByteBuffer implements Serializable
14
{
15
    use SerializableTrait;
16
17
    /**
18
     * @var string
19
     */
20
    private $data;
21
22
    /**
23
     * @var int
24
     */
25
    private $length;
26
27 187
    public function __construct(string $binaryData)
28
    {
29 187
        $this->data = $binaryData;
30 187
        $this->length = \strlen($binaryData);
31 187
    }
32
33 75
    public static function fromHex(string $hex): ByteBuffer
34
    {
35 75
        $bin = @hex2bin($hex);
36 75
        if ($bin === false) {
37 2
            throw new InvalidArgumentException('Invalid hex string');
38
        }
39 73
        return new ByteBuffer($bin);
40
    }
41
42 42
    public static function fromBase64Url(string $base64url): ByteBuffer
43
    {
44 42
        return new ByteBuffer(Base64UrlEncoding::decode($base64url));
45
    }
46
47 8
    public function isEmpty(): bool
48
    {
49 8
        return $this->length === 0;
50
    }
51
52 108
    public function getLength(): int
53
    {
54 108
        return $this->length;
55
    }
56
57 3
    public static function randomBuffer(int $length): ByteBuffer
58
    {
59 3
        return new ByteBuffer(\random_bytes($length));
60
    }
61
62
    /**
63
     * @throws ByteBufferException
64
     */
65 72
    public function getBytes(int $offset, int $length): string
66
    {
67 72
        if ($offset < 0 || $length < 0 || ($offset + $length > $this->length)) {
68 2
            throw new ByteBufferException('Invalid offset or length');
69
        }
70 70
        return \substr($this->data, $offset, $length);
71
    }
72
73
    /**
74
     * @throws ByteBufferException
75
     */
76 73
    public function getByteVal(int $offset): int
77
    {
78 73
        if ($offset < 0 || $offset >= $this->length) {
79 4
            throw new ByteBufferException('Invalid offset');
80
        }
81 71
        return \ord($this->data[$offset]);
82
    }
83
84
    /**
85
     * @throws ByteBufferException
86
     */
87 40
    public function getUint16Val(int $offset): int
88
    {
89 40
        if ($offset < 0 || ($offset + 2) > $this->length) {
90 4
            throw new ByteBufferException('Invalid offset');
91
        }
92 36
        return unpack('n', $this->data, $offset)[1];
93
    }
94
95
    /**
96
     * @throws ByteBufferException
97
     */
98 36
    public function getUint32Val(int $offset): int
99
    {
100 36
        if ($offset < 0 || ($offset + 4) > $this->length) {
101 2
            throw new ByteBufferException('Invalid offset');
102
        }
103 34
        $val = unpack('N', $this->data, $offset)[1];
104
        // Signed integer overflow causes signed negative numbers
105 34
        if ($val < 0) {
106
            throw new ByteBufferException('Value out of integer range.');
107
        }
108 34
        return $val;
109
    }
110
111
    /**
112
     * @throws ByteBufferException
113
     */
114 5
    public function getUint64Val(int $offset): int
115
    {
116 5
        if (PHP_INT_SIZE < 8) {
117
            throw new ByteBufferException('64-bit values not supported by this system');
118
        }
119 5
        if ($offset < 0 || ($offset + 8) > $this->length) {
120 2
            throw new ByteBufferException('Invalid offset');
121
        }
122 3
        $val = unpack('J', $this->data, $offset)[1];
123
124
        // Signed integer overflow causes signed negative numbers
125 3
        if ($val < 0) {
126 2
            throw new ByteBufferException('Value out of integer range.');
127
        }
128
129 2
        return $val;
130
    }
131
132 4
    public function getHalfFloatVal(int $offset): float
133
    {
134
        //FROM spec pseudo decode_half(unsigned char *halfp)
135 4
        $half = $this->getUint16Val($offset);
136
137 2
        $exp = ($half >> 10) & 0x1f;
138 2
        $mant = $half & 0x3ff;
139
140 2
        if ($exp === 0) {
141 2
            $val = $mant * (2 ** -24);
142 2
        } elseif ($exp !== 31) {
143 2
            $val = ($mant + 1024) * (2 ** ($exp - 25));
144
        } else {
145 2
            $val = ($mant === 0) ? INF : NAN;
146
        }
147
148 2
        return ($half & 0x8000) ? -$val : $val;
149
    }
150
151
    /**
152
     * @throws ByteBufferException
153
     */
154 4
    public function getFloatVal(int $offset): float
155
    {
156 4
        if ($offset < 0 || ($offset + 4) > $this->length) {
157 2
            throw new ByteBufferException('Invalid offset');
158
        }
159 2
        return unpack('G', $this->data, $offset)[1];
160
    }
161
162
    /**
163
     * @throws ByteBufferException
164
     */
165 4
    public function getDoubleVal(int $offset): float
166
    {
167 4
        if ($offset < 0 || ($offset + 8) > $this->length) {
168 2
            throw new ByteBufferException('Invalid offset');
169
        }
170 2
        return unpack('E', $this->data, $offset)[1];
171
    }
172
173 71
    public function getBinaryString(): string
174
    {
175 71
        return $this->data;
176
    }
177
178 20
    public function equals(ByteBuffer $buffer): bool
179
    {
180 20
        return $this->data === $buffer->data; // TODO constant time
181
    }
182
183 32
    public function getHex(): string
184
    {
185 32
        return bin2hex($this->data);
186
    }
187
188 12
    public function getBase64Url(): string
189
    {
190 12
        return Base64UrlEncoding::encode($this->data);
191
    }
192
193 1
    public function __serialize(): array
194
    {
195 1
        return ['d' => $this->data];
196
    }
197
198 1
    public function __unserialize(array $data): void
199
    {
200 1
        $this->data = $data['d'];
201 1
        $this->length = strlen($this->data);
202 1
    }
203
}
204