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; } }