/***************************************************************************
codegenerator.cpp - description
-------------------
copyright : (C) 2007-2021 by Andre Simon
email : a.simon@mailbox.org
***************************************************************************/
/*
This file is part of ANSIFilter.
ANSIFilter is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ANSIFilter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ANSIFilter. If not, see .
*/
#include "codegenerator.h"
#ifdef WIN32
#include
#else
#include
#endif
#include
#include
#include
#include "version.h"
#include "pangogenerator.h"
#include "htmlgenerator.h"
#include "rtfgenerator.h"
#include "plaintextgenerator.h"
#include "texgenerator.h"
#include "latexgenerator.h"
#include "bbcodegenerator.h"
#include "svggenerator.h"
namespace ansifilter
{
CodeGenerator * CodeGenerator::getInstance(OutputType type)
{
CodeGenerator* generator=NULL;
switch (type) {
case TEXT:
generator = new PlaintextGenerator();
break;
case HTML:
generator = new HtmlGenerator();
break;
case PANGO:
generator = new PangoGenerator();
break;
case LATEX:
generator = new LaTeXGenerator();
break;
case TEX:
generator = new TeXGenerator();
break;
case RTF:
generator = new RtfGenerator();
break;
case BBCODE:
generator = new BBCodeGenerator();
break;
case SVG:
generator = new SVGGenerator();
break;
default:
break;
}
return generator;
}
CodeGenerator::CodeGenerator(ansifilter::OutputType type)
:in(NULL),
out(NULL),
tagIsOpen(false),
encoding("none"),
docTitle("Source file"),
fragmentOutput(false),
font("Courier New"),
fontSize("10pt"),
lineNumberWidth ( 5 ),
lineNumber ( 0 ),
showLineNumbers ( false ),
numberWrappedLines ( true ), //TODO add option
numberCurrentLine(false),
addAnchors(false),
applyDynStyles(false),
omitVersionInfo(false),
parseCP437(false),
parseAsciiBin(false),
parseAsciiTundra(false),
outputType(type),
ignoreFormatting(false),
readAfterEOF(false),
omitTrailingCR(false),
ignClearSeq(false),
ignCSISeq(false),
termBuffer(NULL),
curX(0),
curY(0),
memX(0),
memY(0),
maxY(0),
asciiArtWidth(80),
asciiArtHeight(150),
lineWrapLen(0)
{
elementStyle.setFgColour(rgb2html(workingPalette[0]));
}
CodeGenerator::~CodeGenerator()
{}
void CodeGenerator::setShowLineNumbers(bool flag)
{
showLineNumbers=flag;
}
void CodeGenerator::setFragmentCode(bool flag)
{
fragmentOutput=flag;
}
void CodeGenerator::setWrapNoNumbers(bool flag)
{
numberWrappedLines = flag;
}
void CodeGenerator::setParseCodePage437(bool flag){
parseCP437 = flag;
}
void CodeGenerator::setParseAsciiBin(bool flag){
parseAsciiBin = flag;
}
void CodeGenerator::setParseAsciiTundra(bool flag){
parseAsciiTundra = flag;
}
void CodeGenerator::setIgnoreClearSeq(bool flag) {
ignClearSeq = flag;
}
void CodeGenerator::setIgnoreCSISeq(bool flag) {
ignCSISeq = flag;
}
void CodeGenerator::setAsciiArtSize(int width, int height){
if (width>0) asciiArtWidth = width;
if (height>0) asciiArtHeight = height;
}
bool CodeGenerator::getFragmentCode()
{
return fragmentOutput;
}
void CodeGenerator::setFont(const string& s)
{
font = s;
}
void CodeGenerator::setFontSize(const string& s)
{
fontSize = s ;
}
void CodeGenerator::setTitle(const string & title)
{
if (!title.empty())
docTitle= title;
std::size_t found = docTitle.rfind("/");
if (found!=std::string::npos){
docTitle = docTitle.substr(found+1);
}
}
string CodeGenerator::getTitle()
{
return docTitle;
}
void CodeGenerator::setEncoding(const string& encodingName)
{
encoding = encodingName;
}
void CodeGenerator::setStyleSheet(const std::string& path)
{
styleSheetPath=path;
}
void CodeGenerator::setPreformatting ( WrapMode lineWrappingStyle,
unsigned int lineLength
)
{
lineWrapLen = lineLength;
}
void CodeGenerator::setApplyDynStyles(bool flag) {
applyDynStyles = flag;
}
void CodeGenerator::setSVGSize ( const string& w, const string& h )
{
width=w;
height=h;
}
ParseError CodeGenerator::generateFile (const string &inFileName,
const string &outFileName)
{
ParseError error=PARSE_OK;
in = (inFileName.empty()? &cin :new ifstream (inFileName.c_str() , std::ios::binary));
if (!in->fail() && error==PARSE_OK) {
out = (outFileName.empty()? &cout :new ofstream (outFileName.c_str()));
if ( out->fail()) {
error=BAD_OUTPUT;
}
}
if ( in->fail()) {
error=BAD_INPUT;
}
if (error==PARSE_OK) {
if (! fragmentOutput) {
*out << getHeader();
}
printBody();
if (! fragmentOutput) {
*out << getFooter();
}
}
if (!outFileName.empty()) {
delete out;
out=NULL;
}
if (!inFileName.empty()) {
delete in;
in=NULL;
}
return error;
}
string CodeGenerator::generateString(const string &input)
{
in = new istringstream (input);
out = new ostringstream ();
if ( in->fail() || out->fail()) {
return "";
}
if (! fragmentOutput) {
*out << getHeader();
}
printBody();
if (! fragmentOutput) {
*out << getFooter();
}
string result = static_cast(out)->str();
delete out;
out=NULL;
delete in;
in=NULL;
return result;
}
string CodeGenerator::generateStringFromFile(const string &inFileName)
{
in = new ifstream (inFileName.c_str() , std::ios::binary);
out = new ostringstream ();
if ( in->fail() || out->fail()) {
return "";
}
if (! fragmentOutput) {
*out << getHeader();
}
printBody();
if (! fragmentOutput) {
*out << getFooter();
}
string result = static_cast(out)->str();
delete out;
out=NULL;
delete in;
in=NULL;
return result;
}
ParseError CodeGenerator::generateFileFromString (const string &sourceStr,
const string &outFileName,
const string &title)
{
ParseError error=PARSE_OK;
in = new istringstream (sourceStr);
if (!in->fail()) {
out = (outFileName.empty()? &cout :new ofstream (outFileName.c_str()));
if ( out->fail()) {
error=BAD_OUTPUT;
}
}
if ( in->fail()) {
error=BAD_INPUT;
}
if (error==PARSE_OK) {
if (! fragmentOutput) {
*out << getHeader();
}
printBody();
if (! fragmentOutput) {
*out << getFooter();
}
}
if (!outFileName.empty()) {
delete out;
out=NULL;
}
delete in;
in=NULL;
return error;
}
bool CodeGenerator::printDynamicStyleFile ( const string &outPath )
{
return true;
}
/*
ESC[nL Inserts n blank lines at cursor line. (NANSI)
ESC[nM Deletes n lines including cursor line. (NANSI)
ESC[n@ Inserts n blank chars at cursor. (NANSI)
ESC[nP Deletes n chars including cursor char. (NANSI)
ESC[n;ny Output char translate (NANSI)
*/
bool CodeGenerator::parseSGRParameters(const string& line, size_t begin, size_t end)
{
if (line.empty() || begin==end) { // fix empty grep --color ending sequence
elementStyle.setReset(true);
return true;
}
int ansiCode=0;
int colorCode=0;
unsigned char colorValues[3]= {0};
string codes=line.substr(begin, end-begin);
vector codeVector = StringTools::splitString(codes, ';');
vector::iterator itVectorData = codeVector.begin();
while( itVectorData != codeVector.end()) {
StringTools::str2num(ansiCode, *(itVectorData), std::dec);
elementStyle.setReset(false);
switch (ansiCode) {
case 0:
elementStyle.setReset(true);
break;
case 1:
elementStyle.setBold(true);
elementStyle.setFgColour(rgb2html(workingPalette[8]));
break;
case 2: //Faint
break;
case 3:
elementStyle.setItalic(true);
break;
case 5: //Blink
case 6: //Blink fast
elementStyle.setBlink(true);
break;
case 7:
elementStyle.imageMode(true);
break;
case 8:
elementStyle.setConceal(true);
break;
case 4:// Underline Single
case 21: // Underline double
elementStyle.setUnderline(true);
break;
case 22:
elementStyle.setBold(false);
break;
case 24:
elementStyle.setUnderline(false);
break;
case 25:
elementStyle.setBlink(false);
break;
case 27:
elementStyle.imageMode(false);
break;
case 28:
elementStyle.setConceal(false);
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
if (elementStyle.isBold()){
elementStyle.setFgColour(rgb2html(workingPalette[ansiCode-30+8]));
} else
elementStyle.setFgColour(rgb2html(workingPalette[ansiCode-30]));
break;
case 38: // xterm 256 foreground color mode \033[38;5;
itVectorData++;
if (itVectorData == codeVector.end()) break;
if (*(itVectorData)=="5") {
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
xterm2rgb((unsigned char)colorCode, colorValues);
elementStyle.setFgColour(rgb2html(colorValues));
} else if (*(itVectorData)=="2") {
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[0] = colorCode & 0xff;
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[1] = colorCode & 0xff;
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[2] = colorCode & 0xff;
elementStyle.setFgColour(rgb2html(colorValues));
}
break;
case 39:
elementStyle.setReset(true);
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
elementStyle.setBgColour(rgb2html(workingPalette[ansiCode-40]));
break;
case 48: // xterm 256 background color mode \033[48;5;
itVectorData++;
if (itVectorData == codeVector.end()) break;
if(*(itVectorData)=="5") {
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
xterm2rgb((unsigned char)colorCode, colorValues);
elementStyle.setBgColour(rgb2html(colorValues));
} else if (*(itVectorData)=="2") {
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[0] = colorCode & 0xff;
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[1] = colorCode & 0xff;
itVectorData++;
if (itVectorData == codeVector.end()) break;
StringTools::str2num(colorCode, *(itVectorData), std::dec);
colorValues[2] = colorCode & 0xff;
elementStyle.setBgColour(rgb2html(colorValues));
}
break;
case 49:
elementStyle.setReset(true);
break;
/*aixterm codes*/
case 90:
case 91:
case 92:
case 93:
case 94:
case 95:
case 96:
case 97:
elementStyle.setFgColour(rgb2html(workingPalette[ansiCode-90+8]));
break;
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
elementStyle.setBgColour(rgb2html(workingPalette[ansiCode-100+8]));
break;
}
// Set RTF color index
// 8 default colours followed by bright colors see rtfgenerator.cpp
if (ansiCode>=30 and ansiCode <=37)
elementStyle.setFgColourID(ansiCode-30 + (elementStyle.isBold()? 8 : 0) );
else if (ansiCode>=90 and ansiCode <98)
elementStyle.setFgColourID(ansiCode-90+8);
else if (ansiCode>=40 and ansiCode <=47)
elementStyle.setBgColourID(ansiCode-40 /*+ elementStyle.isBold()? 8 : 0 */);
else if (ansiCode>=100 and ansiCode <108)
elementStyle.setBgColourID(ansiCode-100+8);
if (itVectorData != codeVector.end()) itVectorData++;
}
return true;
}
void CodeGenerator::parseCodePage437Seq(string line, size_t begin, size_t end){
string codes=line.substr(begin, end-begin);
vector codeVector = StringTools::splitString(codes, ',');
if (line[end]=='H'){
codeVector = StringTools::splitString(codes, ';');
curX = curY = 0;
if (codeVector.size()==1) {
curY = atoi(codeVector[0].c_str());
} else if (codeVector.size()==2){
curY = atoi(codeVector[0].c_str());
curX = atoi(codeVector[1].c_str());
}
if (maxYasciiArtWidth && curYc =0;
}
*/
}
if (line[end]=='K'){
// std::cerr<<"K!!!\n";
// for (int i=curX;ic =0;
}
if (line[end]=='s'){
memX = curX;
memY = curY;
memStyle = elementStyle;
}
if (line[end]=='u'){
curX = memX;
curY = memY;
elementStyle=memStyle;
}
}
void CodeGenerator::insertLineNumber ()
{
if ( showLineNumbers && !parseCP437) {
ostringstream lnum;
lnum << setw ( 5 ) << right;
if( numberCurrentLine ) {
*out << getCloseTag();
lnum << lineNumber;
*out <flush();
delete [] termBuffer;
}
void CodeGenerator::parseBinFile(){
char buffer [2] = {0};
int cur=0;
int next=0;
int count=0;
allocateTermBuffer();
while (in->read (buffer, 2)){
cur = buffer[0]&0xff;
next = buffer[1]&0xff;
int colBg = (next & 240) >> 4;
int colFg = (next & 15);
if (colBg > 8)
{
colBg -= 8;
}
elementStyle.setFgColour(rgb2html(workingPalette[colFg]));
elementStyle.setBgColour(rgb2html(workingPalette[colBg]));
//FIXME:
elementStyle.setBold(cur >= 0x20 && cur <= 0x7a);
if (curX>=0 && curX=0 && curYread(header, 11)){
asciiArtWidth = 0xff & ((header[ 6 ] << 8) + header[ 5 ]);
asciiArtHeight = 0xff & ((header[ 8 ] << 8) + header[ 7 ]);
int fontSize = header[ 9 ];
int flags = header[ 10 ];
/*
std::cerr<<"XBIN width:"<read(palette, 48)) {
int loop;
int index;
//override default palette
//TODO allow user to override this with a map?
for (loop = 0; loop < 16; loop++)
{
index = loop * 3;
workingPalette[loop][0] = palette[index] << 2 | palette[index] >> 4;
workingPalette[loop][1] = palette[index+1] << 2 | palette[index+1] >> 4;
workingPalette[loop][2] = palette[index+2] << 2 | palette[index+2] >> 4;
}
}
// skip font
if( (flags & 2) == 2 ) {
int numchars = ( flags & 0x10 ? 512 : 256 );
in->seekg ( fontSize * numchars, ios::cur);
}
// decode image
if( (flags & 4) == 4) {
int c=0;
while( in && curY < asciiArtHeight)
{
c = in->get();
int compression = c & 0xC0;
int cnt = ( c & 0x3F ) + 1;
int cur = -1;
int attr = -1;
while( cnt-- ) {
// none
if( compression == 0 ) {
cur = in->get();
attr = in->get();
}
// char
else if ( compression == 0x40 ) {
if( cur == -1 ) {
cur = in->get();
}
attr = in->get();
}
// attr
else if ( compression == 0x80 ) {
if( attr == -1 ) {
attr = in->get();
}
cur = in->get();
}
// both
else {
if( cur == -1 ) {
cur = in->get();
}
if( attr == -1 ) {
attr = in->get();
}
}
int colBg = (attr & 240) >> 4;
int colFg = (attr & 15);
if (colBg > 8)
{
colBg -= 8;
}
elementStyle.setFgColour(rgb2html(workingPalette[colFg]));
elementStyle.setBgColour(rgb2html(workingPalette[colBg]));
//FIXME:
elementStyle.setBold(cur >= 0x20 && cur <= 0x7a);
if (curX>=0 && curX=0 && curYread (buffer, 9) ) {
isTundra = string(buffer)=="\x18TUNDRA24";
}
if (!isTundra) {
std::cerr<<"not a Tundra file\n";
return;
}
asciiArtWidth = 80;
allocateTermBuffer();
int fg_red=0, fg_green=0, fg_blue=0;
int bg_red=0, bg_green=0, bg_blue=0;
while (in->read (buffer, 1)){
if (curX >= asciiArtWidth){
curX = 0;
curY ++;
}
int cur = buffer[0]&0xff;
if (cur==1) {
if (!in->read (buffer, 8)) goto GENTLE_EXIT;
curY = ((buffer[0] << 24)& 0xff) + ((buffer[1] << 16)& 0xff) + ((buffer[2] << 8)& 0xff) + (buffer[3]& 0xff);
curX = ((buffer[4] << 24)& 0xff) + ((buffer[5] << 16)& 0xff) + ((buffer[6] << 8)& 0xff) + (buffer[7]& 0xff);
}
if (cur == 2)
{
if (!in->read (buffer, 5) ) goto GENTLE_EXIT;
fg_red=buffer[2];
fg_green=buffer[3];
fg_blue=buffer[4];
cur= buffer[0];
}
if (cur == 4)
{
if (!in->read (buffer, 5) ) goto GENTLE_EXIT;
bg_red=buffer[2];
bg_green=buffer[3];
bg_blue=buffer[4];
cur= buffer[0];
}
if (cur==6)
{
if (!in->read (buffer, 10) ) goto GENTLE_EXIT;
fg_red=buffer[2];
fg_green=buffer[3];
fg_blue=buffer[4];
bg_red=buffer[6];
bg_green=buffer[7];
bg_blue=buffer[8];
cur = buffer[0];
}
if (cur !=1 && cur !=2 && cur !=4 && cur !=6)
{
elementStyle.setFgColour(rgb2html( fg_red&0xff, fg_green&0xff, fg_blue&0xff));
elementStyle.setBgColour(rgb2html( bg_red&0xff, bg_green&0xff, bg_blue&0xff ));
termBuffer[curX + curY*asciiArtWidth].style = elementStyle;
termBuffer[curX + curY*asciiArtWidth].c = cur &0xff;
curX++;
}
}
GENTLE_EXIT:
maxY = curYread (head, sizeof head -1) ) {
isXBIN = string(head)=="XBIN";
}
in->clear();
in->seekg (0, ios::beg);
return isXBIN;
}
bool CodeGenerator::streamIsTundra() {
if (in==&cin) return false;
bool isTND = false;
char head[10] = {0};
if (in->read (head, sizeof head -1) ) {
isTND = string(head)=="\x18TUNDRA24";
}
in->clear();
in->seekg (0, ios::beg);
return isTND;
}
////////////////////////////////////////////////////////////////////////////
void CodeGenerator::processInput()
{
int cur=0;
int next=0;
if (parseCP437 || parseAsciiBin || parseAsciiTundra){
elementStyle.setReset(false);
}
// deal with BIN/XBIN without file watching, reformatting and line numbering distractions
if (parseAsciiBin){
if (streamIsXBIN())
parseXBinFile();
else
parseBinFile();
printTermBuffer();
return;
}
if (parseAsciiTundra && streamIsTundra()){
parseTundraFile();
printTermBuffer();
return;
}
// handle normal text files
if (readAfterEOF && in!=&cin) {
in->seekg (0, ios::end);
// output the last few lines or the complete file if not too big
if (in->tellg()>51200) {
in->seekg (-512, ios::end);
// output complete lines, ignore cur line fragment
in->ignore(512, '\n');
} else {
in->seekg (0, ios::beg); // output complete file
}
}
if (streamIsXBIN()) {
*out<<"Please apply --art-bin option for XBIN files.\n";
return;
}
if (streamIsTundra()) {
*out<<"Please apply --art-tundra option for TND files.\n";
return;
}
string line;
size_t i=0;
size_t plainTxtCnt=0;
bool tagOpen=false;
bool isGrepOutput=false;
bool isKSeq=false;
bool omitNewLine=false;
lineNumber=0;
if (parseCP437){
allocateTermBuffer();
}
while (true) {
bool eof=false;
eof=!getline(*in, line);
if( !omitNewLine )
++lineNumber;
numberCurrentLine = true;
if (eof) {
// imitate tail bahaviour, continue to read after EOF
if (readAfterEOF) {
out->flush();
in->clear();
#ifdef WIN32
Sleep(250);
#else
sleep(1);
#endif
} else {
if (!parseCP437 && !omitTrailingCR)
printNewLine(outputType!=TEXT);
break;
}
} else {
if (!omitNewLine && !parseCP437 && lineNumber>1)
printNewLine();
if (!omitNewLine )
insertLineNumber();
omitNewLine = false;
i=0;
plainTxtCnt=0;
size_t seqEnd=string::npos;
while (i 2){
next = line[i+1]&0xff;
if (next==0x5b) {
i+=2;
seqEnd = i;
//find sequence end
while ( seqEnd0x7e )) {
++seqEnd;
}
if ( line[seqEnd]=='m' ) {
parseSGRParameters(line, i, seqEnd);
} else {
parseCodePage437Seq(line, i, seqEnd);
}
i=seqEnd+1;
}
else {
++i;
}
} else if (cur==0x1a && line.length() - i > 6){
// skip SAUCE info section
while (line[i]==0x1a || !line[i]) ++i;
if (line.substr(i, 5)=="SAUCE"){
break;
}
} else {
if (curX>=0 && curX=0 && curY 2 && (line[i+1]&0xff)==0x08) i++;
if ( cur==0x07) {
++lineNumber;
printNewLine();
insertLineNumber();
}
if ( cur==0x1b || (!ignCSISeq && ( cur==0x9b || cur==0xc2)) ) {
if (line.length() - i > 2){
next = line[i+1]&0xff;
//move index behind CSI
if ( (cur==0x1b && next==0x5b) || ( cur==0xc2 && next==0x9b) ) {
++i;
} else {
// restore a unicode sequence if the two digit CSI is not matched
// ansiweather -l Berlin,DE | ansifilter -T
if (cur==0xc2 || cur==0x1b) {
lineBuf << maskCharacter(cur);
++plainTxtCnt;
}
}
// http://linuxcommand.org/lc3_adv_tput.php
// http://ascii-table.com/ansi-escape-sequences-vt-100.php
if (next==0x28){ // ( -> maybe need to handle more codes here
if (line[i+2]==0x42) { // B
elementStyle.setReset(false);
i+=2;
}
}
// https://iterm2.com/documentation-escape-codes.html
if (next==0x5d) {
if (line[i+2]=='8') {
size_t uriBegin = line.find(';', i+4);
seqEnd = line.find("\x1b]8;;\x07", i);
size_t uriDelim = line.find(0x07, uriBegin+1);
if (uriBegin != string::npos && seqEnd != string::npos){
string uri = line.substr(uriBegin+1, uriDelim - uriBegin - 1 );
string txt = line.substr(uriDelim+1, seqEnd - uriDelim - 1);
lineBuf << getHyperlink(uri, txt);
i=seqEnd+4;
}
}
++i;
}
if (i0x7e )) {
++seqEnd;
}
if ( line[seqEnd]=='m' && !ignoreFormatting ) {
if (!elementStyle.isReset()) {
lineBuf << getCloseTag();
tagOpen=false;
}
parseSGRParameters(line, i, seqEnd);
if (!elementStyle.isReset()) {
lineBuf << getOpenTag();
tagOpen=true;
}
}
// fix K sequences (iterm2/grep)
isKSeq = line[seqEnd]=='K' && !ignClearSeq ;
isGrepOutput = isKSeq && isascii(line[seqEnd+1]) && line[seqEnd+1] !=13 && line[seqEnd+1] != 27;
if ( line[seqEnd]=='s' || line[seqEnd]=='u'
|| (isKSeq && !isGrepOutput) ){
i=line.length()+1;
omitNewLine = isKSeq; // \n may follow K
//FIXME std::cerr << "K CASE!\n";
}
else {
i = 1 + ((seqEnd!=line.length())?seqEnd:i);
}
} else {
cur= line[i-1]&0xff;
next = line[i]&0xff;
//ignore content of two and single byte sequences (no CSI)
if (cur==0x1b && ( next==0x50 || next==0x5d || next==0x58
|| next==0x5e||next==0x5f ) ) // DECSC seq
{
seqEnd=i;
//find string end
while ( seqEndflush();
}
void CodeGenerator::printNewLine(bool eof) {
string lineStr(lineBuf.str());
if (eof) {
lineStr = lineStr.substr(0, lineBuf.tellp());
}
*out << lineStr;
*out << newLineTag;
lineBuf.clear();
lineBuf.str(std::string());
}
/* the following functions are based on Wolfgang Frischs xterm256 converter utility:
http://frexx.de/xterm-256-notes/
*/
void CodeGenerator::xterm2rgb(unsigned char color, unsigned char* rgb)
{
// 16 basic colors
if(color<16) {
rgb[0] = workingPalette[color][0];
rgb[1] = workingPalette[color][1];
rgb[2] = workingPalette[color][2];
}
// color cube color
if(color>=16 && color<=232) {
color-=16;
rgb[0] = valuerange[(color/36)%6];
rgb[1] = valuerange[(color/6)%6];
rgb[2] = valuerange[color%6];
}
// gray tone
if(color>232) {
rgb[0]=rgb[1]=rgb[2] = 8+(color-232)*0x0a;
}
}
string CodeGenerator::rgb2html(unsigned char* rgb){
char colorString[10]= {0};
sprintf(colorString, "#%02x%02x%02x", rgb[0], rgb[1], rgb[2]);
return string(colorString);
}
string CodeGenerator::rgb2html(int r, int g, int b){
char colorString[10]= {0};
sprintf(colorString, "#%02x%02x%02x", r, g, b);
return string(colorString);
}
const unsigned char CodeGenerator::valuerange[] = { 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF };
unsigned char CodeGenerator::defaultPalette[16][3] = {
{ 0x00, 0x00, 0x00 }, // 0 ColorBlack
{ 0xCD, 0x00, 0x00 }, // 1 ColorRed
{ 0x00, 0xCD, 0x00 }, // 2 ColorGreen
{ 0xCD, 0xCD, 0x00 }, // 3 ColorYellow
{ 0x00, 0x00, 0xEE }, // 4 ColorBlue
{ 0xCD, 0x00, 0xCD }, // 5 ColorMagenta
{ 0x00, 0xCD, 0xCD }, // 6 ColorCyan
{ 0xE5, 0xE5, 0xE5 }, // 7 ColorGray
{ 0x7F, 0x7F, 0x7F }, // 8 ColorDarkGray
{ 0xFF, 0x00, 0x00 }, // 9 ColorBrightRed
{ 0x00, 0xFF, 0x00 }, // 10 ColorBrightGreen
{ 0xFF, 0xFF, 0x00 }, // 11 ColorBrightYellow
{ 0x5C, 0x5C, 0xFF }, // 12 ColorBrightBlue
{ 0xFF, 0x00, 0xFF }, // 13 ColorBrightMagenta
{ 0x00, 0xFF, 0xFF }, // 14 ColorBrightCyan
{ 0xFF, 0xFF, 0xFF } // 15 ColorBrightWhite
};
unsigned char CodeGenerator::workingPalette[16][3] = {
{ 0x00, 0x00, 0x00 }, // 0 ColorBlack
{ 0xCD, 0x00, 0x00 }, // 1 ColorRed
{ 0x00, 0xCD, 0x00 }, // 2 ColorGreen
{ 0xCD, 0xCD, 0x00 }, // 3 ColorYellow
{ 0x00, 0x00, 0xEE }, // 4 ColorBlue
{ 0xCD, 0x00, 0xCD }, // 5 ColorMagenta
{ 0x00, 0xCD, 0xCD }, // 6 ColorCyan
{ 0xE5, 0xE5, 0xE5 }, // 7 ColorGray
{ 0x7F, 0x7F, 0x7F }, // 8 ColorDarkGray
{ 0xFF, 0x00, 0x00 }, // 9 ColorBrightRed
{ 0x00, 0xFF, 0x00 }, // 10 ColorBrightGreen
{ 0xFF, 0xFF, 0x00 }, // 11 ColorBrightYellow
{ 0x5C, 0x5C, 0xFF }, // 12 ColorBrightBlue
{ 0xFF, 0x00, 0xFF }, // 13 ColorBrightMagenta
{ 0x00, 0xFF, 0xFF }, // 14 ColorBrightCyan
{ 0xFF, 0xFF, 0xFF } // 15 ColorBrightWhite
};
bool CodeGenerator::setColorMap(const string& mapPath){
//restore default colors
if (mapPath.length()==0){
memcpy(workingPalette, defaultPalette, sizeof defaultPalette);
return true;
}
ifstream mapFile ( mapPath.c_str() );
if ( mapFile ) {
string line;
unsigned int idx=0;
char sep='\0';
string colorCode;
while ( getline ( mapFile, line ) ) {
stringstream s(line);
s>>idx;
if (idx>15) return false;
s>>sep;
if (sep!='=') return false;
s>>colorCode;
if (colorCode.size()>=7 && colorCode[0]=='#' ) {
workingPalette[idx][0] = (char)std::strtol(colorCode.substr ( 1, 2 ).c_str(), NULL, 16);
workingPalette[idx][1] = (char)std::strtol(colorCode.substr ( 3, 2 ).c_str(), NULL, 16);
workingPalette[idx][2] = (char)std::strtol(colorCode.substr ( 5, 2 ).c_str(), NULL, 16);
} else {
return false;
}
}
mapFile.close();
} else {
return false;
}
return true;
}
}