Completed
Branch master (6bd7ca)
by Eugene
01:33
created

BufferUnpacker::extendWith()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 7
cts 7
cp 1
rs 9.8333
c 0
b 0
f 0
cc 3
nc 2
nop 2
crap 3
1
<?php
2
3
/*
4
 * This file is part of the rybakit/msgpack.php package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace MessagePack;
13
14
use MessagePack\Exception\InsufficientDataException;
15
use MessagePack\Exception\IntegerOverflowException;
16
use MessagePack\Exception\InvalidOptionException;
17
use MessagePack\Exception\UnpackingFailedException;
18
use MessagePack\TypeTransformer\CanUnpackExt;
19
20
class BufferUnpacker
21
{
22
    private $buffer;
23
    private $offset = 0;
24
    private $isBigIntAsStr;
25
    private $isBigIntAsGmp;
26
27
    /**
28
     * @var CanUnpackExt[]
29
     */
30
    private $transformers = [];
31
32
    /**
33
     * @param string $buffer
34
     * @param UnpackOptions|int|null $options
35
     * @param CanUnpackExt[] $transformers
36
     *
37
     * @throws InvalidOptionException
38
     */
39 243
    public function __construct(string $buffer = '', $options = null, array $transformers = [])
40
    {
41 243
        if (null === $options) {
42 242
            $options = UnpackOptions::fromDefaults();
43 8
        } elseif (!$options instanceof PackOptions) {
44 8
            $options = UnpackOptions::fromBitmask($options);
0 ignored issues
show
Bug introduced by
It seems like $options can also be of type object<MessagePack\UnpackOptions>; however, MessagePack\UnpackOptions::fromBitmask() does only seem to accept integer, 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...
45
        }
46
47 243
        $this->isBigIntAsStr = $options->isBigIntAsStrMode();
48 243
        $this->isBigIntAsGmp = $options->isBigIntAsGmpMode();
49
50 243
        $this->buffer = $buffer;
51
52 243
        if ([] !== $transformers) {
53 1
            $this->transformers = [];
54 1
            foreach ($transformers as $transformer) {
55 1
                $this->transformers[$transformer->getType()] = $transformer;
56
            }
57
        }
58 243
    }
59
60 1
    public function extendWith(CanUnpackExt $transformer, CanUnpackExt ...$transformers) : self
61
    {
62 1
        $new = clone $this;
63 1
        $new->transformers[$transformer->getType()] = $transformer;
64
65 1
        if ([] !== $transformers) {
66 1
            foreach ($transformers as $extraTransformer) {
67 1
                $new->transformers[$extraTransformer->getType()] = $extraTransformer;
68
            }
69
        }
70
71 1
        return $new;
72
    }
73
74 10
    public function append(string $data) : self
75
    {
76 10
        $this->buffer .= $data;
77
78 10
        return $this;
79
    }
80
81 216
    public function reset(string $buffer = '') : self
82
    {
83 216
        $this->buffer = $buffer;
84 216
        $this->offset = 0;
85
86 216
        return $this;
87
    }
88
89 3 View Code Duplication
    public function seek(int $offset) : self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
90
    {
91 3
        if ($offset < 0) {
92 1
            $offset += \strlen($this->buffer);
93
        }
94
95 3
        if (!isset($this->buffer[$offset])) {
96 1
            throw new \OutOfBoundsException("Unable to seek to position $offset.");
97
        }
98
99 2
        $this->offset = $offset;
100
101 2
        return $this;
102
    }
103
104 2 View Code Duplication
    public function skip(int $offset) : self
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
    {
106 2
        $offset += $this->offset;
107
108 2
        if (!isset($this->buffer[$offset])) {
109 1
            throw new \OutOfBoundsException("Unable to seek to position $offset.");
110
        }
111
112 1
        $this->offset = $offset;
113
114 1
        return $this;
115
    }
116
117 2
    public function withBuffer(string $buffer) : self
118
    {
119 2
        $new = clone $this;
120 2
        $new->buffer = $buffer;
121 2
        $new->offset = 0;
122
123 2
        return $new;
124
    }
125
126 3
    public function tryUnpack() : array
127
    {
128 3
        $data = [];
129 3
        $offset = $this->offset;
130
131
        try {
132
            do {
133 3
                $data[] = $this->unpack();
134 3
                $offset = $this->offset;
135 3
            } while (isset($this->buffer[$this->offset]));
136 1
        } catch (InsufficientDataException $e) {
137 1
            $this->offset = $offset;
138
        }
139
140 3
        if ($this->offset) {
141 3
            $this->buffer = isset($this->buffer[$this->offset]) ? \substr($this->buffer, $this->offset) : '';
142 3
            $this->offset = 0;
143
        }
144
145 3
        return $data;
146
    }
