Completed
Push — master ( 3615fd...6bd7ca )
by Eugene
06:46
created

BufferUnpacker::extendWith()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 6
cts 6
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 242
     * @throws InvalidOptionException
38
     */
39 242
    public function __construct(string $buffer = '', $options = null, array $transformers = [])
40 241
    {
41 8
        if (null === $options) {
42 8
            $options = UnpackOptions::fromDefaults();
43
        } elseif (!$options instanceof PackOptions) {
44
            $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 242
        }
46 242
47
        $this->isBigIntAsStr = $options->isBigIntAsStrMode();
48 242
        $this->isBigIntAsGmp = $options->isBigIntAsGmpMode();
49 242
50
        $this->buffer = $buffer;
51 1
52
        if ([] !== $transformers) {
53 1
            $this->transformers = [];
54
            foreach ($transformers as $transformer) {
55 1
                $this->transformers[$transformer->getType()] = $transformer;
56
            }
57
        }
58 10
    }
59
60 10
    public function extendWith(CanUnpackExt $transformer, CanUnpackExt ...$transformers) : self
61
    {
62 10
        $new = clone $this;
63
        $new->transformers[$transformer->getType()] = $transformer;
64
65 215
        if ([] !== $transformers) {
66
            foreach ($transformers as $extraTransformer) {
67 215
                $new->transformers[$extraTransformer->getType()] = $extraTransformer;
68 215
            }
69
        }
70 215
71
        return $new;
72
    }
73 3
74
    public function append(string $data) : self
75 3
    {
76 1
        $this->buffer .= $data;
77
78
        return $this;
79 3
    }
80 1
81
    public function reset(string $buffer = '') : self
82
    {
83 2
        $this->buffer = $buffer;
84
        $this->offset = 0;
85 2
86
        return $this;
87
    }
88 2
89 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 2
    {
91
        if ($offset < 0) {
92 2
            $offset += \strlen($this->buffer);
93 1
        }
94
95
        if (!isset($this->buffer[$offset])) {
96 1
            throw new \OutOfBoundsException("Unable to seek to position $offset.");
97
        }
98 1
99
        $this->offset = $offset;
100
101 2
        return $this;
102
    }
103 2
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 2
    {
106
        $offset += $this->offset;
107 2
108
        if (!isset($this->buffer[$offset])) {
109
            throw new \OutOfBoundsException("Unable to seek to position $offset.");
110 3
        }
111
112 3
        $this->offset = $offset;
113 3
114
        return $this;
115
    }
116
117 3
    public function withBuffer(string $buffer) : self
118 3
    {
119 3
        $new = clone $this;
120 1
        $new->buffer = $buffer;
121 1
        $new->offset = 0;
122
123
        return $new;
124 3
    }
125 3
126 3
    public function tryUnpack() : array
127
    {
128
        $data = [];
129 3
        $offset = $this->offset;
130
131
        try {
132 147
            do {
133
                $data[] = $this->unpack();
134 147
                $offset = $this->offset;
135 5
            } while (isset($this->buffer[$this->offset]));
136
        } catch (InsufficientDataException $e) {
137
            $this->offset = $offset;
138 144
        }
139 144
140
        if ($this->offset) {
141
            $this->buffer = isset($this->buffer[$this->offset]) ? \substr($this->buffer, $this->offset) : '';
142 144
            $this->offset = 0;
143 31
        }
144
145
        return $data;
146 137
    }
147 18
148
    public function unpack()
149
    {
150 130
        if (!isset($this->buffer[$this->offset])) {
151 5
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
152
        }
153
154 126
        $c = \ord($this->buffer[$this->offset]);
155 126
        ++$this->offset;
156 124
157 119
        // fixint
158
        if ($c <= 0x7f) {
159
            return $c;
160 110
        }
161 109
        // fixstr
162 106 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 103
            return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : '';
164 103
        }
165 103
        // negfixint
166 103
        if ($c >= 0xe0) {
167 103
            return $c - 0x100;
168 103
        }
