Completed
Push — master ( b984b7...c6c1eb )
by thomas
15s queued 10s
created

Buffer::gmp()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 4
cts 5
cp 0.8
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 2
crap 3.072
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Buffertools;
6
7
use Mdanter\Ecc\Math\GmpMathInterface;
8
9
class Buffer implements BufferInterface
10
{
11
    /**
12
     * @var int
13
     */
14
    protected $size;
15
16
    /**
17
     * @var string
18
     */
19
    protected $buffer;
20
21
    /**
22
     * @param string               $byteString
23
     * @param null|integer         $byteSize
24
     * @throws \Exception
25
     */
26 218
    public function __construct(string $byteString = '', int $byteSize = null)
27
    {
28 218
        if ($byteSize !== null) {
29
            // Check the integer doesn't overflow its supposed size
30 164
            if (strlen($byteString) > $byteSize) {
31 164
                throw new \Exception('Byte string exceeds maximum size');
32
            }
33
        } else {
34 208
            $byteSize = strlen($byteString);
35
        }
36
37 216
        $this->size   = $byteSize;
38 216
        $this->buffer = $byteString;
39 216
    }
40
41
    /**
42
     * Return a formatted version for var_dump
43
     */
44 2
    public function __debugInfo()
45
    {
46
        return [
47 2
            'size' => $this->size,
48 2
            'buffer' => '0x' . unpack("H*", $this->buffer)[1],
49
        ];
50
    }
51
52
    /**
53
     * Create a new buffer from a hex string
54
     *
55
     * @param string $hexString
56
     * @param int|null $byteSize
57
     * @return Buffer
58
     * @throws \Exception
59
     */
60 94
    public static function hex(string $hexString = '', int $byteSize = null): BufferInterface
61
    {
62 94
        if (strlen($hexString) > 0 && !ctype_xdigit($hexString)) {
63
            throw new \InvalidArgumentException('Buffer::hex: non-hex character passed');
64
        }
65
66 94
        $binary = pack("H*", $hexString);
67 94
        return new self($binary, $byteSize);
68
    }
69
70
    /**
71
     * @param int|string $integer
72
     * @param null|int $byteSize
73
     * @return Buffer
74
     */
75 6
    public static function int($integer, $byteSize = null): BufferInterface
76
    {
77 6
        $gmp = gmp_init($integer, 10);
78
        return self::gmp($gmp, $byteSize);
79
    }
80
81 6
    /**
82 6
     * @param \GMP $gmp
83 4
     * @return Buffer
84
     * @throws \Exception
85
     */
86 6
    public static function gmp(\GMP $gmp, $byteSize = null): BufferInterface
87 6
    {
88
        if (gmp_sign($gmp) < 0) {
89
            throw new \InvalidArgumentException('Negative integers not supported. This could be an application error, or you should be using templates.');
90
        }
91
92
        $hex = gmp_strval($gmp, 16);
93
        if ((mb_strlen($hex) % 2) !== 0) {
94
            $hex = "0{$hex}";
95
        }
96 2
97
        $binary = pack("H*", $hex);
98 2
        return new self($binary, $byteSize);
99
    }
100
101
    /**
102 2
     * @param int      $start
103
     * @param integer|null $end
104
     * @return BufferInterface
105
     * @throws \Exception
106 2
     */
107
    public function slice(int $start, int $end = null): BufferInterface
108
    {
109
        if ($start > $this->getSize()) {
110 2
            throw new \Exception('Start exceeds buffer length');
111 2
        }
112
113
        if ($end === null) {
114
            return new self(substr($this->getBinary(), $start));
115 2
        }
116 2
117
        if ($end > $this->getSize()) {
118
            throw new \Exception('Length exceeds buffer length');
119
        }
120
121
        $string = substr($this->getBinary(), $start, $end);
122
        if (!is_string($string)) {
123
            throw new \RuntimeException('Failed to slice string of with requested start/end');
124 28
        }
125
126 28
        $length = strlen($string);
127
        return new self($string, $length);
128
    }
129
130
    /**
131
     * Get the size of the buffer to be returned
132
     *
133
     * @return int
134 2
     */
135
    public function getSize(): int
136 2
    {
137
        return $this->size;
138
    }
139
140
    /**
141
     * Get the size of the value stored in the buffer
142 208
     *
143
     * @return int
144
     */
145 208
    public function getInternalSize(): int
146 208
    {
147 10
        return strlen($this->buffer);
148 206
    }
149
150
    /**
151
     * @return string
152
     */
153 206
    public function getBinary(): string
154
    {
155
        // if a size is specified we'll make sure the value returned is that size
156
        if ($this->size !== null) {
157
            if (strlen($this->buffer) < $this->size) {
158
                return str_pad($this->buffer, $this->size, chr(0), STR_PAD_LEFT);
159 152
            } elseif (strlen($this->buffer) > $this->size) {
160
                return substr($this->buffer, 0, $this->size);
161 152
            }
162
        }
163
164
        return $this->buffer;
165
    }
166
167 2
    /**
168
     * @return string
169 2
     */
170 2
    public function getHex(): string
171
    {
172
        return unpack("H*", $this->getBinary())[1];
173
    }
174
175
    /**
176 2
     * @return \GMP
177
     */
178 2
    public function getGmp(): \GMP
179
    {
180
        $gmp = gmp_init($this->getHex(), 16);
181
        return $gmp;
182
    }
183
184 6
    /**
185
     * @return int|string
186
     */
187 6
    public function getInt()
188 6
    {
189
        return gmp_strval($this->getGmp(), 10);
190
    }
191
192
    /**
193
     * @return Buffer
194
     */
195 2
    public function flip(): BufferInterface
196
    {
197 2
        /** @var Buffer $buffer */
198 2
        $buffer = Buffertools::flipBytes($this);
199
        return $buffer;
200
    }
201
202
    /**
203
     * @param BufferInterface $other
204
     * @return bool
205
     */
206
    public function equals(BufferInterface $other): bool
207
    {
208
        return ($other->getSize() === $this->getSize()
209
             && $other->getBinary() === $this->getBinary());
210
    }
211
}
212