147
148 148
    public function unpack()
149
    {
150 148
        if (!isset($this->buffer[$this->offset])) {
151 5
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
152
        }
153
154 145
        $c = \ord($this->buffer[$this->offset]);
155 145
        ++$this->offset;
156
157
        // fixint
158 145
        if ($c <= 0x7f) {
159 31
            return $c;
160
        }
161
        // fixstr
162 138 View Code Duplication
        if ($c >= 0xa0 && $c <= 0xbf) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
163 18
            return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : '';
164
        }
165
        // negfixint
166 131
        if ($c >= 0xe0) {
167 5
            return $c - 0x100;
168
        }
169
170 127
        switch ($c) {
171 127
            case 0xc0: return null;
172 125
            case 0xc2: return false;
173 120
            case 0xc3: return true;
174
175
            // fixmap
176 111
            case 0x80: return [];
177 110
            case 0x81: return [$this->unpack() => $this->unpack()];
178 107
            case 0x82: return [$this->unpack() => $this->unpack(), $this->unpack() => $this->unpack()];
179 104
            case 0x83: return [$this->unpack() => $this->unpack(), $this->unpack() => $this->unpack(), $this->unpack() => $this->unpack()];
180 104
            case 0x84: return $this->unpackMapData(4);
181 104
            case 0x85: return $this->unpackMapData(5);
182 104
            case 0x86: return $this->unpackMapData(6);
183 104
            case 0x87: return $this->unpackMapData(7);
184 104
            case 0x88: return $this->unpackMapData(8);
185 104
            case 0x89: return $this->unpackMapData(9);
186 104
            case 0x8a: return $this->unpackMapData(10);
187 104
            case 0x8b: return $this->unpackMapData(11);
188 104
            case 0x8c: return $this->unpackMapData(12);
189 104
            case 0x8d: return $this->unpackMapData(13);
190 104
            case 0x8e: return $this->unpackMapData(14);
191 104
            case 0x8f: return $this->unpackMapData(15);
192
193
            // fixarray
194 104
            case 0x90: return [];
195 103
            case 0x91: return [$this->unpack()];
196 103
            case 0x92: return [$this->unpack(), $this->unpack()];
197 100
            case 0x93: return [$this->unpack(), $this->unpack(), $this->unpack()];
198 99
            case 0x94: return $this->unpackArrayData(4);
199 99
            case 0x95: return $this->unpackArrayData(5);
200 99
            case 0x96: return $this->unpackArrayData(6);
201 99
            case 0x97: return $this->unpackArrayData(7);
202 99
            case 0x98: return $this->unpackArrayData(8);
203 99
            case 0x99: return $this->unpackArrayData(9);
204 99
            case 0x9a: return $this->unpackArrayData(10);
205 99
            case 0x9b: return $this->unpackArrayData(11);
206 99
            case 0x9c: return $this->unpackArrayData(12);
207 99
            case 0x9d: return $this->unpackArrayData(13);
208 99
            case 0x9e: return $this->unpackArrayData(14);
209 99
            case 0x9f: return $this->unpackArrayData(15);
210
211
            // bin
212 99
            case 0xc4: return $this->unpackStrData($this->unpackUint8());
213 94
            case 0xc5: return $this->unpackStrData($this->unpackUint16());
214 93
            case 0xc6: return $this->unpackStrData($this->unpackUint32());
215
216
            // float
217 92
            case 0xca: return $this->unpackFloat32();
218 89
            case 0xcb: return $this->unpackFloat64();
219
220
            // uint
221 85
            case 0xcc: return $this->unpackUint8();
222 81
            case 0xcd: return $this->unpackUint16();
223 74
            case 0xce: return $this->unpackUint32();
224 69
            case 0xcf: return $this->unpackUint64();
225
226
            // int
227 57
            case 0xd0: return $this->unpackInt8();
228 52
            case 0xd1: return $this->unpackInt16();
229 47
            case 0xd2: return $this->unpackInt32();
230 42
            case 0xd3: return $this->unpackInt64();
231
232
            // str
233 34
            case 0xd9: return $this->unpackStrData($this->unpackUint8());
234 30
            case 0xda: return $this->unpackStrData($this->unpackUint16());
235 28
            case 0xdb: return $this->unpackStrData($this->unpackUint32());
236
237
            // array
238 27
            case 0xdc: return $this->unpackArrayData($this->unpackUint16());
239 25
            case 0xdd: return $this->unpackArrayData($this->unpackUint32());
240
241
            // map
242 24
            case 0xde: return $this->unpackMapData($this->unpackUint16());
243 22
            case 0xdf: return $this->unpackMapData($this->unpackUint32());
244
245
            // ext
246 21
            case 0xd4: return $this->unpackExtData(1);
247 17
            case 0xd5: return $this->unpackExtData(2);
248 15
            case 0xd6: return $this->unpackExtData(4);
249 13
            case 0xd7: return $this->unpackExtData(8);
250 11
            case 0xd8: return $this->unpackExtData(16);
251 9
            case 0xc7: return $this->unpackExtData($this->unpackUint8());
252 5
            case 0xc8: return $this->unpackExtData($this->unpackUint16());
253 3
            case 0xc9: return $this->unpackExtData($this->unpackUint32());
254
        }
