package net.ME1312.SubServers.Console; import org.fusesource.jansi.AnsiOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class AnsiHTMLColorStream extends AnsiOutputStream { private static final String[] ANSI_COLOR_MAP = new String[]{"000000", "cd0000", "25bc24", "e1e100", "0000ee", "cd00cd", "00e1e1", "ffffff"}; private static final byte[] BYTES_NBSP = " ".getBytes(); private static final byte[] BYTES_QUOT = """.getBytes(); private static final byte[] BYTES_AMP = "&".getBytes(); private static final byte[] BYTES_LT = "<".getBytes(); private static final byte[] BYTES_GT = ">".getBytes(); private LinkedList closingAttributes = new LinkedList(); private boolean underline = false; private boolean strikethrough = false; public void close() throws IOException { this.closeAttributes(); super.close(); } public AnsiHTMLColorStream(OutputStream os) { super(os); } private void write(String s) throws IOException { super.out.write(s.getBytes()); } private void writeAttribute(String s) throws IOException { this.write("<" + s + ">"); this.closingAttributes.add(0, s); } private void closeAttribute(String s) throws IOException { LinkedList closedAttributes = new LinkedList(); LinkedList closingAttributes = new LinkedList(); LinkedList unclosedAttributes = new LinkedList(); closingAttributes.addAll(this.closingAttributes); for (String attr : closingAttributes) { if (attr.toLowerCase().startsWith(s.toLowerCase())) { for (String a : unclosedAttributes) { closedAttributes.add(0, a); this.write(""); } this.closingAttributes.removeFirstOccurrence(attr); unclosedAttributes.clear(); this.write(""); } else { unclosedAttributes.add(attr); } } for (String attr : closedAttributes) { this.write("<" + attr + ">"); } } private void closeAttributes() throws IOException { for (String attr : closingAttributes) { this.write(""); } this.underline = false; this.strikethrough = false; this.closingAttributes.clear(); } private boolean nbsp = true; @Override public void write(int data) throws IOException { if (data == 32) { if (nbsp) this.out.write(BYTES_NBSP); else super.write(data); nbsp = !nbsp; } else { nbsp = false; switch(data) { case 34: this.out.write(BYTES_QUOT); break; case 38: this.out.write(BYTES_AMP); break; case 60: this.out.write(BYTES_LT); break; case 62: this.out.write(BYTES_GT); break; default: super.write(data); } } } public void writeLine(byte[] buf, int offset, int len) throws IOException { this.write(buf, offset, len); this.closeAttributes(); } private String parseTextDecoration() { String dec = ""; if (underline) dec += " underline"; if (strikethrough) dec += " line-through"; if (dec.length() <= 0) dec += " none"; return dec.substring(1); } @Override protected void processSetAttribute(int attribute) throws IOException { switch(attribute) { case 1: this.writeAttribute("b"); break; case 3: this.writeAttribute("i"); break; case 4: this.closeAttribute("span class=\"ansi-decoration"); this.underline = true; this.writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\""); break; case 9: this.closeAttribute("span class=\"ansi-decoration"); this.strikethrough = true; this.writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\""); break; case 22: this.closeAttribute("b"); break; case 23: this.closeAttribute("i"); break; case 24: this.closeAttribute("span class=\"ansi-decoration"); this.underline = false; this.writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\""); break; case 29: this.closeAttribute("span class=\"ansi-decoration"); this.strikethrough = false; this.writeAttribute("span class=\"ansi-decoration\" style=\"text-decoration: " + parseTextDecoration() + ";\""); break; default: break; } } @Override protected void processAttributeRest() throws IOException { this.closeAttributes(); } @Override protected void processSetForegroundColor(int color) throws IOException { this.writeAttribute("span class=\"ansi-foreground\" style=\"color: #" + ANSI_COLOR_MAP[color] + ";\""); } @Override protected void processSetBackgroundColor(int color) throws IOException { this.writeAttribute("span class=\"ansi-background\" style=\"background-color: #" + ANSI_COLOR_MAP[color] + ";\""); } }