001/* 002 * Copyright (C) 2009-2017 the original author(s). 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.fusesource.jansi; 017 018import java.io.IOException; 019import java.io.OutputStream; 020import java.util.ArrayList; 021import java.util.List; 022 023/** 024 * @author <a href="http://code.dblock.org">Daniel Doubrovkine</a> 025 */ 026public class HtmlAnsiOutputStream extends AnsiOutputStream { 027 028 private boolean concealOn = false; 029 030 @Override 031 public void close() throws IOException { 032 closeAttributes(); 033 super.close(); 034 } 035 036 private static final String[] ANSI_COLOR_MAP = {"black", "red", 037 "green", "yellow", "blue", "magenta", "cyan", "white",}; 038 039 private static final byte[] BYTES_QUOT = """.getBytes(); 040 private static final byte[] BYTES_AMP = "&".getBytes(); 041 private static final byte[] BYTES_LT = "<".getBytes(); 042 private static final byte[] BYTES_GT = ">".getBytes(); 043 044 public HtmlAnsiOutputStream(OutputStream os) { 045 super(os); 046 } 047 048 private final List<String> closingAttributes = new ArrayList<String>(); 049 050 private void write(String s) throws IOException { 051 super.out.write(s.getBytes()); 052 } 053 054 private void writeAttribute(String s) throws IOException { 055 write("<" + s + ">"); 056 closingAttributes.add(0, s.split(" ", 2)[0]); 057 } 058 059 private void closeAttributes() throws IOException { 060 for (String attr : closingAttributes) { 061 write("</" + attr + ">"); 062 } 063 closingAttributes.clear(); 064 } 065 066 public void write(int data) throws IOException { 067 switch (data) { 068 case 34: // " 069 out.write(BYTES_QUOT); 070 break; 071 case 38: // & 072 out.write(BYTES_AMP); 073 break; 074 case 60: // < 075 out.write(BYTES_LT); 076 break; 077 case 62: // > 078 out.write(BYTES_GT); 079 break; 080 default: 081 super.write(data); 082 } 083 } 084 085 public void writeLine(byte[] buf, int offset, int len) throws IOException { 086 write(buf, offset, len); 087 closeAttributes(); 088 } 089 090 @Override 091 protected void processSetAttribute(int attribute) throws IOException { 092 switch (attribute) { 093 case ATTRIBUTE_CONCEAL_ON: 094 write("\u001B[8m"); 095 concealOn = true; 096 break; 097 case ATTRIBUTE_INTENSITY_BOLD: 098 writeAttribute("b"); 099 break; 100 case ATTRIBUTE_INTENSITY_NORMAL: 101 closeAttributes(); 102 break; 103 case ATTRIBUTE_UNDERLINE: 104 writeAttribute("u"); 105 break; 106 case ATTRIBUTE_UNDERLINE_OFF: 107 closeAttributes(); 108 break; 109 case ATTRIBUTE_NEGATIVE_ON: 110 break; 111 case ATTRIBUTE_NEGATIVE_OFF: 112 break; 113 default: 114 break; 115 } 116 } 117 118 @Override 119 protected void processAttributeRest() throws IOException { 120 if (concealOn) { 121 write("\u001B[0m"); 122 concealOn = false; 123 } 124 closeAttributes(); 125 } 126 127 @Override 128 protected void processSetForegroundColor(int color, boolean bright) throws IOException { 129 writeAttribute("span style=\"color: " + ANSI_COLOR_MAP[color] + ";\""); 130 } 131 132 @Override 133 protected void processSetBackgroundColor(int color, boolean bright) throws IOException { 134 writeAttribute("span style=\"background-color: " + ANSI_COLOR_MAP[color] + ";\""); 135 } 136}