156 lines
3.1 KiB
PHP
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;
|
|
}
|
|
} |