Issues (1)

src/ByteBuffer.php (1 issue)

Severity
1
<?php
2
/**
3
 * This file is part of PHPinnacle/Buffer.
4
 *
5
 * (c) PHPinnacle Team <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types = 1);
12
13
namespace PHPinnacle\Buffer;
14
15 1
if (!\class_exists('\PHPinnacle\Buffer\ByteBuffer'))
16
{
17
    class ByteBuffer
18
    {
19
        /**
20
         * @var bool
21
         */
22
        private static $isLittleEndian;
23
24
        /**
25
         * @var string
26
         */
27
        private $data;
28
29
        /**
30
         * @var int
31
         */
32
        private $size;
33
34
        /**
35
         * @param string $buffer
36
         */
37 48
        public function __construct(string $buffer = '')
38
        {
39 48
            $this->data = $buffer;
40 48
            $this->size = \strlen($this->data);
41
42 48
            if (!isset(self::$isLittleEndian)) {
43 1
                self::$isLittleEndian = \unpack("S", "\x01\x00")[1] === 1;
44
            }
45 48
        }
46
47
        /**
48
         * @param string|static $value
49
         *
50
         * @return static
51
         * @throws \TypeError
52
         */
53 15
        public function append($value): self
54
        {
55 15
            if ($value instanceof self) {
56 1
                $value = $value->data;
57
            }
58
59 15
            if (!\is_string($value)) {
0 ignored issues
show
The condition is_string($value) is always true.
Loading history...
60 1
                throw new \TypeError;
61
            }
62
63 14
            $this->data .= $value;
64 14
            $this->size += \strlen($value);
65
66 14
            return $this;
67
        }
68
69
        /**
70
         * @param int $n
71
         * @param int $offset
72
         *
73
         * @return string
74
         * @throws BufferOverflow
75
         */
76 29
        public function read(int $n, int $offset = 0): string
77
        {
78 29
            if ($this->size < $offset + $n) {
79 1
                throw new BufferOverflow;
80
            }
81
82 28
            if ($offset === 0 && $this->size === $offset + $n) {
83 27
                return $this->data;
84
            }
85
86 3
            return \substr($this->data, $offset, $n);
87
        }
88
89
        /**
90
         * @param int $n
91
         *
92
         * @return string
93
         * @throws BufferOverflow
94
         */
95 10
        public function consume(int $n): string
96
        {
97 10
            if ($this->size < $n) {
98 1
                throw new BufferOverflow;
99
            }
100
101 9
            if ($this->size === $n) {
102 9
                $buffer = $this->data;
103
104 9
                $this->data = '';
105 9
                $this->size = 0;
106
            } else {
107 2
                $buffer = \substr($this->data, 0, $n);
108
109 2
                $this->data = \substr($this->data, $n);
110 2
                $this->size -= $n;
111
            }
112
113 9
            return $buffer;
114
        }
115
116
        /**
117
         * @param int $n
118
         *
119
         * @return static
120
         * @throws BufferOverflow
121
         */
122 5
        public function discard(int $n): self
123
        {
124 5
            if ($this->size < $n) {
125 1
                throw new BufferOverflow;
126
            }
127
128 4
            if ($this->size === $n) {
129 4
                $this->data = '';
130 4
                $this->size = 0;
131
            } else {
132 1
                $this->data = \substr($this->data, $n);
133 1
                $this->size -= $n;
134
            }
135
136 4
            return $this;
137
        }
138
139
        /**
140
         * @param int $n
141
         *
142
         * @return static
143
         * @throws BufferOverflow
144
         */
145 2
        public function slice(int $n): self
146
        {
147 2
            if ($this->size < $n) {
148 1
                throw new BufferOverflow;
149
            }
150
151 1
            return $this->size === $n ? new static($this->data) : new static(\substr($this->data, 0, $n));
152
        }
153
154
        /**
155
         * @param int $n
156
         *
157
         * @return static
158
         * @throws BufferOverflow
159
         */
160 2
        public function shift(int $n): self
161
        {
162 2
            if ($this->size < $n) {
163 1
                throw new BufferOverflow;
164
            }
165
166 1
            if ($this->size === $n) {
167 1
                $buffer = $this->data;
168
169 1
                $this->data = '';
170 1
                $this->size = 0;
171
            } else {
172 1
                $buffer = \substr($this->data, 0, $n);
173
                
174 1
                $this->data = \substr($this->data, $n);
175 1
                $this->size -= $n;
176
            }
177
178 1
            return new static($buffer);
179
        }
180
181
        /**
182
         * @return string
183
         */
184 1
        public function flush(): string
