/* * Copyright (c) 2009-2011 Graham Edgecombe. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package com.athena.asm.util.vt100; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.graphics.Color; import android.text.SpannableString; import android.text.Spanned; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; import android.text.style.UnderlineSpan; import android.widget.TextView; import com.athena.asm.aSMApplication; /** * A VT100/ANSI-compatible terminal model. * @author Graham Edgecombe */ public class Vt100TerminalModel { public static final int CMD_BACKGROUND_COLOR = 1; public static final int CMD_FOREGROUND_COLOR = 2; public static final int CMD_UNDERLINE = 3; // public static final int CMD_STRIKEOUT = 4; public static final int CMD_INVERSE = 5; private static String Str_Control = "" + (char)(27) + "["; public List<Map<String, Integer>> liCommand = new ArrayList<Map<String, Integer>>(4); public boolean bSetCommand = true; /** * A {@link AnsiControlSequenceListener} which modifies the * {@link TerminalModel} appropriately when an event happens. * @author Graham Edgecombe */ private class Vt100Listener implements AnsiControlSequenceListener { @Override public void parsedControlSequence(AnsiControlSequence seq) { char command = seq.getCommand(); String[] parameters = seq.getParameters(); switch (command) { case 'm': if (parameters.length == 0) { parameters = new String[] { "0" }; } for (String parameter : parameters) { if (parameter.equals("0")) { // reset color configuration to default foregroundColor = DEFAULT_FOREGROUND_COLOR; backgroundColor = DEFAULT_BACKGROUND_COLOR; backgroundBold = DEFAULT_BACKGROUND_BOLD; foregroundBold = DEFAULT_FOREGROUND_BOLD; underlineFlag = DEFAULT_UNDERLINE_FLAG; inverseFlag = DEFAULT_INVERSE_FLAG; // strikeoutFlag = DEFAULT_STRIKEOUT_FLAG; } else if (parameter.equals("1") || parameter.equals("2")) { backgroundBold = true; foregroundBold = true; } else if (parameter.equals("4")) { underlineFlag = true; } else if (parameter.equals("7")) { inverseFlag = true; } /*else if (parameter.equals("9")) { strikeoutFlag = true; } */else if (parameter.equals("22")) { backgroundBold = false; foregroundBold = false; } else if ((parameter.startsWith("3") || parameter.startsWith("4")) && parameter.length() == 2) { int color = Integer.parseInt(parameter.substring(1)); if (parameter.startsWith("3")) { foregroundColor = color; } else if (parameter.startsWith("4")) { backgroundColor = color; } } } break; case '#': // custom foreground color control if (1 != parameters.length) { break; } String param = parameters[0]; foregroundColor = Color.rgb( Integer.valueOf(param.substring(0, 3)), Integer.valueOf(param.substring(3, 6)), Integer.valueOf(param.substring(6, 9))); break; } } @Override public String parsedString(String str, int nStart, List<Map<String, Integer>> liCommand, boolean bSetCommand) { StringBuilder sb = new StringBuilder(""); for (char ch : str.toCharArray()) { switch (ch) { case 127: continue; case 7: continue; } sb.append((char)ch); } String strText = sb.toString(); int nLen = strText.length(); if(0 == nLen) { return strText; } if(!bSetCommand) { return strText; } int back = backgroundBold ? SgrColor.BACKGROUND_COLOR_BRIGHT[backgroundColor] : SgrColor.COLOR_NORMAL[backgroundColor]; int fore = 10 > Math.abs(foregroundColor) ? (foregroundBold ? SgrColor.COLOR_BRIGHT[foregroundColor] : SgrColor.COLOR_NORMAL[foregroundColor]) : foregroundColor; if(backgroundColor == foregroundColor && foregroundBold) { back = SgrColor.COLOR_NORMAL[backgroundColor]; } int start = nStart - nLen + 1; if(0 > start) { start = 0; } int end = nStart + 1; if(backgroundBold || backgroundColor != DEFAULT_BACKGROUND_COLOR) { Map<String, Integer> mapCmd = new HashMap<String, Integer>(4); mapCmd.put("c", CMD_BACKGROUND_COLOR); mapCmd.put("s", start); mapCmd.put("e", end); mapCmd.put("v", back); liCommand.add(mapCmd); } if(foregroundBold || foregroundColor != DEFAULT_FOREGROUND_COLOR) { Map<String, Integer> mapCmd = new HashMap<String, Integer>(4); mapCmd.put("c", CMD_FOREGROUND_COLOR); mapCmd.put("s", start); mapCmd.put("e", end); mapCmd.put("v", fore); liCommand.add(mapCmd); } if(underlineFlag) { Map<String, Integer> mapCmd = new HashMap<String, Integer>(3); mapCmd.put("c", CMD_UNDERLINE); mapCmd.put("s", start); mapCmd.put("e", end); liCommand.add(mapCmd); } if(inverseFlag) { Map<String, Integer> mapCmd = new HashMap<String, Integer>(5); mapCmd.put("c", CMD_INVERSE); mapCmd.put("s", start); mapCmd.put("e", end); mapCmd.put("v1", back); mapCmd.put("v2", fore); liCommand.add(mapCmd); } /*if(strikeoutFlag) { Map<String, Integer> mapCmd = new HashMap<String, Integer>(3); mapCmd.put("c", CMD_STRIKEOUT); mapCmd.put("s", start); mapCmd.put("e", end); liCommand.add(mapCmd); }*/ return strText; } } /** * The default foreground bold flag. */ private static final boolean DEFAULT_FOREGROUND_BOLD = false; /** * The default background bold flag. */ private static final boolean DEFAULT_BACKGROUND_BOLD = false; /** * The default underline flag. */ private static final boolean DEFAULT_UNDERLINE_FLAG = false; /** * The default inverse flag. */ private static final boolean DEFAULT_INVERSE_FLAG = false; /** * The default strikeout flag. */ // private static final boolean DEFAULT_STRIKEOUT_FLAG = false; /** * The default foreground color. */ private static final int DEFAULT_FOREGROUND_COLOR = 7; /** * The default background color. */ private static final int DEFAULT_BACKGROUND_COLOR = 0; /** * The ANSI control sequence listener. */ private final AnsiControlSequenceListener listener = this.new Vt100Listener(); /** * The ANSI control sequence parser. */ private final AnsiControlSequenceParser parser = new AnsiControlSequenceParser(listener); /** * The current foreground bold flag. */ private boolean foregroundBold = DEFAULT_FOREGROUND_BOLD; /** * The current background bold flag. */ private boolean backgroundBold = DEFAULT_BACKGROUND_BOLD; /** * The current foreground color. */ private int foregroundColor = DEFAULT_FOREGROUND_COLOR; /** * The current background color. */ private int backgroundColor = DEFAULT_BACKGROUND_COLOR; /** * The current underline flag. */ private boolean underlineFlag = DEFAULT_UNDERLINE_FLAG; /** * The current inverse flag. */ private boolean inverseFlag = DEFAULT_INVERSE_FLAG; /** * The current strikeout flag. */ // private boolean strikeoutFlag = DEFAULT_STRIKEOUT_FLAG; /** * Creates the terminal model with the default number of columns and rows, * and the default buffer size. */ public Vt100TerminalModel() { if (aSMApplication.getCurrentApplication().isNightTheme()) { SgrColor.COLOR_NORMAL = SgrColor.COLOR_NORMAL_NIGHT; SgrColor.COLOR_BRIGHT = SgrColor.COLOR_BRIGHT_NIGHT; SgrColor.BACKGROUND_COLOR_BRIGHT = SgrColor.BACKGROUND_COLOR_BRIGHT_NIGHT; } else { SgrColor.COLOR_NORMAL = SgrColor.COLOR_NORMAL_DAY; SgrColor.COLOR_BRIGHT = SgrColor.COLOR_BRIGHT_DAY; SgrColor.BACKGROUND_COLOR_BRIGHT = SgrColor.BACKGROUND_COLOR_BRIGHT_DAY; } } public String print(String str) { if (str == null) { return null; } return parser.parse(str, liCommand, bSetCommand); } private static void handleCommands(TextView textView, String source, List<Map<String, Integer>> liCommand) { SpannableString strSpan = new SpannableString(source); for(Map<String, Integer> mapCmd : liCommand) { int cmd = mapCmd.get("c"); int start = mapCmd.get("s"); int end = mapCmd.get("e"); if(CMD_BACKGROUND_COLOR == cmd) { strSpan.setSpan(new BackgroundColorSpan(mapCmd.get("v")), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if(CMD_FOREGROUND_COLOR == cmd) { strSpan.setSpan(new ForegroundColorSpan(mapCmd.get("v")), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if(CMD_UNDERLINE == cmd) { strSpan.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if(CMD_INVERSE == cmd) { strSpan.setSpan(new ForegroundColorSpan(mapCmd.get("v1")), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); strSpan.setSpan(new BackgroundColorSpan(mapCmd.get("v2")), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } /*else if(CMD_STRIKEOUT == cmd) { strSpan.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } */ } textView.setText(strSpan); } public static void handleContent(String strRawContentOri, TextView textView) { if(null == strRawContentOri) { textView.setText(""); return; } // Log.d("tag", "11111111"); boolean bHasControl = true; Vt100TerminalModel vt100 = new Vt100TerminalModel(); String strRawContentNew = strRawContentOri.replace("\\r[", Str_Control); if(strRawContentOri.length() == strRawContentNew.length()) { bHasControl = false; } String strRawContent = strRawContentNew.replace("\\r", "\r"); // Log.d("tag", "22222222222"); strRawContent = vt100.print(strRawContent); // Log.d("tag", "333333333"); if(bHasControl) { handleCommands(textView, strRawContent, vt100.liCommand); // Log.d("tag", "44444444444"); } else { textView.setText(strRawContent); } } public int getDefaultBackgroundColor() { final int bg = DEFAULT_BACKGROUND_COLOR; return DEFAULT_BACKGROUND_BOLD ? SgrColor.COLOR_BRIGHT[bg] : SgrColor.COLOR_NORMAL[bg]; } public int getDefaultForegroundColor() { final int fg = DEFAULT_FOREGROUND_COLOR; return DEFAULT_FOREGROUND_BOLD ? SgrColor.COLOR_BRIGHT[fg] : SgrColor.COLOR_NORMAL[fg]; } }