169 103
170 103
        switch ($c) {
171 103
            case 0xc0: return null;
172 103
            case 0xc2: return false;
173 103
            case 0xc3: return true;
174 103
175 103
            // fixmap
176
            case 0x80: return [];
177
            case 0x81: return [$this->unpack() => $this->unpack()];
178 103
            case 0x82: return [$this->unpack() => $this->unpack(), $this->unpack() => $this->unpack()];
179 102
            case 0x83: return [$this->unpack() => $this->unpack(), $this->unpack() => $this->unpack(), $this->unpack() => $this->unpack()];
180 102
            case 0x84: return $this->unpackMapData(4);
181 99
            case 0x85: return $this->unpackMapData(5);
182 98
            case 0x86: return $this->unpackMapData(6);
183 98
            case 0x87: return $this->unpackMapData(7);
184 98
            case 0x88: return $this->unpackMapData(8);
185 98
            case 0x89: return $this->unpackMapData(9);
186 98
            case 0x8a: return $this->unpackMapData(10);
187 98
            case 0x8b: return $this->unpackMapData(11);
188 98
            case 0x8c: return $this->unpackMapData(12);
189 98
            case 0x8d: return $this->unpackMapData(13);
190 98
            case 0x8e: return $this->unpackMapData(14);
191 98
            case 0x8f: return $this->unpackMapData(15);
192 98
193 98
            // fixarray
194
            case 0x90: return [];
195
            case 0x91: return [$this->unpack()];
196 98
            case 0x92: return [$this->unpack(), $this->unpack()];
197 93
            case 0x93: return [$this->unpack(), $this->unpack(), $this->unpack()];
198 92
            case 0x94: return $this->unpackArrayData(4);
199
            case 0x95: return $this->unpackArrayData(5);
200
            case 0x96: return $this->unpackArrayData(6);
201 91
            case 0x97: return $this->unpackArrayData(7);
202 88
            case 0x98: return $this->unpackArrayData(8);
203
            case 0x99: return $this->unpackArrayData(9);
204
            case 0x9a: return $this->unpackArrayData(10);
205 84
            case 0x9b: return $this->unpackArrayData(11);
206 80
            case 0x9c: return $this->unpackArrayData(12);
207 73
            case 0x9d: return $this->unpackArrayData(13);
208 68
            case 0x9e: return $this->unpackArrayData(14);
209
            case 0x9f: return $this->unpackArrayData(15);
210
211 56
            // bin
212 51
            case 0xc4: return $this->unpackStrData($this->unpackUint8());
213 46
            case 0xc5: return $this->unpackStrData($this->unpackUint16());
214 41
            case 0xc6: return $this->unpackStrData($this->unpackUint32());
215
216
            // float
217 33
            case 0xca: return $this->unpackFloat32();
218 29
            case 0xcb: return $this->unpackFloat64();
219 27
220
            // uint
221
            case 0xcc: return $this->unpackUint8();
222 26
            case 0xcd: return $this->unpackUint16();
223 24
            case 0xce: return $this->unpackUint32();
224
            case 0xcf: return $this->unpackUint64();
225
226 23
            // int
227 21
            case 0xd0: return $this->unpackInt8();
228
            case 0xd1: return $this->unpackInt16();
229
            case 0xd2: return $this->unpackInt32();
230 20
            case 0xd3: return $this->unpackInt64();
231 17
232 15
            // str
233 13
            case 0xd9: return $this->unpackStrData($this->unpackUint8());
234 11
            case 0xda: return $this->unpackStrData($this->unpackUint16());
235 9
            case 0xdb: return $this->unpackStrData($this->unpackUint32());
236 5
237 3
            // array
238
            case 0xdc: return $this->unpackArrayData($this->unpackUint16());
239
            case 0xdd: return $this->unpackArrayData($this->unpackUint32());
240 1
241
            // map
242
            case 0xde: return $this->unpackMapData($this->unpackUint16());
243 3
            case 0xdf: return $this->unpackMapData($this->unpackUint32());
244
245 3
            // ext
246 1
            case 0xd4: return $this->unpackExtData(1);
247
            case 0xd5: return $this->unpackExtData(2);
248
            case 0xd6: return $this->unpackExtData(4);
249 2
            case 0xd7: return $this->unpackExtData(8);
250 1
            case 0xd8: return $this->unpackExtData(16);
251
            case 0xc7: return $this->unpackExtData($this->unpackUint8());
252 1
            case 0xc8: return $this->unpackExtData($this->unpackUint16());
253
            case 0xc9: return $this->unpackExtData($this->unpackUint32());
254
        }
