Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.16% covered (success)
92.16%
47 / 51
60.00% covered (warning)
60.00%
6 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
PacketReader
92.16% covered (success)
92.16%
47 / 51
60.00% covered (warning)
60.00%
6 / 10
26.33
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 remaining
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 pos
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 readInt32
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 readUint32
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 readUint16
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 readUint8
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 readFloat
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
 readString
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 rest
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php declare(strict_types=1);
2
3/**
4 * Clansuite Server Query
5 *
6 * SPDX-FileCopyrightText: 2003-2025 Jens A. Koch
7 * SPDX-License-Identifier: MIT
8 *
9 * For the full copyright and license information, please view
10 * the LICENSE file that was distributed with this source code.
11 */
12
13namespace Clansuite\ServerQuery\Util;
14
15use function ord;
16use function strlen;
17use function substr;
18use function unpack;
19
20/**
21 * Utility class for reading binary data from network packets, providing methods to extract various data types.
22 */
23final class PacketReader
24{
25    private int $pos = 0;
26
27    /**
28     * Constructor.
29     */
30    public function __construct(private string $buffer)
31    {
32        $this->pos = 0;
33    }
34
35    /**
36     * remaining method.
37     */
38    public function remaining(): int
39    {
40        return strlen($this->buffer) - $this->pos;
41    }
42
43    /**
44     * pos method.
45     */
46    public function pos(): int
47    {
48        return $this->pos;
49    }
50
51    /**
52     * readInt32 method.
53     */
54    public function readInt32(): ?int
55    {
56        if ($this->remaining() < 4) {
57            return null;
58        }
59        $data = unpack('l', substr($this->buffer, $this->pos, 4));
60
61        if ($data === false || !isset($data[1])) {
62            return null;
63        }
64
65        $v = (int) $data[1];
66        $this->pos += 4;
67
68        return $v;
69    }
70
71    /**
72     * readUint32 method.
73     */
74    public function readUint32(): ?int
75    {
76        if ($this->remaining() < 4) {
77            return null;
78        }
79        $data = unpack('V', substr($this->buffer, $this->pos, 4));
80
81        if ($data === false || !isset($data[1])) {
82            return null;
83        }
84
85        $v = (int) $data[1];
86        $this->pos += 4;
87
88        return $v;
89    }
90
91    /**
92     * readUint16 method.
93     */
94    public function readUint16(): ?int
95    {
96        if ($this->remaining() < 2) {
97            return null;
98        }
99        $data = unpack('v', substr($this->buffer, $this->pos, 2));
100
101        if ($data === false || !isset($data[1])) {
102            return null;
103        }
104
105        $v = (int) $data[1];
106        $this->pos += 2;
107
108        return $v;
109    }
110
111    /**
112     * readUint8 method.
113     */
114    public function readUint8(): ?int
115    {
116        if ($this->remaining() < 1) {
117            return null;
118        }
119        $v = ord($this->buffer[$this->pos]);
120        $this->pos++;
121
122        return $v;
123    }
124
125    /**
126     * readFloat method.
127     */
128    public function readFloat(): ?float
129    {
130        if ($this->remaining() < 4) {
131            return null;
132        }
133        $data = unpack('f', substr($this->buffer, $this->pos, 4));
134
135        if ($data === false || !isset($data[1])) {
136            return null;
137        }
138
139        $v = (float) $data[1];
140        $this->pos += 4;
141
142        return $v;
143    }
144
145    /**
146     * readString method.
147     */
148    public function readString(): ?string
149    {
150        $start = $this->pos;
151
152        while ($this->pos < strlen($this->buffer) && $this->buffer[$this->pos] !== "\x00") {
153            $this->pos++;
154        }
155
156        if ($this->pos >= strlen($this->buffer)) {
157            return null;
158        }
159        $s = substr($this->buffer, $start, $this->pos - $start);
160        $this->pos++; // skip null
161
162        return $s;
163    }
164
165    /**
166     * rest method.
167     */
168    public function rest(): string
169    {
170        $r         = substr($this->buffer, $this->pos);
171        $this->pos = strlen($this->buffer);
172
173        return $r;
174    }
175}