Completed
Pull Request — master (#72)
by
unknown
04:10 queued 02:44
created

Buffer::__debugInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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