255 1
256
        throw UnpackingFailedException::unknownCode($c);
257
    }
258 5
259
    public function unpackNil()
260 5
    {
261 1
        if (!isset($this->buffer[$this->offset])) {
262
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
263
        }
264 4
265 4
        if ("\xc0" === $this->buffer[$this->offset]) {
266
            ++$this->offset;
267 4
268 2
            return null;
269
        }
270 2
271 1
        throw UnpackingFailedException::unexpectedCode(\ord($this->buffer[$this->offset++]), 'nil');
272
    }
273
274 1
    public function unpackBool()
275
    {
276
        if (!isset($this->buffer[$this->offset])) {
277 40
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
278
        }
279 40
280 1
        $c = \ord($this->buffer[$this->offset]);
281
        ++$this->offset;
282
283 39
        if (0xc2 === $c) {
284 39
            return false;
285
        }
286
        if (0xc3 === $c) {
287 39
            return true;
288 3
        }
289
290
        throw UnpackingFailedException::unexpectedCode($c, 'bool');
291 36
    }
292 3
293
    public function unpackInt()
294
    {
295 33
        if (!isset($this->buffer[$this->offset])) {
296
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
297 33
        }
298 30
299 27
        $c = \ord($this->buffer[$this->offset]);
300 24
        ++$this->offset;
301
302
        // fixint
303 20
        if ($c <= 0x7f) {
304 16
            return $c;
305 12
        }
306 8
        // negfixint
307
        if ($c >= 0xe0) {
308
            return $c - 0x100;
309 1
        }
310
311
        switch ($c) {
312 7
            // uint
313
            case 0xcc: return $this->unpackUint8();
314 7
            case 0xcd: return $this->unpackUint16();
315 1
            case 0xce: return $this->unpackUint32();
316
            case 0xcf: return $this->unpackUint64();
317
318 6
            // int
319 6
            case 0xd0: return $this->unpackInt8();
320
            case 0xd1: return $this->unpackInt16();
321 6
            case 0xd2: return $this->unpackInt32();
322 3
            case 0xd3: return $this->unpackInt64();
323
        }
324 3
325 2
        throw UnpackingFailedException::unexpectedCode($c, 'int');
326
    }
327
328 1
    public function unpackFloat()
329
    {
330
        if (!isset($this->buffer[$this->offset])) {
331 14
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
332
        }
333 14
334 1
        $c = \ord($this->buffer[$this->offset]);
335
        ++$this->offset;
336
337 13
        if (0xcb === $c) {
338 13
            return $this->unpackFloat64();
339
        }
340 13
        if (0xca === $c) {
341 5
            return $this->unpackFloat32();
342
        }
343 8
344 4
        throw UnpackingFailedException::unexpectedCode($c, 'float');
345
    }
346 4
347 2
    public function unpackStr()
348
    {
349 2
        if (!isset($this->buffer[$this->offset])) {
350 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
351
        }
352
353 1
        $c = \ord($this->buffer[$this->offset]);
354
        ++$this->offset;
355
356 7 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
            return ($c & 0x1f) ? $this->unpackStrData($c & 0x1f) : '';
358 7
        }
359 1
        if (0xd9 === $c) {
360
            return $this->unpackStrData($this->unpackUint8());
361
        }
362 6
        if (0xda === $c) {
363 6
            return $this->unpackStrData($this->unpackUint16());
364
        }
365 6
        if (0xdb === $c) {
366 3
            return $this->unpackStrData($this->unpackUint32());
367
        }
368 3
369 1
        throw UnpackingFailedException::unexpectedCode($c, 'str');
370
    }
371 2
372 1
    public function unpackBin()
373
    {
374
        if (!isset($this->buffer[$this->offset])) {
375 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
376
        }
377
378 9
        $c = \ord($this->buffer[$this->offset]);
379
        ++$this->offset;
380 9
381
        if (0xc4 === $c) {
382 7
            return $this->unpackStrData($this->unpackUint8());
383 7
        }
384 6
        if (0xc5 === $c) {
385
            return $this->unpackStrData($this->unpackUint16());
386
        }
387 7
        if (0xc6 === $c) {
388
            return $this->unpackStrData($this->unpackUint32());
389
        }
390 9
391
        throw UnpackingFailedException::unexpectedCode($c, 'bin');
392 9
    }
