Skip to content

Commit

Permalink
Merge pull request #29 from Hyleus/bencode
Browse files Browse the repository at this point in the history
This will make the bencode decoder more robust and stable. Some
functionality is now split in seperate functions.
  • Loading branch information
HDVinnie committed Dec 13, 2017
2 parents e58563c + 9a37cdd commit 4099f66
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 48 deletions.
167 changes: 121 additions & 46 deletions app/Services/Bencode.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,67 +9,142 @@
* @license https://choosealicense.com/licenses/gpl-3.0/ GNU General Public License v3.0
* @author BluCrew
*/

namespace App\Services;

use function theodorejb\polycast\{safe_int, safe_float};

/**
* Bencode library for torrents
*
*/
class Bencode
{
public static function bdecode($s, & $pos = 0)
public static function parse_integer($s, &$pos)
{
if ($pos >= strlen($s)) {
$len = strlen($s);
if ($len == 0 || $s[$pos] != 'i') {
return null;
}
++$pos;

switch ($s[$pos]) {
case 'd':
$pos++;
$retval = [];
while ($s[$pos] != 'e') {
$key = self::bdecode($s, $pos);
$val = self::bdecode($s, $pos);
if ($key === null || $val === null) {
break;
}
$retval[$key] = $val;
}
$retval['isDct'] = true;
$pos++;
return $retval;

case 'l':
$pos++;
$retval = [];
while ($s[$pos] != 'e') {
$val = self::bdecode($s, $pos);
if ($val === null) {
break;
}
$retval[] = $val;
$result = "";
while ($pos < $len && $s[$pos] != 'e') {
if (is_numeric($s[$pos])) {
$result .= $s[$pos];
} else {
// We have an invalid character in the string.
return null;
}
++$pos;
}

if ($pos >= $len) {
// No end marker, hence we return null.
return null;
}

++$pos;

if (safe_int($result)) {
return (int)$result;
} else {
return null;
}
}

public static function parse_string($s, &$pos)
{
$len = strlen($s);
$length_str = "";

while ($pos < $len && $s[$pos] != ':') {
if (is_numeric($s[$pos])) {
$length_str .= $s[$pos];
} else {
// Non-numeric character, we return null in this case.
return null;
}
++$pos;
}

if ($pos >= $len) {
// We need a colon here, but there's none.
return null;
}

++$pos;
if (!safe_int($length_str)) {
return null;
}

$length = (int)$length_str;
$result = "";
while ($pos < $len && $length > 0) {
$result .= $s[$pos];
--$length;
++$pos;
}

if ($length > 0) {
// Input ended, but the string is longer than that.
return null;
}

return $result;
}

public static function bdecode($s, &$pos = 0)
{
$len = strlen($s);
if ($pos >= $len) {
return null;
}

$c = $s[$pos];
if ($c == 'i') {
return self::parse_integer($s, $pos);
} elseif (is_numeric($c)) {
return self::parse_string($s, $pos);
} elseif ($c == 'd') {
$dict = [];
++$pos;
while ($pos < $len && $s[$pos] != 'e') {
$key = self::bdecode($s, $pos);
$value = self::bdecode($s, $pos);
if (is_null($key) || is_null($value)) {
return null;
}
$pos++;
return $retval;

case 'i':
$pos++;
$digits = strpos($s, 'e', $pos) - $pos;
$val = round((float)substr($s, $pos, $digits));
$pos += $digits + 1;
return $val;

default:
$digits = strpos($s, ':', $pos) - $pos;
if ($digits < 0 || $digits > 20) {
$dict[$key] = $value;
}

if ($pos >= $len) {
// We need a end marker here
return null;
}
++$pos;

return $dict;
} elseif ($c == 'l') {
$list = [];
++$pos;
while ($pos < $len && $s[$pos] != 'e') {
$next = self::bdecode($s, $pos);
if (!is_null($next)) {
array_push($list, $next);
} else {
return null;
}
$len = (int)substr($s, $pos, $digits);
$pos += $digits + 1;
$str = substr($s, $pos, $len);
$pos += $len;
return (string)$str;
}

if ($pos >= $len) {
// We need a end marker here
return null;
}
++$pos;
return $list;
} else {
return null;
}
}

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"predis/predis": "1.1.1",
"renatomarinho/laravel-page-speed": "^1.8",
"spatie/laravel-cookie-consent": "^1.8",
"spatie/laravel-image-optimizer": "^1.1"
"spatie/laravel-image-optimizer": "^1.1",
"theodorejb/polycast": "^1.0"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
Expand Down
39 changes: 38 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4099f66

Please sign in to comment.