Completed
Pull Request — master (#35)
by Eugene
07:03
created

Container::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 2
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 Decimal\Decimal;
15
use MessagePack\Exception\InsufficientDataException;
16
use MessagePack\Exception\InvalidOptionException;
17
use MessagePack\Exception\UnpackingFailedException;
18
use MessagePack\TypeTransformer\Extension;
19
20
class BufferUnpacker
21
{
22
    private $buffer;
23
    private $offset = 0;
24
    private $isBigIntAsDec;
25
    private $isBigIntAsGmp;
26
27
    /**
28
     * @var Extension[]
29
     */
30
    private $extensions = [];
31
32
    /**
33
     * @param UnpackOptions|int|null $options
34
     * @param Extension[] $extensions
35
     *
36
     * @throws InvalidOptionException
37
     */
38 320
    public function __construct(string $buffer = '', $options = null, array $extensions = [])
39
    {
40 320
        if (\is_null($options)) {
41 319
            $options = UnpackOptions::fromDefaults();
42 8
        } elseif (!$options instanceof UnpackOptions) {
43 8
            $options = UnpackOptions::fromBitmask($options);
44
        }
45
46 320
        $this->isBigIntAsDec = $options->isBigIntAsDecMode();
47 320
        $this->isBigIntAsGmp = $options->isBigIntAsGmpMode();
48
49 320
        $this->buffer = $buffer;
50
51 320
        if ($extensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extensions of type MessagePack\TypeTransformer\Extension[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
52 1
            foreach ($extensions as $extension) {
53 1
                $this->extensions[$extension->getType()] = $extension;
54
            }
55
        }
56 320
    }
57
58 1
    public function extendWith(Extension $extension, Extension ...$extensions) : self
59
    {
60 1
        $new = clone $this;
61 1
        $new->extensions[$extension->getType()] = $extension;
62
63 1
        if ($extensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extensions of type MessagePack\TypeTransformer\Extension[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
64 1
            foreach ($extensions as $extraExtension) {
65 1
                $new->extensions[$extraExtension->getType()] = $extraExtension;
66
            }
67
        }
68
69 1
        return $new;
70
    }
71
72 2
    public function withBuffer(string $buffer) : self
73
    {
74 2
        $new = clone $this;
75 2
        $new->buffer = $buffer;
76 2
        $new->offset = 0;
77
78 2
        return $new;
79
    }
80
81 10
    public function append(string $data) : self
82
    {
83 10
        $this->buffer .= $data;
84
85 10
        return $this;
86
    }
87
88 293
    public function reset(string $buffer = '') : self
89
    {
90 293
        $this->buffer = $buffer;
91 293
        $this->offset = 0;
92
93 293
        return $this;
94
    }
95
96 3
    public function seek(int $offset) : self
97
    {
98 3
        if ($offset < 0) {
99 1
            $offset += \strlen($this->buffer);
100
        }
101
102 3
        if (!isset($this->buffer[$offset])) {
103 1
            throw new InsufficientDataException("Unable to seek to position $offset");
104
        }
105
106 2
        $this->offset = $offset;
107
108 2
        return $this;
109
    }
110
111 2 View Code Duplication
    public function skip(int $length) : 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...
112
    {
113 2
        $offset = $this->offset + $length;
114
115 2
        if (!isset($this->buffer[$offset])) {
116 1
            throw new InsufficientDataException("Unable to seek to position $offset");
117
        }
118
119 1
        $this->offset = $offset;
120
121 1
        return $this;
122
    }
123
124 2
    public function getRemainingCount() : int
125
    {
126 2
        return \strlen($this->buffer) - $this->offset;
127
    }
128
129 176
    public function hasRemaining() : bool
130
    {
131 176
        return isset($this->buffer[$this->offset]);
132
    }
133
134 1
    public function release() : int
135
    {
136 1
        if (0 === $this->offset) {
137 1
            return 0;
138
        }
139
140 1
        $releasedBytesCount = $this->offset;
141 1
        $this->buffer = isset($this->buffer[$this->offset]) ? \substr($this->buffer, $this->offset) : '';
142 1
        $this->offset = 0;
143
144 1
        return $releasedBytesCount;
145
    }
146
147
    /**
148
     * @param int $length
149
     *
150
     * @return string
151
     */
152 47 View Code Duplication
    public function read($length)
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...
153
    {
154 47
        if (!isset($this->buffer[$this->offset + $length - 1])) {
155 1
            throw new InsufficientDataException();
156
        }
157
158 47
        $data = \substr($this->buffer, $this->offset, $length);
159 47
        $this->offset += $length;
160
161 47
        return $data;
162
    }
163
164 3
    public function tryUnpack() : array
165
    {
166 3
        $data = [];
167 3
        $offset = $this->offset;
168
169
        try {
170
            do {
171 3
                $data[] = $this->unpack();
172 3
                $offset = $this->offset;
173 3
            } while (isset($this->buffer[$this->offset]));
174 1
        } catch (InsufficientDataException $e) {
175 1
            $this->offset = $offset;
176
        }
177
178 3
        return $data;
179
    }
180
181 189
    public function unpack()
182
    {
183 189
        $buffer = &$this->buffer;
184 4
        $offset = &$this->offset;
185
        $stack = [];
186
        $top = 0;
187 187
188 187
        begin:
189
        if (!isset($buffer[$offset])) {
190
            throw new InsufficientDataException();
191 187
        }
192 29
193
        $c = \ord($buffer[$offset]);
194
        ++$offset;
195 175
196 16
        // fixint
197
        if ($c <= 0x7f) {
198
            $value = $c;
199 169
            goto end;
200 5
        }
201
202
        // fixstr
203
        if ($c >= 0xa0 && $c <= 0xbf) {
204 165
            if ($c & 0x1f) {
205 163
                $length = $c & 0x1f;
206 159
                goto read;
207
            }
208 151
            $value = '';
209 150
            goto end;
210 117
        }
211 116
212 116
        // negfixint
213 116
        if ($c >= 0xe0) {
214 116
            $value = $c - 0x100;
215 116
            goto end;
216 116
        }
217 116
218 116
        switch ($c) {
219 116
            case 0xc0: $value = null; goto end;
220 116
            case 0xc2: $value = false; goto end;
221 116
            case 0xc3: $value = true; goto end;
222 116
223 116
            // fixmap
224
            case 0x80: $value = []; goto end;
225 116
            case 0x81: $stack[++$top] = new Container(2 /* map key */, 1); goto begin;
226 115
            case 0x82: $stack[++$top] = new Container(2 /* map key */, 2); goto begin;
227 115
            case 0x83: $stack[++$top] = new Container(2 /* map key */, 3); goto begin;
228 110
            case 0x84: $stack[++$top] = new Container(2 /* map key */, 4); goto begin;
229 109
            case 0x85: $stack[++$top] = new Container(2 /* map key */, 5); goto begin;
230 109
            case 0x86: $stack[++$top] = new Container(2 /* map key */, 6); goto begin;
231 109
            case 0x87: $stack[++$top] = new Container(2 /* map key */, 7); goto begin;
232 109
            case 0x88: $stack[++$top] = new Container(2 /* map key */, 8); goto begin;
233 109
            case 0x89: $stack[++$top] = new Container(2 /* map key */, 9); goto begin;
234 109
            case 0x8a: $stack[++$top] = new Container(2 /* map key */, 10); goto begin;
235 109
            case 0x8b: $stack[++$top] = new Container(2 /* map key */, 11); goto begin;
236 109
            case 0x8c: $stack[++$top] = new Container(2 /* map key */, 12); goto begin;
237 109
            case 0x8d: $stack[++$top] = new Container(2 /* map key */, 13); goto begin;
238 109
            case 0x8e: $stack[++$top] = new Container(2 /* map key */, 14); goto begin;
239 109
            case 0x8f: $stack[++$top] = new Container(2 /* map key */, 15); goto begin;
240 109
241
            // fixarray
242 109
            case 0x90: $value = []; goto end;
243 104
            case 0x91: $stack[++$top] = new Container(1 /* array item */, 1); goto begin;
244 103
            case 0x92: $stack[++$top] = new Container(1 /* array item */, 2); goto begin;
245
            case 0x93: $stack[++$top] = new Container(1 /* array item */, 3); goto begin;
246 102
            case 0x94: $stack[++$top] = new Container(1 /* array item */, 4); goto begin;
247 99
            case 0x95: $stack[++$top] = new Container(1 /* array item */, 5); goto begin;
248
            case 0x96: $stack[++$top] = new Container(1 /* array item */, 6); goto begin;
249 95
            case 0x97: $stack[++$top] = new Container(1 /* array item */, 7); goto begin;
250 91
            case 0x98: $stack[++$top] = new Container(1 /* array item */, 8); goto begin;
251 85
            case 0x99: $stack[++$top] = new Container(1 /* array item */, 9); goto begin;
252 81
            case 0x9a: $stack[++$top] = new Container(1 /* array item */, 10); goto begin;
253
            case 0x9b: $stack[++$top] = new Container(1 /* array item */, 11); goto begin;
254 71
            case 0x9c: $stack[++$top] = new Container(1 /* array item */, 12); goto begin;
255 66
            case 0x9d: $stack[++$top] = new Container(1 /* array item */, 13); goto begin;
256 61
            case 0x9e: $stack[++$top] = new Container(1 /* array item */, 14); goto begin;
257 56
            case 0x9f: $stack[++$top] = new Container(1 /* array item */, 15); goto begin;
258
259 48
            // bin
260 44
            case 0xc4: $length = self::unpackUint8($buffer, $offset); goto read;
261 42
            case 0xc5: $length = self::unpackUint16($buffer, $offset); goto read;
262
            case 0xc6: $length = self::unpackUint32($buffer, $offset); goto read;
263 41
264 39
            // float
265
            case 0xca: $value = self::unpackFloat32($buffer, $offset); goto end;
266 38
            case 0xcb: $value = self::unpackFloat64($buffer, $offset); goto end;
267 36
268
            // uint
269 35
            case 0xcc: $value = self::unpackUint8($buffer, $offset); goto end;
270 30
            case 0xcd: $value = self::unpackUint16($buffer, $offset); goto end;
271 27
            case 0xce: $value = self::unpackUint32($buffer, $offset); goto end;
272 24
            case 0xcf: $value = $this->unpackUint64(); goto end;
273 21
274 18
            // int
275 11
            case 0xd0: $value = self::unpackInt8($buffer, $offset); goto end;
276 6
            case 0xd1: $value = self::unpackInt16($buffer, $offset); goto end;
277
            case 0xd2: $value = self::unpackInt32($buffer, $offset); goto end;
278
            case 0xd3: $value = self::unpackInt64($buffer, $offset); goto end;
279 1
280
            // str
281
            case 0xd9: $length = self::unpackUint8($buffer, $offset); goto read;
282 3
            case 0xda: $length = self::unpackUint16($buffer, $offset); goto read;
283
            case 0xdb: $length = self::unpackUint32($buffer, $offset); goto read;
284 3
285 1
            // array
286
            case 0xdc: $stack[++$top] = new Container(1 /* array item */, self::unpackUint16($buffer, $offset)); goto begin;
287
            case 0xdd: $stack[++$top] = new Container(1 /* array item */, self::unpackUint32($buffer, $offset)); goto begin;
288 2
289 1
            // map
290
            case 0xde: $stack[++$top] = new Container(2 /* map key */, self::unpackUint16($buffer, $offset)); goto begin;
291 1
            case 0xdf: $stack[++$top] = new Container(2 /* map key */, self::unpackUint32($buffer, $offset)); goto begin;
292
293
            // ext
294 1
            case 0xd4: $value = $this->unpackExtData(1); goto end;
295
            case 0xd5: $value = $this->unpackExtData(2); goto end;
296
            case 0xd6: $value = $this->unpackExtData(4); goto end;
297 5
            case 0xd7: $value = $this->unpackExtData(8); goto end;
298
            case 0xd8: $value = $this->unpackExtData(16); goto end;
299 5
            case 0xc7: $value = $this->unpackExtData(self::unpackUint8($buffer, $offset)); goto end;
300 1
            case 0xc8: $value = $this->unpackExtData(self::unpackUint16($buffer, $offset)); goto end;
301
            case 0xc9: $value = $this->unpackExtData(self::unpackUint32($buffer, $offset)); goto end;
302
        }
303 4
304 4
        throw UnpackingFailedException::unknownCode($c);
305
306 4
        read:
307 2
        if (!isset($buffer[$offset + $length - 1])) {
308
            throw new InsufficientDataException();
309 2
        }
310 1
311
        $value = \substr($buffer, $offset, $length);
312
        $offset += $length;
313 1
314
        end:
315
        while ($stack) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stack of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
316 40
            /** @var Container $state */
317
            $state = $stack[$top];
318 40
            if ($state->type === 1 /* array item */) {
319 1
                $state->value[] = $value;
320
                ++$state->count;
321
            } else if ($state->type === 2 /* map key */) {
322 39
                $state->type = 3 /* map value */;
323 39
                $state->key = $value;
324
                goto begin;
325
            } else if ($state->type === 3 /* map value */) {
326 39
                $state->type = 2 /* map key */;
327 3
                $state->value[$state->key] = $value;
328
                ++$state->count;
329
            }
330 36
331 3
            if ($state->size !== $state->count) {
332
                goto begin;
333
            }
334
335
            unset($stack[$top]);
336 33
            --$top;
337 30
            $value = $state->value;
338 27
        }
339 24
340
        return $value;
341 20
    }
342 16
343 12
    public function unpackNil()
344 8
    {
345
        $buffer = &$this->buffer;
346
        $offset = &$this->offset;
347 1
348
        if (!isset($buffer[$offset])) {
349
            throw new InsufficientDataException();
350 7
        }
351
352 7
        if ("\xc0" === $buffer[$offset]) {
353 1
            ++$offset;
354
355
            return null;
356 6
        }
357 6
358
        throw UnpackingFailedException::unexpectedCode(\ord($buffer[$offset++]), 'nil');
359 6
    }
360 3
361
    public function unpackBool()
362 3
    {
363 2
        $buffer = &$this->buffer;
364
        $offset = &$this->offset;
365
366 1
        if (!isset($buffer[$offset])) {
367
            throw new InsufficientDataException();
368
        }
369 14
370
        $c = \ord($buffer[$offset]);
371 14
        ++$offset;
372 1
373
        if (0xc2 === $c) {
374
            return false;
375 13
        }
376 13
        if (0xc3 === $c) {
377
            return true;
378 13
        }
379 5
380
        throw UnpackingFailedException::unexpectedCode($c, 'bool');
381 8
    }
382 4
383
    public function unpackInt()
384 4
    {
385 2
        $buffer = &$this->buffer;
386
        $offset = &$this->offset;
387 2
388 1
        if (!isset($buffer[$offset])) {
389
            throw new InsufficientDataException();
390
        }
391 1
392
        $c = \ord($buffer[$offset]);
393
        ++$offset;
394 7
395
        // fixint
396 7
        if ($c <= 0x7f) {
397 1
            return $c;
398
        }
399
        // negfixint
400 6
        if ($c >= 0xe0) {
401 6
            return $c - 0x100;
402
        }
403 6
404 3
        switch ($c) {
405
            // uint
406 3
            case 0xcc: return self::unpackUint8($buffer, $offset);
407 1
            case 0xcd: return self::unpackUint16($buffer, $offset);
408
            case 0xce: return self::unpackUint32($buffer, $offset);
409 2
            case 0xcf: return $this->unpackUint64();
410 1
            // int
411
            case 0xd0: return self::unpackInt8($buffer, $offset);
412
            case 0xd1: return self::unpackInt16($buffer, $offset);
413 1
            case 0xd2: return self::unpackInt32($buffer, $offset);
414
            case 0xd3: return self::unpackInt64($buffer, $offset);
415
        }
416 9
417
        throw UnpackingFailedException::unexpectedCode($c, 'int');
418 9
    }
419
420 7
    public function unpackFloat()
421 7
    {
422 6
        $buffer = &$this->buffer;
423
        $offset = &$this->offset;
424
425 7
        if (!isset($buffer[$offset])) {
426
            throw new InsufficientDataException();
427
        }
428 9
429
        $c = \ord($buffer[$offset]);
430 9
        ++$offset;
431 1
432
        if (0xcb === $c) {
433
            return self::unpackFloat64($buffer, $offset);
434 8
        }
435 8
        if (0xca === $c) {
436
            return self::unpackFloat32($buffer, $offset);
437 8
        }
438 4
439
        throw UnpackingFailedException::unexpectedCode($c, 'float');
440 4
    }
441 2
442
    public function unpackStr()
443 2
    {
444 1
        $buffer = &$this->buffer;
445
        $offset = &$this->offset;
446
447 1
        if (!isset($buffer[$offset])) {
448
            throw new InsufficientDataException();
449
        }
450 43
451
        $c = \ord($buffer[$offset]);
452 43
        ++$offset;
453
454 41
        if ($c >= 0xa0 && $c <= 0xbf) {
455 41
            return ($c & 0x1f) ? $this->read($c & 0x1f) : '';
456 40
        }
457
        if (0xd9 === $c) {
458
            return $this->read(self::unpackUint8($buffer, $offset));
459 9
        }
460
        if (0xda === $c) {
461
            return $this->read(self::unpackUint16($buffer, $offset));
462 43
        }
463
        if (0xdb === $c) {
464 43
            return $this->read(self::unpackUint32($buffer, $offset));
465 1
        }
466
467
        throw UnpackingFailedException::unexpectedCode($c, 'str');
468 42
    }
469 42
470
    public function unpackBin()
471 42
    {
472 38
        $buffer = &$this->buffer;
473
        $offset = &$this->offset;
474 4
475 2
        if (!isset($buffer[$offset])) {
476
            throw new InsufficientDataException();
477 2
        }
478 1
479
        $c = \ord($buffer[$offset]);
480
        ++$offset;
481 1
482
        if (0xc4 === $c) {
483
            return $this->read(self::unpackUint8($buffer, $offset));
484 13
        }
485
        if (0xc5 === $c) {
486 13
            return $this->read(self::unpackUint16($buffer, $offset));
487 1
        }
488
        if (0xc6 === $c) {
489
            return $this->read(self::unpackUint32($buffer, $offset));
490 12
        }
491 12
492
        throw UnpackingFailedException::unexpectedCode($c, 'bin');
493
    }
494 12
495 11
    public function unpackArray()
496 10
    {
497 9
        $size = $this->unpackArrayHeader();
498 8
499 7
        $array = [];
500 5
        while ($size--) {
501 3
            $array[] = $this->unpack();
502
        }
503
504 1
        return $array;
505
    }
506
507 38 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...
508
    {
509 38
        $buffer = &$this->buffer;
510 2
        $offset = &$this->offset;
511
512
        if (!isset($buffer[$offset])) {
513 36
            throw new InsufficientDataException();
514
        }
515
516 32
        $c = \ord($buffer[$offset]);
517
        ++$offset;
518 32
519 2
        if ($c >= 0x90 && $c <= 0x9f) {
520
            return $c & 0xf;
521
        }
522 30
        if (0xdc === $c) {
523 30
            return self::unpackUint16($buffer, $offset);
524
        }
525
        if (0xdd === $c) {
526 24
            return self::unpackUint32($buffer, $offset);
527
        }
528 24
529 2
        throw UnpackingFailedException::unexpectedCode($c, 'array');
530
    }
531
532 22
    public function unpackMap()
533 22
    {
534 22
        $size = $this->unpackMapHeader();
535 22
536
        $map = [];
537
        while ($size--) {
538 16
            //$map[$this->unpackMapKey()] = $this->unpack();
539
            $map[$this->unpack()] = $this->unpack();
540 16
        }
541 1
542
        return $map;
543
    }
544 15
545 15 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...
546
    {
547 15
        $buffer = &$this->buffer;
548 10
        $offset = &$this->offset;
549
550 5
        if (!isset($buffer[$offset])) {
551 1
            throw new InsufficientDataException();
552
        }
553 4
554 1
        $c = \ord($buffer[$offset]);
555
        ++$offset;
556
557 3
        if ($c >= 0x80 && $c <= 0x8f) {
558
            return $c & 0xf;
559
        }
560 9
        if (0xde === $c) {
561
            return self::unpackUint16($buffer, $offset);
562 9
        }
563 1
        if (0xdf === $c) {
564
            return self::unpackUint32($buffer, $offset);
565
        }
566 8
567 8
        throw UnpackingFailedException::unexpectedCode($c, 'map');
568
    }
569 8
570
    public function unpackExt()
571
    {
572 9
        $buffer = &$this->buffer;
573
        $offset = &$this->offset;
574 9
575 1
        if (!isset($buffer[$offset])) {
576
            throw new InsufficientDataException();
577
        }
578 8
579 8
        $c = \ord($buffer[$offset]);
580 8
        ++$offset;
581
582 8
        switch ($c) {
583
            case 0xd4: return $this->unpackExtData(1);
584
            case 0xd5: return $this->unpackExtData(2);
585 9
            case 0xd6: return $this->unpackExtData(4);
586
            case 0xd7: return $this->unpackExtData(8);
587 9
            case 0xd8: return $this->unpackExtData(16);
588 1
            case 0xc7: return $this->unpackExtData(self::unpackUint8($buffer, $offset));
589
            case 0xc8: return $this->unpackExtData(self::unpackUint16($buffer, $offset));
590
            case 0xc9: return $this->unpackExtData(self::unpackUint32($buffer, $offset));
591 8
        }
592 8
593 8
        throw UnpackingFailedException::unexpectedCode($c, 'ext');
594 8
    }
595 8
596
    private static function unpackUint8($buffer, &$offset)
597 8
    {
598
        if (!isset($buffer[$offset])) {
599
            throw new InsufficientDataException();
600 15
        }
601
602 15
        return \ord($buffer[$offset++]);
603 1
    }
604
605
    private static function unpackUint16($buffer, &$offset)
606 14
    {
607 14
        if (!isset($buffer[$offset + 1])) {
608
            throw new InsufficientDataException();
609 14
        }
610
611
        return \ord($buffer[$offset++]) << 8
612 5
            | \ord($buffer[$offset++]);
613
    }
614 5
615 1
    private static function unpackUint32($buffer, &$offset)
616
    {
617
        if (!isset($buffer[$offset + 3])) {
618 4
            throw new InsufficientDataException();
619 4
        }
620
621 4
        return \ord($buffer[$offset++]) << 24
622
            | \ord($buffer[$offset++]) << 16
623
            | \ord($buffer[$offset++]) << 8
624 7
            | \ord($buffer[$offset++]);
625
    }
626 7
627 1
    private function unpackUint64()
628
    {
629
        $buffer = &$this->buffer;
630 6
        $offset = &$this->offset;
631 6
632
        if (!isset($buffer[$offset + 7])) {
633 6
            throw new InsufficientDataException();
634
        }
635
636 4
        $num = \unpack('J', $buffer, $offset)[1];
637
        $offset += 8;
638 4
639 4
        if ($num >= 0) {
640 4
            return $num;
641
        }
642
        if ($this->isBigIntAsDec) {
643 4
            return new Decimal(\sprintf('%u', $num));
644
        }
645
        if ($this->isBigIntAsGmp) {
646 5
            return \gmp_import(\substr($buffer, $offset - 8, 8));
647
        }
648 5
649 5
        return \sprintf('%u', $num);
650 5
    }
651
652
    private static function unpackInt8($buffer, &$offset)
653 5
    {
654
        if (!isset($buffer[$offset])) {
655
            throw new InsufficientDataException();
656 82
        }
657
658 82
        $num = \ord($buffer[$offset]);
659
        ++$offset;
660
661
        return $num > 0x7f ? $num - 0x100 : $num;
662 82
    }
663 82
664
    private static function unpackInt16($buffer, &$offset)
665
    {
666 82
        if (!isset($buffer[$offset + 1])) {
667 14
            throw new InsufficientDataException();
668
        }
669
670 76
        $num = \ord($buffer[$offset]) << 8
671 2
            | \ord($buffer[++$offset]);
672
        ++$offset;
673
674 74
        return $num > 0x7fff ? $num - 0x10000 : $num;
675 2
    }
676
677
    private static function unpackInt32($buffer, &$offset)
678
    {
679
        if (!isset($buffer[$offset + 3])) {
680 72
            throw new InsufficientDataException();
681 72
        }
682 70
683 68
        $num = \ord($buffer[$offset]) << 24
684
            | \ord($buffer[++$offset]) << 16
685 66
            | \ord($buffer[++$offset]) << 8
686 66
            | \ord($buffer[++$offset]);
687 66
        ++$offset;
688 66
689
        return $num > 0x7fffffff ? $num - 0x100000000 : $num;
690 66
    }
691 66
692 66 View Code Duplication
    private static function unpackInt64($buffer, &$offset)
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...
693
    {
694 66
        if (!isset($buffer[$offset + 7])) {
695 64
            throw new InsufficientDataException();
696 64
        }
697
698
        $num = \unpack('J', $buffer, $offset)[1];
699 64
        $offset += 8;
700
701
        return $num;
702 42
    }
703
704 42 View Code Duplication
    private static function unpackFloat32($buffer, &$offset)
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...
705 16
    {
706
        if (!isset($buffer[$offset + 3])) {
707
            throw new InsufficientDataException();
708
        }
709 26
710 26
        $num = \unpack('G', $buffer, $offset)[1];
711
        $offset += 4;
712 26
713
        return $num;
714
    }
715
716 26 View Code Duplication
    private static function unpackFloat64($buffer, &$offset)
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...
717 2
    {
718
        if (!isset($buffer[$offset + 7])) {
719
            throw new InsufficientDataException();
720 24
        }
721 24
722
        $num = \unpack('E', $buffer, $offset)[1];
723 24
        $offset += 8;
724
725
        return $num;
726
    }
727
728
    private function unpackExtData($length)
729
    {
730
        $buffer = &$this->buffer;
731
        $offset = &$this->offset;
732
733
        if (!isset($buffer[$offset + $length])) { // 1 (type) + length - 1
734
            throw new InsufficientDataException();
735
        }
736
737
        // int8
738
        $type = \ord($buffer[$offset]);
739
        ++$offset;
740
741
        if ($type > 0x7f) {
742
            $type -= 0x100;
743
        }
744
745
        if (isset($this->extensions[$type])) {
746
            return $this->extensions[$type]->unpackExt($this, $length);
747
        }
748
749
        $data = \substr($buffer, $offset, $length);
750
        $offset += $length;
751
752
        return new Ext($type, $data);
753
    }
754
}
755
756
final class Container
757
{
758
    public $type;
759
    public $size;
760
    public $count = 0;
761
    public $value;
762
    public $key;
763
764
    public function __construct($type, $size)
765
    {
766
        $this->type = $type;
767
        $this->size = $size;
768
    }
769
}
770