185
        {
186 1
            $data = $this->data;
187
188 1
            $this->data = '';
189 1
            $this->size = 0;
190
191 1
            return $data;
192
        }
193
194
        /**
195
         * @return int
196
         */
197 11
        public function size(): int
198
        {
199 11
            return $this->size;
200
        }
201
202
        /**
203
         * @return boolean
204
         */
205 3
        public function empty(): bool
206
        {
207 3
            return $this->size === 0;
208
        }
209
210
        /**
211
         * @param int $value
212
         *
213
         * @return static
214
         */
215 1
        public function appendInt8(int $value): self
216
        {
217 1
            return $this->append(\pack("c", $value));
218
        }
219
220
        /**
221
         * @param int $offset
222
         *
223
         * @return int
224
         * @throws BufferOverflow
225
         */
226 1
        public function readInt8(int $offset = 0): int
227
        {
228 1
            return \unpack("c", $this->read(1, $offset))[1];
229
        }
230
231
        /**
232
         * @return int
233
         * @throws BufferOverflow
234
         */
235 1
        public function consumeInt8(): int
236
        {
237 1
            return \unpack("c", $this->consume(1))[1];
238
        }
239
240
        /**
241
         * @param int $value
242
         *
243
         * @return static
244
         */
245 1
        public function appendInt16(int $value): self
246
        {
247 1
            return $this->append(self::swapEndian16(\pack("s", $value)));
248
        }
249
250
        /**
251
         * @param int $offset
252
         *
253
         * @return int
254
         * @throws BufferOverflow
255
         */
256 1
        public function readInt16(int $offset = 0): int
257
        {
258 1
            return \unpack("s", self::swapEndian16($this->read(2, $offset)))[1];
259
        }
260
261
        /**
262
         * @return int
263
         * @throws BufferOverflow
264
         */
265 1
        public function consumeInt16(): int
266
        {
267 1
            return \unpack("s", self::swapEndian16($this->consume(2)))[1];
268
        }
269
270
        /**
271
         * @param int $value
272
         *
273
         * @return static
274
         */
275 1
        public function appendInt32(int $value): self
276
        {
277 1
            return $this->append(self::swapEndian32(\pack("l", $value)));
278
        }
279
280
        /**
281
         * @param int $offset
282
         *
283
         * @return int
284
         * @throws BufferOverflow
285
         */
286 1
        public function readInt32(int $offset = 0): int
287
        {
288 1
            return \unpack("l", self::swapEndian32($this->read(4, $offset)))[1];
289
        }
290
291
        /**
292
         * @return int
293
         * @throws BufferOverflow
294
         */
295 1
        public function consumeInt32(): int
296
        {
297 1
            return \unpack("l", self::swapEndian32($this->consume(4)))[1];
298
        }
299
300
        /**
301
         * @param int $value
302
         *
303
         * @return static
304
         */
305 1
        public function appendInt64(int $value): self
306
        {
307 1
            return $this->append(self::swapEndian64(\pack("q", $value)));
308
        }
309
310
        /**
311
         * @param int $offset
312
         *
313
         * @return int
314
         * @throws BufferOverflow
315
         */
316 1
        public function readInt64(int $offset = 0): int
317
        {
318 1
            return \unpack("q", self::swapEndian64($this->read(8, $offset)))[1];
319
        }
320
321
        /**
322
         * @return int
323
         * @throws BufferOverflow
324
         */
325 1
        public function consumeInt64(): int
326
        {
327 1
            return \unpack("q", self::swapEndian64($this->consume(8)))[1];
328
        }
329
330
        /**
331
         * @param int $value
332
         *
333
         * @return static
334
         */
335 1
        public function appendUint8(int $value): self
336
        {
337 1
            return $this->append(\pack("C", $value));
338
        }
339
340
        /**
341
         * @param int $offset
342
         *
343
         * @return int
344
         * @throws BufferOverflow
345
         */
346 1
        public function readUint8(int $offset = 0): int
347
        {
348 1
            return \unpack("C", $this->read(1, $offset))[1];
349
        }
350
351
        /**
352
         * @return int
353
         * @throws BufferOverflow
354
         */
355 1
        public function consumeUint8(): int
356
        {
357 1
            $r = \unpack("C", $this->data)[1];
358
359 1
            $this->discard(1);
360
361 1
            return $r;
362
        }
363
364
        /**
365
         * @param int $value
366
         *
367
         * @return static
368
         */
369 1
        public function appendUint16(int $value): self
370
        {
371 1
            return $this->append(\pack("n", $value));
372
        }
373
374
        /**
375
         * @param int $offset
376
         *
377
         * @return int
378
         * @throws BufferOverflow
379
         */
