This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
vbbs/app/Classes/Parser/Ansi.php
2018-12-14 10:21:25 +11:00

156 lines
3.1 KiB
PHP

<?php
namespace App\Classes\Parser;
use Illuminate\Support\Facades\Log;
use App\Classes\FrameFields;
use App\Classes\Parser as AbstractParser;
use App\Classes\Frame\Ansi as AnsiFrame;
class Ansi extends AbstractParser {
private $content = '';
private $startline = 0;
public $fields = NULL;
public function __construct(string $content,int $startline=1)
{
$this->content = $content;
$this->startline = $startline;
$this->fields = collect();
}
public function __toString(): string
{
return $this->parse($this->startline);
}
/**
* Parse a string and look for the next character that is not $char
*
* @param string $char
* @param int $start
* @return bool|int
*/
private function findEOF(string $char,int $start)
{
for ($c=$start;$c <= strlen($this->content);$c++)
{
if ($this->content{$c} != $char)
return $c-$start;
}
return FALSE;
}
/**
* @param $startline
* @param int $offset
* @return string
*/
private function parse($startline): string
{
// Our starting coordinates
$x = 1;
$y = $startline;
$output = '';
// Scan the frame for a field start
for ($c=0; $c<=strlen($this->content); $c++)
{
// If the frame is not big enough, fill it with spaces.
$byte = isset($this->content{$c}) ? $this->content{$c} : ' ';
$advance = 0;
switch ($byte) {
case CR:
$x = 1;
break;
case LF:
$y++;
break;
case ESC:
$advance = 1;
// Is the next byte something we know about
$nextbyte = isset($this->content{$c+$advance}) ? $this->content{$c+$advance} : ' ';
switch ($nextbyte) {
case '[':
$advance++;
$chars = $nextbyte;
// Find our end CSI param
$matches = [];
$a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$this->content,$matches,NULL,$c+$advance);
if (! $a)
break;
$advance += strlen($matches[0])-1;
$chars .= $matches[0];
switch ($matches[2]) {
// We ignore 'm' they are color CSIs
case 'm': break;
case 'C':
$x += $matches[1]; // Advance our position
break;
default:
dump('Unhandled CSI: '.$matches[2]);
}
break;
case ' ':
dump(['l'=>__LINE__,'LOOSE ESC?']);
break;
default:
$c--; // Allow for the original ESC
$advance++;
$fieldtype = ord($nextbyte)%128; // @todo Do we need the %128 for ANSI?
$fieldlength = $this->findEOF(chr($fieldtype),$c+2)+1;
$byte = '';
$this->fields->push(new FrameFields([
'type'=>chr($fieldtype),
'length'=>$fieldlength,
'x'=>$x, // Adjust for the ESC char
'y'=>$y,
]));
Log::debug(sprintf('Field found at [%s,%s], Type: %s, Length: %s',$x-1,$y,$fieldtype,$fieldlength));
$advance += $fieldlength-2;
$x += $fieldlength;
$chars = $this->fields->last()->output(AnsiFrame::$if_filler);
}
break;
default:
$x++;
}
$output .= $byte;
if ($advance) {
$output .= $chars;
$c += $advance;
}
if ($x > 80) {
$x = 1;
$y++;
}
}
return $output;
}
}