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
2019-07-12 10:42:01 +07:00

149 lines
3.0 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 {
/**
* 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,string $content)
{
for ($c=$start;$c <= strlen($content);$c++)
{
if ($content{$c} != $char)
return $c-$start;
}
return FALSE;
}
/**
* @param $startline
* @param int $offset
* @return string
*/
protected function parse(int $startline,string $content,int $width): string
{
// Our starting coordinates
$x = 1;
$y = $startline;
$output = '';
// Scan the frame for a field start
for ($c=0; $c<=strlen($content); $c++)
{
// If the frame is not big enough, fill it with spaces.
$byte = isset($content{$c}) ? $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($content{$c+$advance}) ? $content{$c+$advance} : ' ';
switch ($nextbyte) {
case '[':
$advance++;
$chars = $nextbyte;
// Find our end CSI param
$matches = [];
$a = preg_match('/([0-9]+[;]?)+([a-zA-Z])/',$content,$matches,NULL,$c+$advance);
if (! $a)
break;
$advance += strlen($matches[0])-1;
$chars .= $matches[0];
if (! isset($this->frame_data[$y][$x]))
$this->frame_data[$y][$x] = '';
else
$this->frame_data[$y][$x] .= '|';
$this->frame_data[$y][$x] .= $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:
// Allow for the original ESC
$c--;
$advance++;
$fieldtype = ord($nextbyte);
$fieldlength = $this->findEOF(chr($fieldtype),$c+2,$content)+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++;
}
$this->frame_content[$y][$x] = $byte;
$output .= $byte;
if ($advance) {
$output .= $chars;
$c += $advance;
}
if ($x > $width) {
$x = 1;
$y++;
}
}
return $output;
}
}