380 1
        public function readUint16(int $offset = 0): int
381
        {
382 1
            return \unpack("n", $this->read(2, $offset))[1];
383
        }
384
385
        /**
386
         * @return int
387
         * @throws BufferOverflow
388
         */
389 1
        public function consumeUint16(): int
390
        {
391 1
            $r = \unpack("n", $this->data)[1];
392
393 1
            $this->discard(2);
394
395 1
            return $r;
396
        }
397
398
        /**
399
         * @param int $value
400
         *
401
         * @return static
402
         */
403 1
        public function appendUint32(int $value): self
404
        {
405 1
            return $this->append(\pack("N", $value));
406
        }
407
408
        /**
409
         * @param int $offset
410
         *
411
         * @return int
412
         * @throws BufferOverflow
413
         */
414 1
        public function readUint32(int $offset = 0): int
415
        {
416 1
            return \unpack("N", $this->read(4, $offset))[1];
417
        }
418
419
        /**
420
         * @return int
421
         * @throws BufferOverflow
422
         */
423 1
        public function consumeUint32(): int
424
        {
425 1
            $r = \unpack("N", $this->data)[1];
426
427 1
            $this->discard(4);
428
429 1
            return $r;
430
        }
431
432
        /**
433
         * @param int $value
434
         *
435
         * @return static
436
         */
437 1
        public function appendUint64(int $value): self
438
        {
439 1
            return $this->append(self::swapEndian64(\pack("Q", $value)));
440
        }
441
442
        /**
443
         * @param int $offset
444
         *
445
         * @return int
446
         * @throws BufferOverflow
447
         */
448 1
        public function readUint64(int $offset = 0): int
449
        {
450 1
            return \unpack("Q", self::swapEndian64($this->read(8, $offset)))[1];
451
        }
452
453
        /**
454
         * @return int
455
         * @throws BufferOverflow
456
         */
457 1
        public function consumeUint64(): int
458
        {
459 1
            return \unpack("Q", self::swapEndian64($this->consume(8)))[1];
460
        }
461
462
        /**
463
         * @param float $value
464
         *
465
         * @return static
466
         */
467 1
        public function appendFloat(float $value): self
468
        {
469 1
            return $this->append(self::swapEndian32(\pack("f", $value)));
470
        }
471
472
        /**
473
         * @param int $offset
474
         *
475
         * @return float
476
         * @throws BufferOverflow
477
         */
478 1
        public function readFloat(int $offset = 0): float
479
        {
480 1
            return \unpack("f", self::swapEndian32($this->read(4, $offset)))[1];
481
        }
482
483
        /**
484
         * @return float
485
         * @throws BufferOverflow
486
         */
487 1
        public function consumeFloat(): float
488
        {
489 1
            return \unpack("f", self::swapEndian32($this->consume(4)))[1];
490
        }
491
492
        /**
493
         * @param float $value
494
         *
495
         * @return static
496
         */
497 1
        public function appendDouble($value): self
498
        {
499 1
            return $this->append(self::swapEndian64(\pack("d", $value)));
500
        }
501
502
        /**
503
         * @param int $offset
504
         *
505
         * @return float
506
         * @throws BufferOverflow
507
         */
508 1
        public function readDouble(int $offset = 0): float
509
        {
510 1
            return \unpack("d", self::swapEndian64($this->read(8, $offset)))[1];
511
        }
512
513
        /**
514
         * @return float
515
         * @throws BufferOverflow
516
         */
517 1
        public function consumeDouble(): float
518
        {
519 1
            return \unpack("d", self::swapEndian64($this->consume(8)))[1];
520
        }
521
522
        /**
523
         * @return string
524
         */
525 1
        public function __toString(): string
526
        {
527 1
            return $this->data;
528
        }
529
530
        /**
531
         * @param string $s
532
         *
533
         * @return string
534
         */
535 3
        private static function swapEndian16(string $s): string
536
        {
537 3
            return self::$isLittleEndian ? $s[1] . $s[0] : $s;
538
        }
539
540
        /**
541
         * @param string $s
542
         *
543
         * @return string
544
         */
545 6
        private static function swapEndian32(string $s): string
546
        {
547 6
            return self::$isLittleEndian ? $s[3] . $s[2] . $s[1] . $s[0] : $s;
548
        }
549
550
        /**
551
         * @param string $s
552
         *
553
         * @return string
554
         */
555 9
        private static function swapEndian64(string $s): string
556
        {
557 9
            return self::$isLittleEndian ? $s[7] . $s[6] . $s[5] . $s[4] . $s[3] . $s[2] . $s[1] . $s[0] : $s;
558
        }
559
    }
560
}
561