255
256 1
        throw UnpackingFailedException::unknownCode($c);
257
    }
258
259 3
    public function unpackNil()
260
    {
261 3
        if (!isset($this->buffer[$this->offset])) {
262 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
263
        }
264
265 2
        if ("\xc0" === $this->buffer[$this->offset]) {
266 1
            ++$this->offset;
267
268 1
            return null;
269
        }
270
271 1
        throw UnpackingFailedException::unexpectedCode(\ord($this->buffer[$this->offset++]), 'nil');
272
    }
273
274 5
    public function unpackBool()
275
    {
276 5
        if (!isset($this->buffer[$this->offset])) {
277 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
278
        }
279
280 4
        $c = \ord($this->buffer[$this->offset]);
281 4
        ++$this->offset;
282
283 4
        if (0xc2 === $c) {
284 2
            return false;
285
        }
286 2
        if (0xc3 === $c) {
287 1
            return true;
288
        }
289
290 1
        throw UnpackingFailedException::unexpectedCode($c, 'bool');
291
    }
292
293 40
    public function unpackInt()
294
    {
295 40
        if (!isset($this->buffer[$this->offset])) {
296 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
297
        }
298
299 39
        $c = \ord($this->buffer[$this->offset]);
300 39
        ++$this->offset;
301
302
        // fixint
303 39
        if ($c <= 0x7f) {
304 3
            return $c;
305
        }
306
        // negfixint
307 36
        if ($c >= 0xe0) {
308 3
            return $c - 0x100;
309
        }
310
311 33
        switch ($c) {
312
            // uint
313 33
            case 0xcc: return $this->unpackUint8();
314 30
            case 0xcd: return $this->unpackUint16();
315 27
            case 0xce: return $this->unpackUint32();
316 24
            case 0xcf: return $this->unpackUint64();
317
318
            // int
319 20
            case 0xd0: return $this->unpackInt8();
320 16
            case 0xd1: return $this->unpackInt16();
321 12
            case 0xd2: return $this->unpackInt32();
322 8
            case 0xd3: return $this->unpackInt64();
323
        }
324
325 1
        throw UnpackingFailedException::unexpectedCode($c, 'int');
326
    }
327
328 7
    public function unpackFloat()
329
    {
330 7
        if (!isset($this->buffer[$this->offset])) {
331 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
332
        }
333
334 6
        $c = \ord($this->buffer[$this->offset]);
335 6
        ++$this->offset;
336
337 6
        if (0xcb === $c) {
338 3
            return $this->unpackFloat64();
339
        }
340 3
        if (0xca === $c) {
341 2
            return $this->unpackFloat32();
342
        }
343
344 1
        throw UnpackingFailedException::unexpectedCode($c, 'float');
345
    }
346
347 14
    public function unpackStr()
348
    {
349 14
        if (!isset($this->buffer[$this->offset])) {
350 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
351
        }
352
353 13
        $c = \ord($this->buffer[$this->offset]);
354 13
        ++$this->offset;
355
356 13 View Code Duplication
        if ($c >= 0xa0 && $c <= 0xbf) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
357 5
            return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : '';
358
        }
359 8
        if (0xd9 === $c) {
360 4
            return $this->unpackStrData($this->unpackUint8());
361
        }
362 4
        if (0xda === $c) {
363 2
            return $this->unpackStrData($this->unpackUint16());
364
        }
365 2
        if (0xdb === $c) {
366 1
            return $this->unpackStrData($this->unpackUint32());
367
        }
368
369 1
        throw UnpackingFailedException::unexpectedCode($c, 'str');
370
    }