393 1
394
    public function unpackArray()
395
    {
396 8
        $size = $this->unpackArrayHeader();
397 8
398
        $array = [];
399 8
        while ($size--) {
400 4
            $array[] = $this->unpack();
401
        }
402 4
403 2
        return $array;
404
    }
405 2
406 1 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
        if (!isset($this->buffer[$this->offset])) {
409 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
410
        }
411
412 13
        $c = \ord($this->buffer[$this->offset]);
413
        ++$this->offset;
414 13
415
        if ($c >= 0x90 && $c <= 0x9f) {
416 11
            return $c & 0xf;
417 11
        }
418 10
        if (0xdc === $c) {
419
            return $this->unpackUint16();
420
        }
421 11
        if (0xdd === $c) {
422
            return $this->unpackUint32();
423
        }
424 13
425
        throw UnpackingFailedException::unexpectedCode($c, 'array header');
426 13
    }
427 1
428
    public function unpackMap()
429
    {
430 12
        $size = $this->unpackMapHeader();
431 12
432
        $map = [];
433 12
        while ($size--) {
434 8
            $map[$this->unpack()] = $this->unpack();
435
        }
436 4
437 2
        return $map;
438
    }
439 2
440 1 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
        if (!isset($this->buffer[$this->offset])) {
443 1
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
444
        }
445
446 10
        $c = \ord($this->buffer[$this->offset]);
447
        ++$this->offset;
448 10
449 1
        if ($c >= 0x80 && $c <= 0x8f) {
450
            return $c & 0xf;
451
        }
452 9
        if (0xde === $c) {
453 9
            return $this->unpackUint16();
454
        }
455 9
        if (0xdf === $c) {
456 9
            return $this->unpackUint32();
457 8
        }
458 7
459 6
        throw UnpackingFailedException::unexpectedCode($c, 'map header');
460 5
    }
461 4
462 3
    public function unpackExt()
463 2
    {
464
        if (!isset($this->buffer[$this->offset])) {
465
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
466 1
        }
467
468
        $c = \ord($this->buffer[$this->offset]);
469 34
        ++$this->offset;
470
471 34
        switch ($c) {
472 2
            case 0xd4: return $this->unpackExtData(1);
473
            case 0xd5: return $this->unpackExtData(2);
474
            case 0xd6: return $this->unpackExtData(4);
475 32
            case 0xd7: return $this->unpackExtData(8);
476
            case 0xd8: return $this->unpackExtData(16);
477
            case 0xc7: return $this->unpackExtData($this->unpackUint8());
478 28
            case 0xc8: return $this->unpackExtData($this->unpackUint16());
479
            case 0xc9: return $this->unpackExtData($this->unpackUint32());
480 28
        }
481 2
482
        throw UnpackingFailedException::unexpectedCode($c, 'ext header');
483
    }
484 26
485 26
    private function unpackUint8()
486 26
    {
487
        if (!isset($this->buffer[$this->offset])) {
488 26
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
489
        }
490
491 20
        return \ord($this->buffer[$this->offset++]);
492
    }
493 20
494 2
    private function unpackUint16()
495
    {
496
        if (!isset($this->buffer[$this->offset + 1])) {
497 18
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 2);
498 18
        }
499
500 18
        $hi = \ord($this->buffer[$this->offset]);
501
        $lo = \ord($this->buffer[++$this->offset]);
502
        ++$this->offset;
503 16
504
        return $hi << 8 | $lo;
505 16
    }
506 1
507
    private function unpackUint32()
508
    {
509 15
        if (!isset($this->buffer[$this->offset + 3])) {
510 15
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
511
        }
512 15
513
        $num = \unpack('N', $this->buffer, $this->offset)[1];
514
        $this->offset += 4;
515 9
516
        return $num;
517 9
    }
518 1
519 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 8
        if (!isset($this->buffer[$this->offset + 7])) {
522 8
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
523
        }
524 8
525
        $num = \unpack('J', $this->buffer, $this->offset)[1];
526
        $this->offset += 8;
