• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

azjezz / psl / 23101178730

15 Mar 2026 02:02AM UTC coverage: 95.57%. Remained the same
23101178730

push

github

web-flow
bc: use $camelCase variable naming everywhere (#631)

930 of 1013 new or added lines in 219 files covered. (91.81%)

10 existing lines in 8 files now uncovered.

10462 of 10947 relevant lines covered (95.57%)

32.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

44.25
/src/Psl/Encoding/QuotedPrintable/EncodingReadHandle.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Psl\Encoding\QuotedPrintable;
6

7
use Psl;
8
use Psl\Async\CancellationTokenInterface;
9
use Psl\Async\NullCancellationToken;
10
use Psl\IO;
11

12
use function str_ends_with;
13
use function strlen;
14
use function strpos;
15
use function substr;
16

17
/**
18
 * A read handle that encodes raw text from an inner readable handle using quoted-printable encoding.
19
 *
20
 * Reads line-by-line from the inner handle and encodes each line via {@see encode_line()}.
21
 */
22
final class EncodingReadHandle implements IO\BufferedReadHandleInterface
23
{
24
    use IO\ReadHandleConvenienceMethodsTrait;
25

26
    private IO\Reader $reader;
27
    private string $buffer = '';
28
    private bool $eof = false;
29
    private bool $firstLine = true;
30

31
    public function __construct(IO\ReadHandleInterface $handle)
32
    {
33
        $this->reader = new IO\Reader($handle);
10✔
34
    }
35

36
    public function reachedEndOfDataSource(): bool
37
    {
38
        return $this->eof && $this->buffer === '';
8✔
39
    }
40

41
    public function tryRead(null|int $maxBytes = null): string
42
    {
43
        if ($this->buffer === '' && !$this->eof) {
8✔
44
            $this->fillBuffer();
×
45
        }
46

47
        if ($this->buffer === '') {
8✔
48
            return '';
1✔
49
        }
50

51
        if (null === $maxBytes || $maxBytes >= strlen($this->buffer)) {
7✔
52
            $result = $this->buffer;
7✔
53
            $this->buffer = '';
7✔
54
            return $result;
7✔
55
        }
56

NEW
57
        $result = substr($this->buffer, 0, $maxBytes);
×
NEW
58
        $this->buffer = substr($this->buffer, $maxBytes);
×
UNCOV
59
        return $result;
×
60
    }
61

62
    public function read(
63
        null|int $maxBytes = null,
64
        CancellationTokenInterface $cancellation = new NullCancellationToken(),
65
    ): string {
66
        if ($this->eof && $this->buffer === '') {
8✔
67
            return '';
×
68
        }
69

70
        if ($this->buffer === '') {
8✔
71
            $this->fillBuffer($cancellation);
7✔
72
        }
73

74
        return $this->tryRead($maxBytes);
8✔
75
    }
76

77
    public function readByte(CancellationTokenInterface $cancellation = new NullCancellationToken()): string
78
    {
79
        if ($this->buffer === '' && !$this->eof) {
2✔
80
            $this->fillBuffer($cancellation);
2✔
81
        }
82

83
        if ($this->buffer === '') {
2✔
84
            throw new IO\Exception\RuntimeException('Reached EOF without any more data.');
1✔
85
        }
86

87
        $ret = $this->buffer[0];
1✔
88
        if ($ret === $this->buffer) {
1✔
89
            $this->buffer = '';
1✔
90
            return $ret;
1✔
91
        }
92

93
        $this->buffer = substr($this->buffer, 1);
1✔
94
        return $ret;
1✔
95
    }
96

97
    public function readLine(CancellationTokenInterface $cancellation = new NullCancellationToken()): null|string
98
    {
99
        $line = $this->readUntil("\n", $cancellation);
×
100
        if ($line !== null) {
×
101
            if ($line !== '' && $line[-1] === "\r") {
×
102
                return substr($line, 0, -1);
×
103
            }
104

105
            return $line;
×
106
        }
107

108
        // No EOL found; return whatever remains, or null if empty
109
        if ($this->buffer === '' && !$this->eof) {
×
110
            $this->fillBuffer($cancellation);
×
111
        }
112

113
        if ($this->buffer === '') {
×
114
            return null;
×
115
        }
116

117
        $result = $this->buffer;
×
118
        $this->buffer = '';
×
119
        return $result;
×
120
    }
121

122
    public function readUntil(
123
        string $suffix,
124
        CancellationTokenInterface $cancellation = new NullCancellationToken(),
125
    ): null|string {
126
        $suffixLen = strlen($suffix);
1✔
127
        $idx = strpos($this->buffer, $suffix);
1✔
128
        if ($idx !== false) {
1✔
129
            $result = substr($this->buffer, 0, $idx);
×
NEW
130
            $this->buffer = substr($this->buffer, $idx + $suffixLen);
×
131
            return $result;
×
132
        }
133

134
        while (!$this->eof) {
1✔
135
            $offset = strlen($this->buffer) - $suffixLen + 1;
1✔
136
            $offset = $offset > 0 ? $offset : 0;
1✔
137

138
            $this->fillBuffer($cancellation);
1✔
139

140
            $idx = strpos($this->buffer, $suffix, $offset);
1✔
141
            if ($idx !== false) {
1✔
142
                $result = substr($this->buffer, 0, $idx);
1✔
143
                $this->buffer = substr($this->buffer, $idx + $suffixLen);
1✔
144
                return $result;
1✔
145
            }
146
        }
147

148
        return null;
×
149
    }
150

151
    public function readUntilBounded(
152
        string $suffix,
153
        int $maxBytes,
154
        CancellationTokenInterface $cancellation = new NullCancellationToken(),
155
    ): null|string {
NEW
156
        $suffixLen = strlen($suffix);
×
157
        $idx = strpos($this->buffer, $suffix);
×
158
        if ($idx !== false) {
×
NEW
159
            if ($idx > $maxBytes) {
×
160
                throw new IO\Exception\OverflowException(Psl\Str\format(
×
161
                    'Exceeded maximum byte limit (%d) before encountering the suffix ("%s").',
×
NEW
162
                    $maxBytes,
×
163
                    $suffix,
×
164
                ));
×
165
            }
166

167
            $result = substr($this->buffer, 0, $idx);
×
NEW
168
            $this->buffer = substr($this->buffer, $idx + $suffixLen);
×
169
            return $result;
×
170
        }
171

NEW
172
        if (strlen($this->buffer) > $maxBytes) {
×
173
            throw new IO\Exception\OverflowException(Psl\Str\format(
×
174
                'Exceeded maximum byte limit (%d) before encountering the suffix ("%s").',
×
NEW
175
                $maxBytes,
×
176
                $suffix,
×
177
            ));
×
178
        }
179

180
        while (!$this->eof) {
×
NEW
181
            $offset = strlen($this->buffer) - $suffixLen + 1;
×
182
            $offset = $offset > 0 ? $offset : 0;
×
183

184
            $this->fillBuffer($cancellation);
×
185

186
            $idx = strpos($this->buffer, $suffix, $offset);
×
187
            if ($idx !== false) {
×
NEW
188
                if ($idx > $maxBytes) {
×
189
                    throw new IO\Exception\OverflowException(Psl\Str\format(
×
190
                        'Exceeded maximum byte limit (%d) before encountering the suffix ("%s").',
×
NEW
191
                        $maxBytes,
×
192
                        $suffix,
×
193
                    ));
×
194
                }
195

196
                $result = substr($this->buffer, 0, $idx);
×
NEW
197
                $this->buffer = substr($this->buffer, $idx + $suffixLen);
×
198
                return $result;
×
199
            }
200

NEW
201
            if (strlen($this->buffer) > $maxBytes) {
×
202
                throw new IO\Exception\OverflowException(Psl\Str\format(
×
203
                    'Exceeded maximum byte limit (%d) before encountering the suffix ("%s").',
×
NEW
204
                    $maxBytes,
×
205
                    $suffix,
×
206
                ));
×
207
            }
208
        }
209

210
        return null;
×
211
    }
212

213
    private function fillBuffer(CancellationTokenInterface $cancellation = new NullCancellationToken()): void
214
    {
215
        if ($this->eof) {
10✔
216
            return;
×
217
        }
218

219
        $line = $this->reader->readUntil("\n", $cancellation);
10✔
220
        if ($line !== null) {
10✔
221
            $line = str_ends_with($line, "\r") ? substr($line, 0, -1) : $line;
2✔
222

223
            if (!$this->firstLine) {
2✔
224
                $this->buffer .= "\r\n";
×
225
            }
226

227
            $this->buffer .= encode_line($line);
2✔
228
            $this->firstLine = false;
2✔
229

230
            return;
2✔
231
        }
232

233
        $remaining = $this->reader->read(null, $cancellation);
10✔
234
        if ($remaining !== '') {
10✔
235
            $remaining = str_ends_with($remaining, "\r") ? substr($remaining, 0, -1) : $remaining;
8✔
236

237
            if (!$this->firstLine) {
8✔
238
                $this->buffer .= "\r\n";
2✔
239
            }
240

241
            $this->buffer .= encode_line($remaining);
8✔
242
        }
243

244
        $this->eof = true;
10✔
245
    }
246
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc