Skip to content

Commit 5fa9740

Browse files
committed
Streamlined Decoder::readDigits() for common paths
1 parent c483d98 commit 5fa9740

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

src/Decoder.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ protected function dictionaryComplianceError(string $key, string $lastKey): void
252252
$this->complianceError($msg . " dictionary entry '" . $key . "'", $offset);
253253
}
254254

255+
protected function digitException(): DecodingException
256+
{
257+
return (str_contains('0123456789', $this->bencoded[$this->offset]))
258+
? new ComplianceError('Illegal character', $this->offset)
259+
: new DecodingException('Illegal character', $this->offset);
260+
}
261+
255262
/**
256263
* Return the rightmost boundary to the last safe character that can start a value
257264
*
@@ -276,23 +283,26 @@ protected function getSafeBoundary(): int
276283

277284
protected function readDigits(string $terminator): string
278285
{
279-
// Digits sorted by decreasing frequency as observed on a random sample of torrent files
280-
$spn = strspn($this->bencoded, '1463720859', $this->offset);
281-
if ($spn === 0)
286+
if ($this->bencoded[$this->offset] === '0')
282287
{
283-
throw new DecodingException('Illegal character', $this->offset);
288+
++$this->offset;
289+
$string = '0';
284290
}
285-
286-
$string = substr($this->bencoded, $this->offset, $spn);
287-
if ($string[0] === '0' && $spn !== 1)
291+
else
288292
{
289-
$this->complianceError('Illegal character', 1 + $this->offset);
293+
// Digits sorted by decreasing frequency as observed on a random sample of torrent files
294+
$spn = strspn($this->bencoded, '1463720859', $this->offset);
295+
if ($spn === 0)
296+
{
297+
throw new DecodingException('Illegal character', $this->offset);
298+
}
299+
$string = substr($this->bencoded, $this->offset, $spn);
300+
$this->offset += $spn;
290301
}
291302

292-
$this->offset += $spn;
293303
if ($this->bencoded[$this->offset] !== $terminator)
294304
{
295-
throw new DecodingException('Illegal character', $this->offset);
305+
throw $this->digitException();
296306
}
297307
++$this->offset;
298308

src/NonCompliantDecoder.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use ArrayObject;
1111
use const SORT_STRING, false, true;
12-
use function strcmp;
12+
use function preg_match, strcmp, strlen;
1313

1414
class NonCompliantDecoder extends Decoder
1515
{
@@ -41,4 +41,16 @@ protected function dictionaryComplianceError(string $key, string $lastKey): void
4141
{
4242
$this->sortDictionary = true;
4343
}
44+
45+
protected function readDigits(string $terminator): string
46+
{
47+
if ($this->bencoded[$this->offset] === '0')
48+
{
49+
// Skip past the trailing zeroes and stop at the next digit or the last zero
50+
preg_match('(0++[1-9]?)A', $this->bencoded, $m, 0, $this->offset);
51+
$this->offset += strlen($m[0]) - 1;
52+
}
53+
54+
return parent::readDigits($terminator);
55+
}
4456
}

tests/DecoderTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ public static function getDecodeInvalidTests()
268268
'i1x',
269269
new DecodingException('Illegal character', 2)
270270
],
271+
[
272+
'i0x',
273+
new DecodingException('Illegal character', 2)
274+
],
271275
[
272276
'lxe',
273277
new DecodingException('Illegal character', 1)

0 commit comments

Comments
 (0)