527 9
528
        return $num < 0 ? $this->handleIntOverflow($num) : $num;
529 9
    }
530 1
531
    private function unpackInt8()
532
    {
533 8
        if (!isset($this->buffer[$this->offset])) {
534 8
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 1);
535 8
        }
536
537 8
        $num = \ord($this->buffer[$this->offset]);
538
        ++$this->offset;
539
540 9
        return $num > 0x7f ? $num - 0x100 : $num;
541
    }
542 9
543 1
    private function unpackInt16()
544
    {
545
        if (!isset($this->buffer[$this->offset + 1])) {
546 8
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 2);
547 8
        }
548
549 8
        $hi = \ord($this->buffer[$this->offset]);
550
        $lo = \ord($this->buffer[++$this->offset]);
551
        ++$this->offset;
552 15
553
        return $hi > 0x7f ? $hi << 8 | $lo - 0x10000 : $hi << 8 | $lo;
554 15
    }
555 1
556 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 14
        if (!isset($this->buffer[$this->offset + 3])) {
559 14
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
560
        }
561 14
562
        $num = \unpack('N', $this->buffer, $this->offset)[1];
563
        $this->offset += 4;
564 5
565
        return $num > 0x7fffffff ? $num - 0x100000000 : $num;
566 5
    }
567 1
568
    private function unpackInt64()
569
    {
570 4
        if (!isset($this->buffer[$this->offset + 7])) {
571 4
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
572
        }
573 4
574
        $num = \unpack('J', $this->buffer, $this->offset)[1];
575
        $this->offset += 8;
576 7
577
        return $num;
578 7
    }
579 1
580
    private function unpackFloat32()
581
    {
582 6
        if (!isset($this->buffer[$this->offset + 3])) {
583 6
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 4);
584
        }
585 6
586
        $num = \unpack('G', $this->buffer, $this->offset)[1];
587
        $this->offset += 4;
588 47
589
        return $num;
590 47
    }
591 1
592
    private function unpackFloat64()
593
    {
594 47
        if (!isset($this->buffer[$this->offset + 7])) {
595 47
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, 8);
596
        }
597 47
598
        $num = \unpack('E', $this->buffer, $this->offset)[1];
599
        $this->offset += 8;
600 4
601
        return $num;
602 4
    }
603 4
604 4
    private function unpackStrData($length)
605
    {
606
        if (!isset($this->buffer[$this->offset + $length - 1])) {
607 4
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, $length);
608
        }
609
610 5
        $str = \substr($this->buffer, $this->offset, $length);
611
        $this->offset += $length;
612 5
613 5
        return $str;
614 5
    }
615
616
    private function unpackArrayData($size)
617 5
    {
618
        $array = [];
619
        while ($size--) {
620 24
            $array[] = $this->unpack();
621
        }
622 24
623 5
        return $array;
624
    }
625
626
    private function unpackMapData($size)
627 19
    {
628 19
        $map = [];
629
        while ($size--) {
630 19
            $map[$this->unpack()] = $this->unpack();
631
        }
632
633
        return $map;
634 19
    }
635 1
636
    private function unpackExtData($length)
637
    {
638 18
        if (!isset($this->buffer[$this->offset + $length - 1])) {
639 18
            throw InsufficientDataException::unexpectedLength($this->buffer, $this->offset, $length);
640
        }
641 18
642
        // int8
643
        $type = \ord($this->buffer[$this->offset]);
644 5
        ++$this->offset;
645
646 5
        if ($type > 0x7f) {
647 3
            $type -= 0x100;
648
        }
649 2
650 1
        if (isset($this->transformers[$type])) {
651
            return $this->transformers[$type]->unpackExt($this, $length);
652
        }
653 1
654
        $data = \substr($this->buffer, $this->offset, $length);
655
        $this->offset += $length;
656
657
        return new Ext($type, $data);
658
    }
659
660
    private function handleIntOverflow($value)
661
    {
662
        if ($this->isBigIntAsStr) {
663
            return \sprintf('%u', $value);
664
        }
665
        if ($this->isBigIntAsGmp) {
666
            return \gmp_init(\sprintf('%u', $value));
667
        }
668
669
        throw new IntegerOverflowException($value);
670
    }
671
}
672