Parser::writeBytes()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.5923

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 6
cts 9
cp 0.6667
rs 9.6666
c 0
b 0
f 0
cc 4
nc 6
nop 3
crap 4.5923
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Buffertools;
6
7
use BitWasp\Buffertools\Exceptions\ParserOutOfRange;
8
9
class Parser
10
{
11
    /**
12
     * @var string
13
     */
14
    private $string;
15
16
    /**
17
     * @var int
18
     */
19
    private $size = 0;
20
21
    /**
22
     * @var int
23
     */
24
    private $position = 0;
25
26
    /**
27
     * Instantiate class, optionally taking Buffer or HEX.
28
     *
29
     * @param null|string|BufferInterface $input
30
     */
31 164
    public function __construct($input = null)
32
    {
33 164
        if (null === $input) {
34 14
            $input = '';
35
        }
36
37 164
        if (is_string($input)) {
38 24
            $bin = Buffer::hex($input, null)->getBinary();
39 142
        } elseif ($input instanceof BufferInterface) {
40 142
            $bin = $input->getBinary();
41
        } else {
42
            throw new \InvalidArgumentException("Invalid argument to Parser");
43
        }
44
45 164
        $this->string = $bin;
46 164
        $this->position = 0;
47 164
        $this->size = strlen($this->string);
48 164
    }
49
50
    /**
51
     * Get the position pointer of the parser - ie, how many bytes from 0
52
     *
53
     * @return int
54
     */
55 148
    public function getPosition(): int
56
    {
57 148
        return $this->position;
58
    }
59
60
    /**
61
     * Get the total size of the parser
62
     *
63
     * @return int
64
     */
65 16
    public function getSize()
66
    {
67 16
        return $this->size;
68
    }
69
70
    /**
71
     * Parse $bytes bytes from the string, and return the obtained buffer
72
     *
73
     * @param  int $numBytes
74
     * @param  bool $flipBytes
75
     * @return BufferInterface
76
     * @throws \Exception
77
     */
78 146
    public function readBytes(int $numBytes, bool $flipBytes = false): BufferInterface
79
    {
80 146
        $string = substr($this->string, $this->getPosition(), $numBytes);
81 146
        $length = strlen($string);
82
83 146
        if ($length === 0) {
84 4
            throw new ParserOutOfRange('Could not parse string of required length (empty)');
85 144
        } elseif ($length < $numBytes) {
86 2
            throw new ParserOutOfRange('Could not parse string of required length (too short)');
87
        }
88
89 142
        $this->position += $numBytes;
90
91 142
        if ($flipBytes) {
92 2
            $string = Buffertools::flipBytes($string);
93
            /** @var string $string */
94
        }
95
96 142
        return new Buffer($string, $length);
0 ignored issues
show
Bug introduced by
It seems like $string defined by \BitWasp\Buffertools\Buf...ols::flipBytes($string) on line 92 can also be of type object<BitWasp\Buffertools\Buffer>; however, BitWasp\Buffertools\Buffer::__construct() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
97
    }
98
99
    /**
100
     * Write $data as $bytes bytes. Can be flipped if needed.
101
     *
102
     * @param  integer $numBytes - number of bytes to write
103
     * @param  SerializableInterface|BufferInterface|string $data - buffer, serializable or hex
104
     * @param  bool $flipBytes
105
     * @return Parser
106
     */
107 10
    public function writeBytes(int $numBytes, $data, bool $flipBytes = false): Parser
108
    {
109
        // Treat $data to ensure it's a buffer, with the correct size
110 10
        if ($data instanceof SerializableInterface) {
111
            $data = $data->getBuffer();
112
        }
113
114 10
        if (is_string($data)) {
115
            // Convert to a buffer
116
            $data = Buffer::hex($data, $numBytes);
117 10
        } else if (!($data instanceof BufferInterface)) {
118
            throw new \RuntimeException('Invalid data passed to Parser::writeBytes');
119
        }
120
121 10
        $this->writeBuffer($numBytes, $data, $flipBytes);
122
123 10
        return $this;
124
    }
125
126
    /**
127
     * Write $data as $bytes bytes. Can be flipped if needed.
128
     *
129
     * @param  integer $numBytes
130
     * @param  string $data
131
     * @param  bool $flipBytes
132
     * @return Parser
133
     */
134
    public function writeRawBinary(int $numBytes, string $data, bool $flipBytes = false): Parser
135
    {
136
        return $this->writeBuffer($numBytes, new Buffer($data, $numBytes), $flipBytes);
137
    }
138
139
    /**
140
     * @param BufferInterface $buffer
141
     * @param bool $flipBytes
142
     * @param int $numBytes
143
     * @return Parser
144
     */
145 10
    public function writeBuffer(int $numBytes, BufferInterface $buffer, bool $flipBytes = false): Parser
146
    {
147
        // only create a new buffer if the size does not match
148 10
        if ($buffer->getSize() != $numBytes) {
149 4
            $buffer = new Buffer($buffer->getBinary(), $numBytes);
150
        }
151
152 10
        $this->appendBuffer($buffer, $flipBytes);
153
154 10
        return $this;
155
    }
156
157
    /**
158
     * @param BufferInterface $buffer
159
     * @param bool $flipBytes
160
     * @return Parser
161
     */
162 10
    public function appendBuffer(BufferInterface $buffer, bool $flipBytes = false): Parser
163
    {
164 10
        $this->appendBinary($buffer->getBinary(), $flipBytes);
165 10
        return $this;
166
    }
167
168
    /**
169
     * @param string $binary
170
     * @param bool $flipBytes
171
     * @return Parser
172
     */
173 10
    public function appendBinary(string $binary, bool $flipBytes = false): Parser
174
    {
175 10
        if ($flipBytes) {
176 4
            $binary = Buffertools::flipBytes($binary);
177
        }
178
179 10
        $this->string .= $binary;
180 10
        $this->size += strlen($binary);
181 10
        return $this;
182
    }
183
184
    /**
185
     * Take an array containing serializable objects.
186
     * @param SerializableInterface[]|BufferInterface[] $serializable
187
     * @return Parser
188
     */
189 2
    public function writeArray(array $serializable): Parser
190
    {
191 2
        $parser = new Parser(Buffertools::numToVarInt(count($serializable)));
192 2
        foreach ($serializable as $object) {
193 2
            if ($object instanceof SerializableInterface) {
194
                $object = $object->getBuffer();
195
            }
196
197 2
            if ($object instanceof BufferInterface) {
198 2
                $parser->writeBytes($object->getSize(), $object);
199
            } else {
200 2
                throw new \RuntimeException('Input to writeArray must be Buffer[], or SerializableInterface[]');
201
            }
202
        }
203
204 2
        $this->string .= $parser->getBuffer()->getBinary();
205 2
        $this->size += $parser->getSize();
206
207 2
        return $this;
208
    }
209
210
    /**
211
     * Return the string as a buffer
212
     *
213
     * @return BufferInterface
214
     */
215 16
    public function getBuffer(): BufferInterface
216
    {
217 16
        return new Buffer($this->string, null);
218
    }
219
}
220