371
372 7
    public function unpackBin()
373
    {
374 7
        if (!isset($this->buffer[$this->offset])) {
375 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
376
        }
377
378 6
        $c = \ord($this->buffer[$this->offset]);
379 6
        ++$this->offset;
380
381 6
        if (0xc4 === $c) {
382 3
            return $this->unpackStrData($this->unpackUint8());
383
        }
384 3
        if (0xc5 === $c) {
385 1
            return $this->unpackStrData($this->unpackUint16());
386
        }
387 2
        if (0xc6 === $c) {
388 1
            return $this->unpackStrData($this->unpackUint32());
389
        }
390
391 1
        throw UnpackingFailedException::unexpectedCode($c, 'bin');
392
    }
393
394 9
    public function unpackArray()
395
    {
396 9
        $size = $this->unpackArrayHeader();
397
398 7
        $array = [];
399 7
        while ($size--) {
400 6
            $array[] = $this->unpack();
401
        }
402
403 7
        return $array;
404
    }
405
406 9 View Code Duplication
    public function unpackArrayHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
407
    {
408 9
        if (!isset($this->buffer[$this->offset])) {
409 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
410
        }
411
412 8
        $c = \ord($this->buffer[$this->offset]);
413 8
        ++$this->offset;
414
415 8
        if ($c >= 0x90 && $c <= 0x9f) {
416 4
            return $c & 0xf;
417
        }
418 4
        if (0xdc === $c) {
419 2
            return $this->unpackUint16();
420
        }
421 2
        if (0xdd === $c) {
422 1
            return $this->unpackUint32();
423
        }
424
425 1
        throw UnpackingFailedException::unexpectedCode($c, 'array header');
426
    }
427
428 13
    public function unpackMap()
429
    {
430 13
        $size = $this->unpackMapHeader();
431
432 11
        $map = [];
433 11
        while ($size--) {
434 10
            $map[$this->unpack()] = $this->unpack();
435
        }
436
437 11
        return $map;
438
    }
439
440 13 View Code Duplication
    public function unpackMapHeader()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
441
    {
442 13
        if (!isset($this->buffer[$this->offset])) {
443 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
444
        }
445
446 12
        $c = \ord($this->buffer[$this->offset]);
447 12
        ++$this->offset;
448
449 12
        if ($c >= 0x80 && $c <= 0x8f) {
450 8
            return $c & 0xf;
451
        }
452 4
        if (0xde === $c) {
453 2
            return $this->unpackUint16();
454
        }
455 2
        if (0xdf === $c) {
456 1
            return $this->unpackUint32();
457
        }
458
459 1
        throw UnpackingFailedException::unexpectedCode($c, 'map header');
460
    }
461
462 10
    public function unpackExt()
463
    {
464 10
        if (!isset($this->buffer[$this->offset])) {
465 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
466
        }
467
468 9
        $c = \ord($this->buffer[$this->offset]);
469 9
        ++$this->offset;
470
471 9
        switch ($c) {
472 9
            case 0xd4: return $this->unpackExtData(1);
473 8
            case 0xd5: return $this->unpackExtData(2);
474 7
            case 0xd6: return $this->unpackExtData(4);
475 6
            case 0xd7: return $this->unpackExtData(8);
476 5
            case 0xd8: return $this->unpackExtData(16);
477 4
            case 0xc7: return $this->unpackExtData($this->unpackUint8());
478 3
            case 0xc8: return $this->unpackExtData($this->unpackUint16());
479 2
            case 0xc9: return $this->unpackExtData($this->unpackUint32());
480
        }
481
482 1
        throw UnpackingFailedException::unexpectedCode($c, 'ext header');
483
    }
484
485 34
    private function unpackUint8()
486
    {
487 34
        if (!isset($this->buffer[$this->offset])) {
488 2
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
489
        }
490
491 32
        return \ord($this->buffer[$this->offset++]);
492
    }
493
494 28
    private function unpackUint16()
495
    {
496 28
        if (!isset($this->buffer[$this->offset + 1])) {
497 2
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 2);
498
        }
499
500 26
        $hi = \ord($this->buffer[$this->offset]);
501 26
        $lo = \ord($this->buffer[++$this->offset]);
502 26
        ++$this->offset;
503
504 26
        return $hi << 8 | $lo;
505
    }
506
507 20
    private function unpackUint32()
508
    {
509 20
        if (!isset($this->buffer[$this->offset + 3])) {
510 2
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
511
        }
512
513 18
        $num = \unpack('N', $this->buffer, $this->offset)[1];
514 18
        $this->offset += 4;
515
516 18
        return $num;
517
    }
