Completed
Pull Request — master (#71)
by thomas
23:08 queued 21:53
created

Parser::appendBinary()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
crap 2
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 BufferInterface $input
30
     */
31 164
    public function __construct(BufferInterface $input = null)
32
    {
33 164
        if ($input instanceof BufferInterface) {
34 152
            $this->string = $input->getBinary();
35 152
            $this->size = $input->getSize();
36
        }
37 164
    }
38
39
    /**
40
     * Get the position pointer of the parser - ie, how many bytes from 0
41
     *
42
     * @return int
43
     */
44 148
    public function getPosition(): int
45
    {
46 148
        return $this->position;
47
    }
48
49
    /**
50
     * Get the total size of the parser
51
     *
52
     * @return int
53
     */
54 16
    public function getSize()
55
    {
56 16
        return $this->size;
57
    }
58
59
    /**
60
     * Parse $bytes bytes from the string, and return the obtained buffer
61
     *
62
     * @param  int $numBytes
63
     * @param  bool $flipBytes
64
     * @return BufferInterface
65
     * @throws \Exception
66
     */
67 146
    public function readBytes(int $numBytes, bool $flipBytes = false): BufferInterface
68
    {
69 146
        $string = substr($this->string, $this->getPosition(), $numBytes);
70 146
        $length = strlen($string);
71
72 146
        if ($length === 0) {
73 4
            throw new ParserOutOfRange('Could not parse string of required length (empty)');
74 144
        } elseif ($length < $numBytes) {
75 2
            throw new ParserOutOfRange('Could not parse string of required length (too short)');
76
        }
77
78 142
        $this->position += $numBytes;
79
80 142
        if ($flipBytes) {
81 2
            $string = Buffertools::flipBytes($string);
82
            /** @var string $string */
83
        }
84
85 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 81 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...
86
    }
87
88
    /**
89
     * Write $data as $bytes bytes. Can be flipped if needed.
90
     *
91
     * @param  integer $numBytes - number of bytes to write
92
     * @param  SerializableInterface|BufferInterface|string $data - buffer, serializable or hex
93
     * @param  bool $flipBytes
94
     * @return Parser
95
     */
96 10
    public function writeBytes(int $numBytes, $data, bool $flipBytes = false): Parser
97
    {
98
        // Treat $data to ensure it's a buffer, with the correct size
99 10
        if ($data instanceof SerializableInterface) {
100
            $data = $data->getBuffer();
101
        }
102
103 10
        if (is_string($data)) {
104
            // Convert to a buffer
105
            $data = Buffer::hex($data, $numBytes);
106 10
        } else if (!($data instanceof BufferInterface)) {
107
            throw new \RuntimeException('Invalid data passed to Parser::writeBytes');
108
        }
109
110 10
        $this->writeBuffer($numBytes, $data, $flipBytes);
111
112 10
        return $this;
113
    }
114
115
    /**
116
     * Write $data as $bytes bytes. Can be flipped if needed.
117
     *
118
     * @param  integer $numBytes
119
     * @param  string $data
120
     * @param  bool $flipBytes
121
     * @return Parser
122
     */
123
    public function writeRawBinary(int $numBytes, string $data, bool $flipBytes = false): Parser
124
    {
125
        return $this->writeBuffer($numBytes, new Buffer($data, $numBytes), $flipBytes);
126
    }
127
128
    /**
129
     * @param BufferInterface $buffer
130
     * @param bool $flipBytes
131
     * @param int $numBytes
132
     * @return Parser
133
     */
134 10
    public function writeBuffer(int $numBytes, BufferInterface $buffer, bool $flipBytes = false): Parser
135
    {
136
        // only create a new buffer if the size does not match
137 10
        if ($buffer->getSize() != $numBytes) {
138 4
            $buffer = new Buffer($buffer->getBinary(), $numBytes);
139
        }
140
141 10
        $this->appendBuffer($buffer, $flipBytes);
142
143 10
        return $this;
144
    }
145
146
    /**
147
     * @param BufferInterface $buffer
148
     * @param bool $flipBytes
149
     * @return Parser
150
     */
151 10
    public function appendBuffer(BufferInterface $buffer, bool $flipBytes = false): Parser
152
    {
153 10
        $this->appendBinary($buffer->getBinary(), $flipBytes);
154 10
        return $this;
155
    }
156
157
    /**
158
     * @param string $binary
159
     * @param bool $flipBytes
160
     * @return Parser
161
     */
162 10
    public function appendBinary(string $binary, bool $flipBytes = false): Parser
163
    {
164 10
        if ($flipBytes) {
165 4
            $binary = Buffertools::flipBytes($binary);
166
        }
167
168 10
        $this->string .= $binary;
169 10
        $this->size += strlen($binary);
170 10
        return $this;
171
    }
172
173
    /**
174
     * Take an array containing serializable objects.
175
     * @param SerializableInterface[]|BufferInterface[] $serializable
176
     * @return Parser
177
     */
178 2
    public function writeArray(array $serializable): Parser
179
    {
180 2
        $parser = new Parser(Buffertools::numToVarInt(count($serializable)));
181 2
        foreach ($serializable as $object) {
182 2
            if ($object instanceof SerializableInterface) {
183
                $object = $object->getBuffer();
184
            }
185
186 2
            if ($object instanceof BufferInterface) {
187 2
                $parser->writeBytes($object->getSize(), $object);
188
            } else {
189 2
                throw new \RuntimeException('Input to writeArray must be Buffer[], or SerializableInterface[]');
190
            }
191
        }
192
193 2
        $this->string .= $parser->getBuffer()->getBinary();
194 2
        $this->size += $parser->getSize();
195
196 2
        return $this;
197
    }
198
199
    /**
200
     * Return the string as a buffer
201
     *
202
     * @return BufferInterface
203
     */
204 16
    public function getBuffer(): BufferInterface
205
    {
206 16
        return new Buffer($this->string, null);
207
    }
208
}
209