/*
This file is part of leafdigital leafChat.
leafChat 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.
leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>.
Copyright 2011 Samuel Marshall.
*/
package com.leafdigital.irc;
import java.util.LinkedList;
import java.util.regex.*;
/** Fixes IRC colours. */
class ColourFixer
{
private boolean bold,underline;
private int background = 0, foreground = 1;
private StringBuffer out = new StringBuffer();
private LinkedList<String> tags = null;
private static final Pattern COLOURS=Pattern.compile(
"^([0-9][0-9]?)(,([0-9][0-9]?))?.*$");
/** @return Resulting text */
String get()
{
return out.toString();
}
private final static Pattern CONTROLCHAR_REGEX = Pattern.compile(
"<controlchar num='([0-9]+)'/>");
/**
* @param s Input string
* @param allowStyles True if styles are allowed
* @param allowColours True if colours are allowed
*/
ColourFixer(String s, boolean allowStyles, boolean allowColours)
{
// Turn XML control characters back into real control characters
Matcher m = CONTROLCHAR_REGEX.matcher(s);
StringBuffer controls = new StringBuffer();
while(m.find())
{
String replace = "" + (char)Integer.parseInt(m.group(1));
m.appendReplacement(controls, replace);
}
m.appendTail(controls);
s = controls.toString();
for(int i=0;i<s.length();i++)
{
char c=s.charAt(i);
switch(c)
{
case 2: // Bold (toggle)
if(allowStyles)
{
if(!bold)
{
add("irc-b");
bold=true;
}
else
{
remove("irc-b");
bold=false;
}
}
break;
case 15: // Normal
if(allowStyles)
{
bold=false;
underline=false;
background=0;
foreground=1;
removeAll();
}
break;
case 18: // Reverse (toggle)
if(allowStyles)
{
setColour(background,foreground);
}
break;
case 31: // Underline (toggle)
if(allowStyles)
{
if(!underline)
{
add("irc-u");
underline=true;
}
else
{
remove("irc-u");
underline=false;
}
}
break;
case 3: // Colour
// Parse colour...
m = COLOURS.matcher(s.substring(i+1));
if(m.matches())
{
int
fg=Integer.parseInt(m.group(1) ),
bg=m.group(3)==null ? background : Integer.parseInt(m.group(3));
if(fg>15 || bg>15) break;
if(allowColours) setColour(fg,bg);
i += m.group(1).length() + (m.group(2)!=null ? m.group(2).length() : 0);
}
else
{
// Switches colour off
setColour(1, 0);
}
break;
case '<':
removeAll();
out.append('<');
break;
default:
// Throw away all other control characters
if(c>=32)
{
out.append(c);
}
break;
}
}
removeAll();
}
private void setColour(int fg, int bg)
{
if(bg != background)
{
if(background != 0)
{
remove("irc-bg" + background);
}
background = bg;
if(background != 0)
{
add("irc-bg" + background);
}
}
if(fg != foreground)
{
if(foreground != 1)
{
remove("irc-fg" + foreground);
}
foreground = fg;
if(foreground != 1)
{
add("irc-fg" + foreground);
}
}
}
private void add(String tag)
{
// Only create list if needed
if(tags==null)
{
tags = new LinkedList<String>();
}
out.append("<" + tag + ">");
tags.addLast(tag);
}
private void remove(String tag)
{
if(tags==null || tags.isEmpty())
{
return;
}
String last = tags.removeLast();
out.append("</" + last + ">");
if(last.equals(tag))
{
return;
}
remove(tag); // Recurse
tags.addLast(last);
out.append("<" + last + ">");
}
private void removeAll()
{
if(tags==null)
{
return;
}
while(!tags.isEmpty())
{
out.append("</" + tags.removeLast() + ">");
}
}
}