518
519 16 View Code Duplication
    private function unpackUint64()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
520
    {
521 16
        if (!isset($this->buffer[$this->offset + 7])) {
522 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
523
        }
524
525 15
        $num = \unpack('J', $this->buffer, $this->offset)[1];
526 15
        $this->offset += 8;
527
528 15
        return $num < 0 ? $this->handleIntOverflow($num) : $num;
529
    }
530
531 9
    private function unpackInt8()
532
    {
533 9
        if (!isset($this->buffer[$this->offset])) {
534 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
535
        }
536
537 8
        $num = \ord($this->buffer[$this->offset]);
538 8
        ++$this->offset;
539
540 8
        return $num > 0x7f ? $num - 0x100 : $num;
541
    }
542
543 9
    private function unpackInt16()
544
    {
545 9
        if (!isset($this->buffer[$this->offset + 1])) {
546 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 2);
547
        }
548
549 8
        $hi = \ord($this->buffer[$this->offset]);
550 8
        $lo = \ord($this->buffer[++$this->offset]);
551 8
        ++$this->offset;
552
553 8
        return $hi > 0x7f ? $hi << 8 | $lo - 0x10000 : $hi << 8 | $lo;
554
    }
555
556 9 View Code Duplication
    private function unpackInt32()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
557
    {
558 9
        if (!isset($this->buffer[$this->offset + 3])) {
559 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
560
        }
561
562 8
        $num = \unpack('N', $this->buffer, $this->offset)[1];
563 8
        $this->offset += 4;
564
565 8
        return $num > 0x7fffffff ? $num - 0x100000000 : $num;
566
    }
567
568 15
    private function unpackInt64()
569
    {
570 15
        if (!isset($this->buffer[$this->offset + 7])) {
571 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
572
        }
573
574 14
        $num = \unpack('J', $this->buffer, $this->offset)[1];
575 14
        $this->offset += 8;
576
577 14
        return $num;
578
    }
579
580 5
    private function unpackFloat32()
581
    {
582 5
        if (!isset($this->buffer[$this->offset + 3])) {
583 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
584
        }
585
586 4
        $num = \unpack('G', $this->buffer, $this->offset)[1];
587 4
        $this->offset += 4;
588
589 4
        return $num;
590
    }
591
592 7
    private function unpackFloat64()
593
    {
594 7
        if (!isset($this->buffer[$this->offset + 7])) {
595 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
596
        }
597
598 6
        $num = \unpack('E', $this->buffer, $this->offset)[1];
599 6
        $this->offset += 8;
600
601 6
        return $num;
602
    }
603
604 47
    private function unpackStrData($length)
605
    {
606 47
        if (!isset($this->buffer[$this->offset + $length - 1])) {
607 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, $length);
608
        }
609
610 47
        $str = \substr($this->buffer, $this->offset, $length);
611 47
        $this->offset += $length;
612
613 47
        return $str;
614
    }
615
616 4
    private function unpackArrayData($size)
617
    {
618 4
        $array = [];
619 4
        while ($size--) {
620 4
            $array[] = $this->unpack();
621
        }
622
623 4
        return $array;
624
    }
625
626 5
    private function unpackMapData($size)
627
    {
628 5
        $map = [];
629 5
        while ($size--) {
630 5
            $map[$this->unpack()] = $this->unpack();
631
        }
632
633 5
        return $map;
634
    }
635
636 25
    private function unpackExtData($length)
637
    {
638 25
        if (!isset($this->buffer[$this->offset + $length - 1])) {
639 5
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, $length);
640
        }
641
642
        // int8
643 20
        $type = \ord($this->buffer[$this->offset]);
644 20
        ++$this->offset;
645
646 20
        if ($type > 0x7f) {
647
            $type -= 0x100;
648
        }
649
650 20
        if (isset($this->transformers[$type])) {
651 2
            return $this->transformers[$type]->unpackExt($this, $length);
652
        }
653
654 18
        $data = \substr($this->buffer, $this->offset, $length);
655 18
        $this->offset += $length;
656
657 18
        return new Ext($type, $data);
658
    }
659
660 5
    private function handleIntOverflow($value)
661
    {
662 5
        if ($this->isBigIntAsStr) {
663 3
            return \sprintf('%u', $value);
664
        }
665 2
        if ($this->isBigIntAsGmp) {
666 1
            return \gmp_init(\sprintf('%u', $value));
667
        }
668
669 1
        throw new IntegerOverflowException($value);
670
    }
671
}
672