import java.awt.Color;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class JMXPSingleClass extends NAME IT
{
// singletone routines
private static MXPColors allcolors;
public static int Bold = 0x01;
public static int Italic = 0x02;
public static int Underline = 0x04;
public static int Strikeout = 0x08;
//----------------------------------------------------------------------------------------------------
// enums
//align type for internal windows and images (type Middle is only valid for images)
enum alignType {
nop,
Left,
Right,
Bottom,
Top,
Middle
};
enum mxpMode { openMode, secureMode, lockedMode};
enum parserState {
pText,
pAnsiSeq,
pTag,
pComment,
pQuotedParam
};
enum chunkType {
chunkNone,
chunkText,
chunkTag,
chunkError
};
enum tagParserState {
tagBegin,
tagName,
tagParam,
tagParamValue,
tagQuotedParam,
tagAfterQuotedParam,
tagBetweenParams
};
enum paramParserState {
parNone,
parName,
parValue,
parQuotedValue
};
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
private class windowStruct
{
public String name, title;
public int left, top, width, height;
public boolean scrolling, floating;
}
//----------------------------------------------------------------------------------------------------
private class internalWindowStruct
{
public String name, title;
public alignType align;
public boolean scrolling;
}
//----------------------------------------------------------------------------------------------------
private class relocateStruct
{
public String server;
public int port;
}
//----------------------------------------------------------------------------------------------------
private class imageStruct
{
public String fname, url, type;
public int height, width, hspace, vspace;
public alignType align;
}
//----------------------------------------------------------------------------------------------------
private class moveStruct
{
public int x, y;
}
//----------------------------------------------------------------------------------------------------
private class soundStruct
{
public boolean isSOUND; //1 if SOUND, 0 if MUSIC
public String fname, url; //(fName and U params)
public int vol; //volume (V param)
public int repeats; //-1 for infinite (L param)
public int priority; //0-100; SOUND only (P param)
public boolean continuemusic; //continue without restarting if rerequested? MUSIC only (C param)
public String type; //sound/music type (T param)
}
//----------------------------------------------------------------------------------------------------
private class statStruct
{
public String variable, maxvariable, caption;
}
//----------------------------------------------------------------------------------------------------
private class gaugeStruct
{
public String variable, maxvariable, caption;
public Color color;
}
//----------------------------------------------------------------------------------------------------
private class SendStruct {
public String name, command, text, hint;
public boolean toprompt, ismenu;
}
//----------------------------------------------------------------------------------------------------
private class linkStruct
{
public String name, url, text, hint;
}
//----------------------------------------------------------------------------------------------------
private class formatStruct
{
public static final int USE_BOLD=0x01;
public static final int USE_ITALICS=0x02;
public static final int USE_UNDERLINE=0x04;
public static final int USE_STRIKEOUT=0x08;
public static final int USE_FG=0x10;
public static final int USE_BG=0x20;
public static final int USE_FONT=0x40;
public static final int USE_SIZE=0x80;
public static final int USE_ALL=0xFF;
public int usemask; //8-bit; which params should be applied
public int attributes;
public Color fg, bg;
public String font; //if NULL and it should be applied => default font should be set
public int size;
}
//----------------------------------------------------------------------------------------------------
private class flagStruct
{
public boolean begin;
public String name;
}
//----------------------------------------------------------------------------------------------------
private class varStruct
{
public String name, value;
public boolean erase;
};
//----------------------------------------------------------------------------------------------------
private class MXPColors
{
private final Color nocolor = new Color(0,0,0,0);
private String COLOR_NAMES [] = {
"snow",
"ghostwhite",
"whitesmoke",
"gainsboro",
"floralwhite",
"oldlace",
"linen",
"antiquewhite",
"papayawhip",
"blanchedalmond",
"bisque",
"peachpuff",
"navajowhite",
"moccasin",
"cornsilk",
"ivory",
"lemonchiffon",
"seashell",
"honeydew",
"mintcream",
"azure",
"aliceblue",
"lavender",
"lavenderblush",
"mistyrose",
"white",
"black",
"darkslategray",
"darkslategrey",
"dimgray",
"dimgrey",
"slategray",
"slategrey",
"lightslategray",
"lightslategrey",
"gray",
"grey",
"lightgrey",
"lightgray",
"midnightblue",
"navy",
"navyblue",
"cornflowerblue",
"darkslateblue",
"slateblue",
"mediumslateblue",
"lightslateblue",
"mediumblue",
"royalblue",
"blue",
"dodgerblue",
"deepskyblue",
"skyblue",
"lightskyblue",
"steelblue",
"lightsteelblue",
"lightblue",
"powderblue",
"paleturquoise",
"darkturquoise",
"mediumturquoise",
"turquoise",
"cyan",
"lightcyan",
"cadetblue",
"mediumaquamarine",
"aquamarine",
"darkgreen",
"darkolivegreen",
"darkseagreen",
"seagreen",
"mediumseagreen",
"lightseagreen",
"palegreen",
"springgreen",
"lawngreen",
"green",
"chartreuse",
"mediumspringgreen",
"greenyellow",
"limegreen",
"yellowgreen",
"forestgreen",
"olivedrab",
"darkkhaki",
"khaki",
"palegoldenrod",
"lightgoldenrodyellow",
"lightyellow",
"yellow",
"gold",
"lightgoldenrod",
"goldenrod",
"darkgoldenrod",
"rosybrown",
"indianred",
"saddlebrown",
"sienna",
"peru",
"burlywood",
"beige",
"wheat",
"sandybrown",
"tan",
"chocolate",
"firebrick",
"brown",
"darksalmon",
"salmon",
"lightsalmon",
"orange",
"darkorange",
"coral",
"lightcoral",
"tomato",
"orangered",
"red",
"hotpink",
"deeppink",
"pink",
"lightpink",
"palevioletred",
"maroon",
"mediumvioletred",
"violetred",
"magenta",
"violet",
"plum",
"orchid",
"mediumorchid",
"darkorchid",
"darkviolet",
"blueviolet",
"purple",
"mediumpurple",
"thistle",
"snow1",
"snow2",
"snow3",
"snow4",
"seashell1",
"seashell2",
"seashell3",
"seashell4",
"antiquewhite1",
"antiquewhite2",
"antiquewhite3",
"antiquewhite4",
"bisque1",
"bisque2",
"bisque3",
"bisque4",
"peachpuff1",
"peachpuff2",
"peachpuff3",
"peachpuff4",
"navajowhite1",
"navajowhite2",
"navajowhite3",
"navajowhite4",
"lemonchiffon1",
"lemonchiffon2",
"lemonchiffon3",
"lemonchiffon4",
"cornsilk1",
"cornsilk2",
"cornsilk3",
"cornsilk4",
"ivory1",
"ivory2",
"ivory3",
"ivory4",
"honeydew1",
"honeydew2",
"honeydew3",
"honeydew4",
"lavenderblush1",
"lavenderblush2",
"lavenderblush3",
"lavenderblush4",
"mistyrose1",
"mistyrose2",
"mistyrose3",
"mistyrose4",
"azure1",
"azure2",
"azure3",
"azure4",
"slateblue1",
"slateblue2",
"slateblue3",
"slateblue4",
"royalblue1",
"royalblue2",
"royalblue3",
"royalblue4",
"blue1",
"blue2",
"blue3",
"blue4",
"dodgerblue1",
"dodgerblue2",
"dodgerblue3",
"dodgerblue4",
"steelblue1",
"steelblue2",
"steelblue3",
"steelblue4",
"deepskyblue1",
"deepskyblue2",
"deepskyblue3",
"deepskyblue4",
"skyblue1",
"skyblue2",
"skyblue3",
"skyblue4",
"lightskyblue1",
"lightskyblue2",
"lightskyblue3",
"lightskyblue4",
"slategray1",
"slategray2",
"slategray3",
"slategray4",
"lightsteelblue1",
"lightsteelblue2",
"lightsteelblue3",
"lightsteelblue4",
"lightblue1",
"lightblue2",
"lightblue3",
"lightblue4",
"lightcyan1",
"lightcyan2",
"lightcyan3",
"lightcyan4",
"paleturquoise1",
"paleturquoise2",
"paleturquoise3",
"paleturquoise4",
"cadetblue1",
"cadetblue2",
"cadetblue3",
"cadetblue4",
"turquoise1",
"turquoise2",
"turquoise3",
"turquoise4",
"cyan1",
"cyan2",
"cyan3",
"cyan4",
"darkslategray1",
"darkslategray2",
"darkslategray3",
"darkslategray4",
"aquamarine1",
"aquamarine2",
"aquamarine3",
"aquamarine4",
"darkseagreen1",
"darkseagreen2",
"darkseagreen3",
"darkseagreen4",
"seagreen1",
"seagreen2",
"seagreen3",
"seagreen4",
"palegreen1",
"palegreen2",
"palegreen3",
"palegreen4",
"springgreen1",
"springgreen2",
"springgreen3",
"springgreen4",
"green1",
"green2",
"green3",
"green4",
"chartreuse1",
"chartreuse2",
"chartreuse3",
"chartreuse4",
"olivedrab1",
"olivedrab2",
"olivedrab3",
"olivedrab4",
"darkolivegreen1",
"darkolivegreen2",
"darkolivegreen3",
"darkolivegreen4",
"khaki1",
"khaki2",
"khaki3",
"khaki4",
"lightgoldenrod1",
"lightgoldenrod2",
"lightgoldenrod3",
"lightgoldenrod4",
"lightyellow1",
"lightyellow2",
"lightyellow3",
"lightyellow4",
"yellow1",
"yellow2",
"yellow3",
"yellow4",
"gold1",
"gold2",
"gold3",
"gold4",
"goldenrod1",
"goldenrod2",
"goldenrod3",
"goldenrod4",
"darkgoldenrod1",
"darkgoldenrod2",
"darkgoldenrod3",
"darkgoldenrod4",
"rosybrown1",
"rosybrown2",
"rosybrown3",
"rosybrown4",
"indianred1",
"indianred2",
"indianred3",
"indianred4",
"sienna1",
"sienna2",
"sienna3",
"sienna4",
"burlywood1",
"burlywood2",
"burlywood3",
"burlywood4",
"wheat1",
"wheat2",
"wheat3",
"wheat4",
"tan1",
"tan2",
"tan3",
"tan4",
"chocolate1",
"chocolate2",
"chocolate3",
"chocolate4",
"firebrick1",
"firebrick2",
"firebrick3",
"firebrick4",
"brown1",
"brown2",
"brown3",
"brown4",
"salmon1",
"salmon2",
"salmon3",
"salmon4",
"lightsalmon1",
"lightsalmon2",
"lightsalmon3",
"lightsalmon4",
"orange1",
"orange2",
"orange3",
"orange4",
"darkorange1",
"darkorange2",
"darkorange3",
"darkorange4",
"coral1",
"coral2",
"coral3",
"coral4",
"tomato1",
"tomato2",
"tomato3",
"tomato4",
"orangered1",
"orangered2",
"orangered3",
"orangered4",
"red1",
"red2",
"red3",
"red4",
"deeppink1",
"deeppink2",
"deeppink3",
"deeppink4",
"hotpink1",
"hotpink2",
"hotpink3",
"hotpink4",
"pink1",
"pink2",
"pink3",
"pink4",
"lightpink1",
"lightpink2",
"lightpink3",
"lightpink4",
"palevioletred1",
"palevioletred2",
"palevioletred3",
"palevioletred4",
"maroon1",
"maroon2",
"maroon3",
"maroon4",
"violetred1",
"violetred2",
"violetred3",
"violetred4",
"magenta1",
"magenta2",
"magenta3",
"magenta4",
"orchid1",
"orchid2",
"orchid3",
"orchid4",
"plum1",
"plum2",
"plum3",
"plum4",
"mediumorchid1",
"mediumorchid2",
"mediumorchid3",
"mediumorchid4",
"darkorchid1",
"darkorchid2",
"darkorchid3",
"darkorchid4",
"purple1",
"purple2",
"purple3",
"purple4",
"mediumpurple1",
"mediumpurple2",
"mediumpurple3",
"mediumpurple4",
"thistle1",
"thistle2",
"thistle3",
"thistle4",
"gray0",
"grey0",
"gray1",
"grey1",
"gray2",
"grey2",
"gray3",
"grey3",
"gray4",
"grey4",
"gray5",
"grey5",
"gray6",
"grey6",
"gray7",
"grey7",
"gray8",
"grey8",
"gray9",
"grey9",
"gray10",
"grey10",
"gray11",
"grey11",
"gray12",
"grey12",
"gray13",
"grey13",
"gray14",
"grey14",
"gray15",
"grey15",
"gray16",
"grey16",
"gray17",
"grey17",
"gray18",
"grey18",
"gray19",
"grey19",
"gray20",
"grey20",
"gray21",
"grey21",
"gray22",
"grey22",
"gray23",
"grey23",
"gray24",
"grey24",
"gray25",
"grey25",
"gray26",
"grey26",
"gray27",
"grey27",
"gray28",
"grey28",
"gray29",
"grey29",
"gray30",
"grey30",
"gray31",
"grey31",
"gray32",
"grey32",
"gray33",
"grey33",
"gray34",
"grey34",
"gray35",
"grey35",
"gray36",
"grey36",
"gray37",
"grey37",
"gray38",
"grey38",
"gray39",
"grey39",
"gray40",
"grey40",
"gray41",
"grey41",
"gray42",
"grey42",
"gray43",
"grey43",
"gray44",
"grey44",
"gray45",
"grey45",
"gray46",
"grey46",
"gray47",
"grey47",
"gray48",
"grey48",
"gray49",
"grey49",
"gray50",
"grey50",
"gray51",
"grey51",
"gray52",
"grey52",
"gray53",
"grey53",
"gray54",
"grey54",
"gray55",
"grey55",
"gray56",
"grey56",
"gray57",
"grey57",
"gray58",
"grey58",
"gray59",
"grey59",
"gray60",
"grey60",
"gray61",
"grey61",
"gray62",
"grey62",
"gray63",
"grey63",
"gray64",
"grey64",
"gray65",
"grey65",
"gray66",
"grey66",
"gray67",
"grey67",
"gray68",
"grey68",
"gray69",
"grey69",
"gray70",
"grey70",
"gray71",
"grey71",
"gray72",
"grey72",
"gray73",
"grey73",
"gray74",
"grey74",
"gray75",
"grey75",
"gray76",
"grey76",
"gray77",
"grey77",
"gray78",
"grey78",
"gray79",
"grey79",
"gray80",
"grey80",
"gray81",
"grey81",
"gray82",
"grey82",
"gray83",
"grey83",
"gray84",
"grey84",
"gray85",
"grey85",
"gray86",
"grey86",
"gray87",
"grey87",
"gray88",
"grey88",
"gray89",
"grey89",
"gray90",
"grey90",
"gray91",
"grey91",
"gray92",
"grey92",
"gray93",
"grey93",
"gray94",
"grey94",
"gray95",
"grey95",
"gray96",
"grey96",
"gray97",
"grey97",
"gray98",
"grey98",
"gray99",
"grey99",
"gray100",
"grey100",
"darkgrey",
"darkgray",
"darkblue",
"darkcyan",
"darkmagenta",
"darkred",
"lightgreen",
};
Color COLOR_DEF[] = {
new Color(255, 250, 250),
new Color(248, 248, 255),
new Color(245, 245, 245),
new Color(220, 220, 220),
new Color(255, 250, 240),
new Color(253, 245, 230),
new Color(250, 240, 230),
new Color(250, 235, 215),
new Color(255, 239, 213),
new Color(255, 235, 205),
new Color(255, 228, 196),
new Color(255, 218, 185),
new Color(255, 222, 173),
new Color(255, 228, 181),
new Color(255, 248, 220),
new Color(255, 255, 240),
new Color(255, 250, 205),
new Color(255, 245, 238),
new Color(240, 255, 240),
new Color(245, 255, 250),
new Color(240, 255, 255),
new Color(240, 248, 255),
new Color(230, 230, 250),
new Color(255, 240, 245),
new Color(255, 228, 225),
new Color(255, 255, 255),
new Color(0, 0, 0),
new Color(47, 79, 79),
new Color(47, 79, 79),
new Color(105, 105, 105),
new Color(105, 105, 105),
new Color(112, 128, 144),
new Color(112, 128, 144),
new Color(119, 136, 153),
new Color(119, 136, 153),
new Color(190, 190, 190),
new Color(190, 190, 190),
new Color(211, 211, 211),
new Color(211, 211, 211),
new Color(25, 25, 112),
new Color(0, 0, 128),
new Color(0, 0, 128),
new Color(100, 149, 237),
new Color(72, 61, 139),
new Color(106, 90, 205),
new Color(123, 104, 238),
new Color(132, 112, 255),
new Color(0, 0, 205),
new Color(65, 105, 225),
new Color(0, 0, 255),
new Color(30, 144, 255),
new Color(0, 191, 255),
new Color(135, 206, 235),
new Color(135, 206, 250),
new Color(70, 130, 180),
new Color(176, 196, 222),
new Color(173, 216, 230),
new Color(176, 224, 230),
new Color(175, 238, 238),
new Color(0, 206, 209),
new Color(72, 209, 204),
new Color(64, 224, 208),
new Color(0, 255, 255),
new Color(224, 255, 255),
new Color(95, 158, 160),
new Color(102, 205, 170),
new Color(127, 255, 212),
new Color(0, 100, 0),
new Color(85, 107, 47),
new Color(143, 188, 143),
new Color(46, 139, 87),
new Color(60, 179, 113),
new Color(32, 178, 170),
new Color(152, 251, 152),
new Color(0, 255, 127),
new Color(124, 252, 0),
new Color(0, 255, 0),
new Color(127, 255, 0),
new Color(0, 250, 154),
new Color(173, 255, 47),
new Color(50, 205, 50),
new Color(154, 205, 50),
new Color(34, 139, 34),
new Color(107, 142, 35),
new Color(189, 183, 107),
new Color(240, 230, 140),
new Color(238, 232, 170),
new Color(250, 250, 210),
new Color(255, 255, 224),
new Color(255, 255, 0),
new Color(255, 215, 0),
new Color(238, 221, 130),
new Color(218, 165, 32),
new Color(184, 134, 11),
new Color(188, 143, 143),
new Color(205, 92, 92),
new Color(139, 69, 19),
new Color(160, 82, 45),
new Color(205, 133, 63),
new Color(222, 184, 135),
new Color(245, 245, 220),
new Color(245, 222, 179),
new Color(244, 164, 96),
new Color(210, 180, 140),
new Color(210, 105, 30),
new Color(178, 34, 34),
new Color(165, 42, 42),
new Color(233, 150, 122),
new Color(250, 128, 114),
new Color(255, 160, 122),
new Color(255, 165, 0),
new Color(255, 140, 0),
new Color(255, 127, 80),
new Color(240, 128, 128),
new Color(255, 99, 71),
new Color(255, 69, 0),
new Color(255, 0, 0),
new Color(255, 105, 180),
new Color(255, 20, 147),
new Color(255, 192, 203),
new Color(255, 182, 193),
new Color(219, 112, 147),
new Color(176, 48, 96),
new Color(199, 21, 133),
new Color(208, 32, 144),
new Color(255, 0, 255),
new Color(238, 130, 238),
new Color(221, 160, 221),
new Color(218, 112, 214),
new Color(186, 85, 211),
new Color(153, 50, 204),
new Color(148, 0, 211),
new Color(138, 43, 226),
new Color(160, 32, 240),
new Color(147, 112, 219),
new Color(216, 191, 216),
new Color(255, 250, 250),
new Color(238, 233, 233),
new Color(205, 201, 201),
new Color(139, 137, 137),
new Color(255, 245, 238),
new Color(238, 229, 222),
new Color(205, 197, 191),
new Color(139, 134, 130),
new Color(255, 239, 219),
new Color(238, 223, 204),
new Color(205, 192, 176),
new Color(139, 131, 120),
new Color(255, 228, 196),
new Color(238, 213, 183),
new Color(205, 183, 158),
new Color(139, 125, 107),
new Color(255, 218, 185),
new Color(238, 203, 173),
new Color(205, 175, 149),
new Color(139, 119, 101),
new Color(255, 222, 173),
new Color(238, 207, 161),
new Color(205, 179, 139),
new Color(139, 121, 94),
new Color(255, 250, 205),
new Color(238, 233, 191),
new Color(205, 201, 165),
new Color(139, 137, 112),
new Color(255, 248, 220),
new Color(238, 232, 205),
new Color(205, 200, 177),
new Color(139, 136, 120),
new Color(255, 255, 240),
new Color(238, 238, 224),
new Color(205, 205, 193),
new Color(139, 139, 131),
new Color(240, 255, 240),
new Color(224, 238, 224),
new Color(193, 205, 193),
new Color(131, 139, 131),
new Color(255, 240, 245),
new Color(238, 224, 229),
new Color(205, 193, 197),
new Color(139, 131, 134),
new Color(255, 228, 225),
new Color(238, 213, 210),
new Color(205, 183, 181),
new Color(139, 125, 123),
new Color(240, 255, 255),
new Color(224, 238, 238),
new Color(193, 205, 205),
new Color(131, 139, 139),
new Color(131, 111, 255),
new Color(122, 103, 238),
new Color(105, 89, 205),
new Color(71, 60, 139),
new Color(72, 118, 255),
new Color(67, 110, 238),
new Color(58, 95, 205),
new Color(39, 64, 139),
new Color(0, 0, 255),
new Color(0, 0, 238),
new Color(0, 0, 205),
new Color(0, 0, 139),
new Color(30, 144, 255),
new Color(28, 134, 238),
new Color(24, 116, 205),
new Color(16, 78, 139),
new Color(99, 184, 255),
new Color(92, 172, 238),
new Color(79, 148, 205),
new Color(54, 100, 139),
new Color(0, 191, 255),
new Color(0, 178, 238),
new Color(0, 154, 205),
new Color(0, 104, 139),
new Color(135, 206, 255),
new Color(126, 192, 238),
new Color(108, 166, 205),
new Color(74, 112, 139),
new Color(176, 226, 255),
new Color(164, 211, 238),
new Color(141, 182, 205),
new Color(96, 123, 139),
new Color(198, 226, 255),
new Color(185, 211, 238),
new Color(159, 182, 205),
new Color(108, 123, 139),
new Color(202, 225, 255),
new Color(188, 210, 238),
new Color(162, 181, 205),
new Color(110, 123, 139),
new Color(191, 239, 255),
new Color(178, 223, 238),
new Color(154, 192, 205),
new Color(104, 131, 139),
new Color(224, 255, 255),
new Color(209, 238, 238),
new Color(180, 205, 205),
new Color(122, 139, 139),
new Color(187, 255, 255),
new Color(174, 238, 238),
new Color(150, 205, 205),
new Color(102, 139, 139),
new Color(152, 245, 255),
new Color(142, 229, 238),
new Color(122, 197, 205),
new Color(83, 134, 139),
new Color(0, 245, 255),
new Color(0, 229, 238),
new Color(0, 197, 205),
new Color(0, 134, 139),
new Color(0, 255, 255),
new Color(0, 238, 238),
new Color(0, 205, 205),
new Color(0, 139, 139),
new Color(151, 255, 255),
new Color(141, 238, 238),
new Color(121, 205, 205),
new Color(82, 139, 139),
new Color(127, 255, 212),
new Color(118, 238, 198),
new Color(102, 205, 170),
new Color(69, 139, 116),
new Color(193, 255, 193),
new Color(180, 238, 180),
new Color(155, 205, 155),
new Color(105, 139, 105),
new Color(84, 255, 159),
new Color(78, 238, 148),
new Color(67, 205, 128),
new Color(46, 139, 87),
new Color(154, 255, 154),
new Color(144, 238, 144),
new Color(124, 205, 124),
new Color(84, 139, 84),
new Color(0, 255, 127),
new Color(0, 238, 118),
new Color(0, 205, 102),
new Color(0, 139, 69),
new Color(0, 255, 0),
new Color(0, 238, 0),
new Color(0, 205, 0),
new Color(0, 139, 0),
new Color(127, 255, 0),
new Color(118, 238, 0),
new Color(102, 205, 0),
new Color(69, 139, 0),
new Color(192, 255, 62),
new Color(179, 238, 58),
new Color(154, 205, 50),
new Color(105, 139, 34),
new Color(202, 255, 112),
new Color(188, 238, 104),
new Color(162, 205, 90),
new Color(110, 139, 61),
new Color(255, 246, 143),
new Color(238, 230, 133),
new Color(205, 198, 115),
new Color(139, 134, 78),
new Color(255, 236, 139),
new Color(238, 220, 130),
new Color(205, 190, 112),
new Color(139, 129, 76),
new Color(255, 255, 224),
new Color(238, 238, 209),
new Color(205, 205, 180),
new Color(139, 139, 122),
new Color(255, 255, 0),
new Color(238, 238, 0),
new Color(205, 205, 0),
new Color(139, 139, 0),
new Color(255, 215, 0),
new Color(238, 201, 0),
new Color(205, 173, 0),
new Color(139, 117, 0),
new Color(255, 193, 37),
new Color(238, 180, 34),
new Color(205, 155, 29),
new Color(139, 105, 20),
new Color(255, 185, 15),
new Color(238, 173, 14),
new Color(205, 149, 12),
new Color(139, 101, 8),
new Color(255, 193, 193),
new Color(238, 180, 180),
new Color(205, 155, 155),
new Color(139, 105, 105),
new Color(255, 106, 106),
new Color(238, 99, 99),
new Color(205, 85, 85),
new Color(139, 58, 58),
new Color(255, 130, 71),
new Color(238, 121, 66),
new Color(205, 104, 57),
new Color(139, 71, 38),
new Color(255, 211, 155),
new Color(238, 197, 145),
new Color(205, 170, 125),
new Color(139, 115, 85),
new Color(255, 231, 186),
new Color(238, 216, 174),
new Color(205, 186, 150),
new Color(139, 126, 102),
new Color(255, 165, 79),
new Color(238, 154, 73),
new Color(205, 133, 63),
new Color(139, 90, 43),
new Color(255, 127, 36),
new Color(238, 118, 33),
new Color(205, 102, 29),
new Color(139, 69, 19),
new Color(255, 48, 48),
new Color(238, 44, 44),
new Color(205, 38, 38),
new Color(139, 26, 26),
new Color(255, 64, 64),
new Color(238, 59, 59),
new Color(205, 51, 51),
new Color(139, 35, 35),
new Color(255, 140, 105),
new Color(238, 130, 98),
new Color(205, 112, 84),
new Color(139, 76, 57),
new Color(255, 160, 122),
new Color(238, 149, 114),
new Color(205, 129, 98),
new Color(139, 87, 66),
new Color(255, 165, 0),
new Color(238, 154, 0),
new Color(205, 133, 0),
new Color(139, 90, 0),
new Color(255, 127, 0),
new Color(238, 118, 0),
new Color(205, 102, 0),
new Color(139, 69, 0),
new Color(255, 114, 86),
new Color(238, 106, 80),
new Color(205, 91, 69),
new Color(139, 62, 47),
new Color(255, 99, 71),
new Color(238, 92, 66),
new Color(205, 79, 57),
new Color(139, 54, 38),
new Color(255, 69, 0),
new Color(238, 64, 0),
new Color(205, 55, 0),
new Color(139, 37, 0),
new Color(255, 0, 0),
new Color(238, 0, 0),
new Color(205, 0, 0),
new Color(139, 0, 0),
new Color(255, 20, 147),
new Color(238, 18, 137),
new Color(205, 16, 118),
new Color(139, 10, 80),
new Color(255, 110, 180),
new Color(238, 106, 167),
new Color(205, 96, 144),
new Color(139, 58, 98),
new Color(255, 181, 197),
new Color(238, 169, 184),
new Color(205, 145, 158),
new Color(139, 99, 108),
new Color(255, 174, 185),
new Color(238, 162, 173),
new Color(205, 140, 149),
new Color(139, 95, 101),
new Color(255, 130, 171),
new Color(238, 121, 159),
new Color(205, 104, 137),
new Color(139, 71, 93),
new Color(255, 52, 179),
new Color(238, 48, 167),
new Color(205, 41, 144),
new Color(139, 28, 98),
new Color(255, 62, 150),
new Color(238, 58, 140),
new Color(205, 50, 120),
new Color(139, 34, 82),
new Color(255, 0, 255),
new Color(238, 0, 238),
new Color(205, 0, 205),
new Color(139, 0, 139),
new Color(255, 131, 250),
new Color(238, 122, 233),
new Color(205, 105, 201),
new Color(139, 71, 137),
new Color(255, 187, 255),
new Color(238, 174, 238),
new Color(205, 150, 205),
new Color(139, 102, 139),
new Color(224, 102, 255),
new Color(209, 95, 238),
new Color(180, 82, 205),
new Color(122, 55, 139),
new Color(191, 62, 255),
new Color(178, 58, 238),
new Color(154, 50, 205),
new Color(104, 34, 139),
new Color(155, 48, 255),
new Color(145, 44, 238),
new Color(125, 38, 205),
new Color(85, 26, 139),
new Color(171, 130, 255),
new Color(159, 121, 238),
new Color(137, 104, 205),
new Color(93, 71, 139),
new Color(255, 225, 255),
new Color(238, 210, 238),
new Color(205, 181, 205),
new Color(139, 123, 139),
new Color(0, 0, 0),
new Color(0, 0, 0),
new Color(3, 3, 3),
new Color(3, 3, 3),
new Color(5, 5, 5),
new Color(5, 5, 5),
new Color(8, 8, 8),
new Color(8, 8, 8),
new Color(10, 10, 10),
new Color(10, 10, 10),
new Color(13, 13, 13),
new Color(13, 13, 13),
new Color(15, 15, 15),
new Color(15, 15, 15),
new Color(18, 18, 18),
new Color(18, 18, 18),
new Color(20, 20, 20),
new Color(20, 20, 20),
new Color(23, 23, 23),
new Color(23, 23, 23),
new Color(26, 26, 26),
new Color(26, 26, 26),
new Color(28, 28, 28),
new Color(28, 28, 28),
new Color(31, 31, 31),
new Color(31, 31, 31),
new Color(33, 33, 33),
new Color(33, 33, 33),
new Color(36, 36, 36),
new Color(36, 36, 36),
new Color(38, 38, 38),
new Color(38, 38, 38),
new Color(41, 41, 41),
new Color(41, 41, 41),
new Color(43, 43, 43),
new Color(43, 43, 43),
new Color(46, 46, 46),
new Color(46, 46, 46),
new Color(48, 48, 48),
new Color(48, 48, 48),
new Color(51, 51, 51),
new Color(51, 51, 51),
new Color(54, 54, 54),
new Color(54, 54, 54),
new Color(56, 56, 56),
new Color(56, 56, 56),
new Color(59, 59, 59),
new Color(59, 59, 59),
new Color(61, 61, 61),
new Color(61, 61, 61),
new Color(64, 64, 64),
new Color(64, 64, 64),
new Color(66, 66, 66),
new Color(66, 66, 66),
new Color(69, 69, 69),
new Color(69, 69, 69),
new Color(71, 71, 71),
new Color(71, 71, 71),
new Color(74, 74, 74),
new Color(74, 74, 74),
new Color(77, 77, 77),
new Color(77, 77, 77),
new Color(79, 79, 79),
new Color(79, 79, 79),
new Color(82, 82, 82),
new Color(82, 82, 82),
new Color(84, 84, 84),
new Color(84, 84, 84),
new Color(87, 87, 87),
new Color(87, 87, 87),
new Color(89, 89, 89),
new Color(89, 89, 89),
new Color(92, 92, 92),
new Color(92, 92, 92),
new Color(94, 94, 94),
new Color(94, 94, 94),
new Color(97, 97, 97),
new Color(97, 97, 97),
new Color(99, 99, 99),
new Color(99, 99, 99),
new Color(102, 102, 102),
new Color(102, 102, 102),
new Color(105, 105, 105),
new Color(105, 105, 105),
new Color(107, 107, 107),
new Color(107, 107, 107),
new Color(110, 110, 110),
new Color(110, 110, 110),
new Color(112, 112, 112),
new Color(112, 112, 112),
new Color(115, 115, 115),
new Color(115, 115, 115),
new Color(117, 117, 117),
new Color(117, 117, 117),
new Color(120, 120, 120),
new Color(120, 120, 120),
new Color(122, 122, 122),
new Color(122, 122, 122),
new Color(125, 125, 125),
new Color(125, 125, 125),
new Color(127, 127, 127),
new Color(127, 127, 127),
new Color(130, 130, 130),
new Color(130, 130, 130),
new Color(133, 133, 133),
new Color(133, 133, 133),
new Color(135, 135, 135),
new Color(135, 135, 135),
new Color(138, 138, 138),
new Color(138, 138, 138),
new Color(140, 140, 140),
new Color(140, 140, 140),
new Color(143, 143, 143),
new Color(143, 143, 143),
new Color(145, 145, 145),
new Color(145, 145, 145),
new Color(148, 148, 148),
new Color(148, 148, 148),
new Color(150, 150, 150),
new Color(150, 150, 150),
new Color(153, 153, 153),
new Color(153, 153, 153),
new Color(156, 156, 156),
new Color(156, 156, 156),
new Color(158, 158, 158),
new Color(158, 158, 158),
new Color(161, 161, 161),
new Color(161, 161, 161),
new Color(163, 163, 163),
new Color(163, 163, 163),
new Color(166, 166, 166),
new Color(166, 166, 166),
new Color(168, 168, 168),
new Color(168, 168, 168),
new Color(171, 171, 171),
new Color(171, 171, 171),
new Color(173, 173, 173),
new Color(173, 173, 173),
new Color(176, 176, 176),
new Color(176, 176, 176),
new Color(179, 179, 179),
new Color(179, 179, 179),
new Color(181, 181, 181),
new Color(181, 181, 181),
new Color(184, 184, 184),
new Color(184, 184, 184),
new Color(186, 186, 186),
new Color(186, 186, 186),
new Color(189, 189, 189),
new Color(189, 189, 189),
new Color(191, 191, 191),
new Color(191, 191, 191),
new Color(194, 194, 194),
new Color(194, 194, 194),
new Color(196, 196, 196),
new Color(196, 196, 196),
new Color(199, 199, 199),
new Color(199, 199, 199),
new Color(201, 201, 201),
new Color(201, 201, 201),
new Color(204, 204, 204),
new Color(204, 204, 204),
new Color(207, 207, 207),
new Color(207, 207, 207),
new Color(209, 209, 209),
new Color(209, 209, 209),
new Color(212, 212, 212),
new Color(212, 212, 212),
new Color(214, 214, 214),
new Color(214, 214, 214),
new Color(217, 217, 217),
new Color(217, 217, 217),
new Color(219, 219, 219),
new Color(219, 219, 219),
new Color(222, 222, 222),
new Color(222, 222, 222),
new Color(224, 224, 224),
new Color(224, 224, 224),
new Color(227, 227, 227),
new Color(227, 227, 227),
new Color(229, 229, 229),
new Color(229, 229, 229),
new Color(232, 232, 232),
new Color(232, 232, 232),
new Color(235, 235, 235),
new Color(235, 235, 235),
new Color(237, 237, 237),
new Color(237, 237, 237),
new Color(240, 240, 240),
new Color(240, 240, 240),
new Color(242, 242, 242),
new Color(242, 242, 242),
new Color(245, 245, 245),
new Color(245, 245, 245),
new Color(247, 247, 247),
new Color(247, 247, 247),
new Color(250, 250, 250),
new Color(250, 250, 250),
new Color(252, 252, 252),
new Color(252, 252, 252),
new Color(255, 255, 255),
new Color(255, 255, 255),
new Color(169, 169, 169),
new Color(169, 169, 169),
new Color(0, 0, 139),
new Color(0, 139, 139),
new Color(139, 0, 139),
new Color(139, 0, 0),
new Color(144, 238, 144),
};
private static final int NUM_MXP_COLORS = 657;
private HashMap<String, Color> colors;
/**
* Constructor
*/
public MXPColors()
{
colors = new HashMap<String, Color>();
//fill in the colors mapping...
for (int i = 0; i < NUM_MXP_COLORS; i++)
{
addColor(COLOR_NAMES[i], COLOR_DEF[i]);
}
}
public void addColor( String color_name, Color value )
{
colors.put(color_name, value);
}
public Color noColor()
{
return nocolor;
}
public Color getColor(String color)
{
Color result = nocolor;
color = color.toLowerCase();
if ((color.length() == 7) && (color.charAt(0) == '#'))
{
color = color.substring(1, 6);
int rgb = Integer.parseInt(color, 16);
result = new Color(rgb);
}
if ( colors.containsKey(color ))
{
result = colors.get(color);
}
return result;
}
public void removeColor (String color)
{
colors.remove(color);
}
}
//----------------------------------------------------------------------------------------------------
private class MXPResult
{
public int type; //result type
public Object data; //result data, contents depend on result type
}
//----------------------------------------------------------------------------------------------------
private class EntityManager
{
/** empty string, to speed up some things a little bit */
private String empty_string;
/** partial entity */
private String partent;
/** are we in an entity? */
private boolean inEntity;
private HashMap<String, String> entities = new HashMap<String, String>();
private String ENTITY_NAMES[] = {
"Aacute",
"aacute",
"Acirc",
"acirc",
"acute",
"AElig",
"aelig",
"Agrave",
"agrave",
"amp",
"apos",
"Aring",
"aring",
"Atilde",
"atilde",
"Auml",
"auml",
"brvbar",
"Ccedil",
"ccedil",
"cedil",
"cent",
"copy",
"curren",
"deg",
"divide",
"Eacute",
"eacute",
"Ecirc",
"ecirc",
"Egrave",
"egrave",
"ETH",
"eth",
"Euml",
"euml",
"frac12",
"frac14",
"frac34",
"gt",
"Iacute",
"iacute",
"Icirc",
"icirc",
"iexcl",
"Igrave",
"igrave",
"iquest",
"Iuml",
"iuml",
"laquo",
"lt",
"macr",
"micro",
"middot",
"nbsp",
"not",
"Ntilde",
"ntilde",
"Oacute",
"oacute",
"Ocirc",
"ocirc",
"Ograve",
"ograve",
"ordf",
"ordm",
"Oslash",
"oslash",
"Otilde",
"otilde",
"Ouml",
"ouml",
"para",
"plusmn",
"pound",
"quot",
"raquo",
"reg",
"sect",
"shy",
"sup1",
"sup2",
"sup3",
"szlig",
"THORN",
"thorn",
"times",
"Uacute",
"uacute",
"Ucirc",
"ucirc",
"Ugrave",
"ugrave",
"uml",
"Uuml",
"uuml",
"Yacute",
"yacute",
"yen",
};
private int ENTITY_DEF[] = {
193,
225,
194,
226,
180,
198,
230,
192,
224,
38,
39,
197,
229,
195,
227,
196,
228,
166,
199,
231,
184,
162,
169,
164,
176,
247,
201,
233,
202,
234,
200,
232,
208,
240,
203,
235,
189,
188,
190,
62,
205,
237,
206,
238,
161,
204,
236,
191,
207,
239,
171,
60,
175,
181,
183,
160,
172,
209,
241,
211,
243,
212,
244,
210,
242,
170,
186,
216,
248,
213,
245,
214,
246,
182,
177,
163,
34,
187,
174,
167,
173,
185,
178,
179,
223,
222,
254,
215,
218,
250,
219,
251,
217,
249,
168,
220,
252,
221,
253,
165,
};
private static final int NUM_MXP_ENTITIES = 100;
public EntityManager(boolean noStdEntities)
{
reset(noStdEntities);
}
//~cEntityManager ();
/**
* add or update entity
*/
public void addEntity (String name, String value)
{
if (name.equals("")) return;
//add or modify the entity
entities.put(name, value);
}
/**
* delete entity
*/
public void deleteEntity (String name)
{
entities.remove(name);
}
public String entity(String name)
{
String result = entities.get(name);
if ( result == null )
{
result = "";
}
return result;
}
public boolean exists(String name)
{
return entities.containsKey(name);
};
/**
* expand entities in a string
*/
public String expandEntities(String s, boolean finished)
{
String s1 = "";
if (!partent.equals("")) //some unfinished entity is waiting...
{
inEntity = true;
}
for (int i = 0; i < s.length(); i++ )
{
char ch = s.charAt(i);
if (inEntity)
{
if (ch == ';') //end of entity
{
inEntity = false;
if (partent.equals("")) //received &;
{
s1 += "&;";
}
else
if (partent.charAt(0) == '_') //invalid entity name - IGNORED
{
partent = "";
}
else
if (partent.charAt(0) == '#') //&#nnn; entity
{
//compute number
int n = 0;
//starting from second character
for (int j = 1; j < partent.length(); j++)
{
int x = partent.charAt(j) - 48;
if ((x < 0) || (x > 9)) //WRONG
{
n = 0;
break;
}
n = n * 10 + x;
if (n > 255) //number too big!
{
n = 0;
break;
}
}
//verify number, IGNORE entity if it's wrong
if ((n >= 32) && (n <= 255))
{
s1 += (char) n;
}
partent = "";
}
else
{
//now we have correct entity name, let's expand it, if possible :)
if (entities.containsKey(partent))
s1 += entities.get(partent);
else
//keep the same string if the entity doesn't exist...
s1 += "&" + partent + ";";
partent = "";
}
}
else if (ch == '&')
//unterminated entity, new entity may start here
{
s1 += "&" + partent;
partent = "";
//isEntity remains set
}
else if ((partent.equals("") && correct1(ch)) ||
((!partent.equals("")) && correctN(ch)))
{
partent += ch;
}
//this wasn't an entity after all
else
{
inEntity = false;
s1 += "&" + partent + ch;
partent = "";
}
}
else
{
if (ch == '&')
inEntity = true;
else
//copy without change
s1 += ch;
}
}
//string ends in an unterminated entity, but only if the string is finished
if (inEntity && finished)
{
s1 += "&" + partent;
partent = "";
inEntity = false;
}
//return the resulting string
return s1;
}
public boolean needMoreText()
{
return !partent.equals("");
}
void reset(boolean noStdEntities)
{
partent = "";
entities.clear();
inEntity = false;
if (noStdEntities)
{
return;
}
//restore standard HTML entities
for (int i = 0; i < NUM_MXP_ENTITIES; i++)
{
String s = "";
s += (char)ENTITY_DEF[i];
entities.put(ENTITY_NAMES[i], s);
}
}
//can this be the first letter of an entity?
private boolean correct1 (char l)
{
return (((l >= 'a') && (l <= 'z')) || ((l >= 'A') && (l <= 'Z')) || (l == '#'));
}
//can this be a letter of entity?
private boolean correctN (char l)
{
return (((l >= 'a') && (l <= 'z')) || ((l >= 'A') && (l <= 'Z')) || (l == '_') ||
((l >= '0') && (l <= '9')));
}
}
//----------------------------------------------------------------------------------------------------
private class ElementManager
{
/** list of all custom elements */
private HashMap<String, sElement> elements = new HashMap<String, sElement>();
private HashMap<String, sInternalElement> ielements = new HashMap<String, sInternalElement>();
/** line tags associated with elements */
private HashMap<Integer, String> lineTags = new HashMap<Integer, String>();
/** aliases for internal elements */
private HashMap<String, String> aliases = new HashMap<String, String>();
/** last line tag */
private int lastLineTag;
/** state class */
private MXPState state;
/** result handler */
private ResultHandler results;
/** entity manager */
private EntityManager entities;
/** expander of parameters in custom tags */
private EntityManager paramexpander;
/** parser of custom element definitions */
private MXPParser parser;
private class sElementPart
{
public boolean istag;
public String text;
};
/** one external element (defined by <!element>) */
private class sElement
{
/** is it an open element? */
public boolean open;
/** is it an element with no closing tag? */
public boolean empty;
/** tag associated with this element */
int tag;
/** flag associated with this element */
public String flag = "";
/** list of all element contents */
public ArrayList<sElementPart> element = new ArrayList<sElementPart>();
/** list of element attributes in the right order */
public ArrayList<String> attlist = new ArrayList<String>();
/** default values for attributes */
public HashMap<String, String> attdefault = new HashMap<String, String>();
/** closing sequence */
public ArrayList<String> closingseq = new ArrayList<String>();
};
/**
* one internal element
*/
private class sInternalElement
{
/** is it an open element? */
public boolean open;
/** is it an element with no closing tag? */
public boolean empty;
/** list of element attributes in the right order */
public ArrayList<String> attlist = new ArrayList<String>();
/** default values for attributes; if there's an empty public String (but defined), then it's a flag */
public HashMap<String, String> attdefault = new HashMap<String, String>();
};
/** one parameter in one tag :-) */
private class sParam {
public boolean flag;
public String name = "";
public String value = "";
};
/** constructor */
public ElementManager (MXPState st, ResultHandler res, EntityManager enm)
{
state = st;
results = res;
entities = enm;
paramexpander = new EntityManager (true);
parser = new MXPParser(null,null,null);
reset();
createInternalElements();
}
public void reset()
{
lastLineTag = 0;
removeAll();
}
public void createInternalElements()
{
//the list doesn't contain information on whether an argument is required or not
//processor of the tag implements this functionality
//create all internal elements
sInternalElement e;
//!element
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("definition"); //this name is not in the spec!
e.attlist.add("att");
e.attlist.add("tag");
e.attlist.add("flag");
e.attlist.add("open");
e.attlist.add("delete");
e.attlist.add("empty");
e.attdefault.put("open",""); //flags
e.attdefault.put("delete","");
e.attdefault.put("empty","");
ielements.put("!element", e);
//!attlist
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("att");
ielements.put("!attlist", e);
//!entity
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("value"); //this name is not in the spec!
e.attlist.add("desc");
e.attlist.add("private");
e.attlist.add("publish");
e.attlist.add("add");
e.attlist.add("delete");
e.attlist.add("remove");
e.attdefault.put("private", ""); //flags
e.attdefault.put("publish", "");
e.attdefault.put("delete", "");
e.attdefault.put("add", "");
e.attdefault.put("remove", "");
ielements.put("!entity", e);
//var
e = new sInternalElement();
e.empty = false;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("desc");
e.attlist.add("private");
e.attlist.add("publish");
e.attlist.add("add");
e.attlist.add("delete");
e.attlist.add("remove");
e.attdefault.put("private", ""); //flags
e.attdefault.put("publish", "");
e.attdefault.put("delete", "");
e.attdefault.put("add", "");
e.attdefault.put("remove", "");
ielements.put("var", e);
//b
e = new sInternalElement();
e.empty = false;
e.open = true;
ielements.put("b", e);
//i
e = new sInternalElement();
e.empty = false;
e.open = true;
ielements.put("i", e);
//u
e = new sInternalElement();
e.empty = false;
e.open = true;
ielements.put("u", e);
//s
e = new sInternalElement();
e.empty = false;
e.open = true;
ielements.put("s", e);
//c
e = new sInternalElement();
e.empty = false;
e.open = true;
e.attlist.add("fore");
e.attlist.add("back");
ielements.put("c", e);
//h
e = new sInternalElement();
e.empty = false;
e.open = true;
ielements.put("h", e);
//font
e = new sInternalElement();
e.empty = false;
e.open = true;
e.attlist.add("face");
e.attlist.add("size");
e.attlist.add("color");
e.attlist.add("back");
ielements.put("font", e);
//nobr
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("nobr", e);
//p
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("p", e);
//br
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("br", e);
//sbr
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("sbr", e);
//a
e = new sInternalElement();
e.empty = false;
e.open = false;
e.attlist.add("href");
e.attlist.add("hint");
e.attlist.add("expire");
ielements.put("a", e);
//send
e = new sInternalElement();
e.empty = false;
e.open = false;
e.attlist.add("href");
e.attlist.add("hint");
e.attlist.add("prompt");
e.attlist.add("expire");
e.attdefault.put("prompt", ""); //flags
ielements.put("send", e);
//expire
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
ielements.put("expire", e);
//version
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("version", e);
//support
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("support", e);
//h1
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h1", e);
//h2
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h2", e);
//h3
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h3", e);
//h4
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h4", e);
//h5
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h5", e);
//h6
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("h6", e);
//hr
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("hr", e);
//small
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("small", e);
//tt
e = new sInternalElement();
e.empty = false;
e.open = false;
ielements.put("tt", e);
//sound
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("fname");
e.attlist.add("v");
e.attlist.add("l");
e.attlist.add("p");
e.attlist.add("t");
e.attlist.add("u");
e.attdefault.put("v", "100");
e.attdefault.put("l", "1");
e.attdefault.put("p", "50");
ielements.put("sound", e);
//music
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("fname");
e.attlist.add("v");
e.attlist.add("l");
e.attlist.add("c");
e.attlist.add("t");
e.attlist.add("u");
e.attdefault.put("v", "100");
e.attdefault.put("l", "1");
e.attdefault.put("c", "1");
ielements.put("music", e);
//gauge
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("entity"); //this name is not in the spec!
e.attlist.add("max");
e.attlist.add("caption");
e.attlist.add("color");
ielements.put("gauge", e);
//stat
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("entity"); //this name is not in the spec!
e.attlist.add("max");
e.attlist.add("caption");
ielements.put("stat", e);
//frame
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name");
e.attlist.add("action");
e.attlist.add("title");
e.attlist.add("internal");
e.attlist.add("align");
e.attlist.add("left");
e.attlist.add("top");
e.attlist.add("width");
e.attlist.add("height");
e.attlist.add("scrolling");
e.attlist.add("floating");
e.attdefault.put("action", "open");
e.attdefault.put("align", "top");
e.attdefault.put("left", "0");
e.attdefault.put("top", "0");
e.attdefault.put("internal", ""); //flags
e.attdefault.put("scrolling", "");
e.attdefault.put("floating", "");
ielements.put("frame", e);
//dest
e = new sInternalElement();
e.empty = false;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("x");
e.attlist.add("y");
e.attlist.add("eol");
e.attlist.add("eof");
e.attdefault.put("eol", ""); //flags
e.attdefault.put("eof", "");
ielements.put("dest", e);
//relocate
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("name"); //this name is not in the spec!
e.attlist.add("port"); //this name is not in the spec!
ielements.put("relocate", e);
//user
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("user", e);
//password
e = new sInternalElement();
e.empty = true;
e.open = false;
ielements.put("password", e);
//image
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("fname");
e.attlist.add("url");
e.attlist.add("t");
e.attlist.add("h");
e.attlist.add("w");
e.attlist.add("hspace");
e.attlist.add("vspace");
e.attlist.add("align");
e.attlist.add("ismap");
e.attdefault.put("align", "top");
e.attdefault.put("ismap", ""); //flags
ielements.put("image", e);
//filter
e = new sInternalElement();
e.empty = true;
e.open = false;
e.attlist.add("src");
e.attlist.add("dest");
e.attlist.add("name");
ielements.put("filter", e);
//finally, define some aliases for internal elements
aliases.put("!el", "!element");
aliases.put("!at", "!attlist");
aliases.put("!en", "!entity");
aliases.put("v", "var");
aliases.put("bold", "b");
aliases.put("strong", "b");
aliases.put("italic", "i");
aliases.put("em", "i");
aliases.put("underline", "u");
aliases.put("strikeout", "s");
aliases.put("high", "h");
aliases.put("color", "c");
aliases.put("destination", "dest");
}
private void removeAll()
{
//external elements only
Object names [] = elements.keySet().toArray();
for (Object object : names)
{
removeElement((String)object);
}
}
private void removeElement (String name)
{
//external elements only
if (elements.containsKey(name))
{
sElement e = elements.get(name);
e.element.clear();
e.attlist.clear();
e.attdefault.clear();
e.closingseq.clear();
if (e.tag != 0 )
lineTags.remove(e.tag);
elements.remove(name);
}
}
/** destructor */
protected void finalize() throws Throwable
{
paramexpander = null;
parser = null;
removeAll ();
//internal elements
Collection<sInternalElement> values = ielements.values();
for (sInternalElement internalElement : values)
{
internalElement.attlist.clear();
internalElement.attdefault.clear();
}
ielements.clear();
aliases.clear();
super.finalize();
}
/** set pointer to cMXPState - needed due to circular dependencies */
public void assignMXPState (MXPState st)
{
state = st;
}
/**
* is this element defined?
*/
public boolean elementDefined (String name)
{
return ((elements.containsKey(name)) || (ielements.containsKey(name)) ||
(aliases.containsKey(name)));
}
/**
* is it an internal tag?
*/
public boolean internalElement (String name)
{
return ((ielements.containsKey(name)) || (aliases.containsKey(name)));
}
/**
* is it a custom element? (i.e. defined via <!element>)
*/
public boolean customElement (String name)
{
return (elements.containsKey(name));
}
/**
* open element?
*/
public boolean openElement (String name)
{
if (!elementDefined (name))
return false;
if (internalElement (name))
{
String n = name;
if (aliases.containsKey(name))
n = aliases.get(name);
return ielements.get(n).open;
}
else
return elements.get(name).open;
}
/**
* empty element? i.e. does it need a closing tag?
*/
public boolean emptyElement (String name)
{
if (!elementDefined (name))
return false;
if (internalElement (name))
{
String n = name;
if (aliases.containsKey(name))
n = aliases.get(name);
return ielements.get(n).empty;
}
else
return elements.get(name).empty;
}
public void gotTag (String tag) throws Exception
{
String tagname = "";
ArrayList<sParam> params = new ArrayList<sParam>();
sParam param = new sParam();
param.flag = false;
char quote = 0;
tagParserState pstate = tagParserState.tagBegin;
for (int i = 0; i<tag.length(); i++)
{
char ch = tag.charAt(i);
//process character
switch (pstate) {
case tagBegin: {
if (ch != ' ')
{
pstate = tagParserState.tagName;
tagname += ch;
}
break;
}
case tagName: {
if (ch == ' ')
pstate = tagParserState.tagBetweenParams;
else
tagname += ch;
break;
}
case tagParam: {
if (ch == '=')
pstate = tagParserState.tagParamValue;
else if (ch == ' ')
{
//one parameter, value only (it could also be a flag, we'll check that later)
param.value = param.name;
param.name = "";
//add a new parameter :-)
params.add(param);
param = new sParam();
param.value = "";
pstate = tagParserState.tagBetweenParams;
}
else
param.name += ch;
break;
}
case tagParamValue: {
if (ch == ' ')
{
//add a new parameter :-)
params.add(param);
param = new sParam();
param.name = "";
param.value = "";
pstate = tagParserState.tagBetweenParams;
}
else if (param.value.isEmpty() && ((ch == '\'') || (ch == '"')))
{
pstate = tagParserState.tagQuotedParam;
quote = ch;
}
else
param.value += ch;
break;
}
case tagQuotedParam: {
if (ch == quote)
{
//add a new parameter :-)
params.add(param);
param = new sParam();
param.name = "";
param.value = "";
pstate = tagParserState.tagAfterQuotedParam;
}
else
param.value += ch;
break;
}
case tagAfterQuotedParam: {
if (ch == ' ') //ignore everything up to some space...
pstate = tagParserState.tagBetweenParams;
break;
}
case tagBetweenParams: {
if (ch != ' ')
{
if ((ch == '\'') || (ch == '"'))
{
pstate = tagParserState.tagQuotedParam;
param.name = "";
quote = ch;
}
else
{
pstate = tagParserState.tagParam;
param.name += ch;
}
}
break;
}
};
}
//last parameter...
switch (pstate)
{
case tagBegin:
results.addToList (results.createError ("Received a tag with no body!"));
break;
case tagParam: {
param.value = param.name;
param.name = "";
params.add(param);
param = new sParam();
}
break;
case tagParamValue:
params.add(param);
param = new sParam();
break;
case tagQuotedParam:
results.addToList (results.createError ("Received tag " + tagname +
" with unfinished quoted parameter!"));
break;
};
//nothing more to do if the tag has no contents...
if (pstate == tagParserState.tagBegin) return;
//convert tag name to lowercase
tagname = tagname.toLowerCase();
//handle closing tag...
if (tagname.charAt(0) == '/')
{
if (!params.isEmpty())
{
results.addToList (results.createError ("Received closing tag " + tagname +
" with parametrs!"));
}
//remove that '/'
tagname = tagname.substring(1);
//and call closing tag processing
handleClosingTag(tagname);
return;
}
//convert all parameter names to lower-case
for (sParam param2 : params)
{
param2.name = param2.name.toLowerCase();
}
//now we check the type of the tag and act accordingly
if (!elementDefined (tagname))
{
params.clear();
results.addToList (results.createError ("Received undefined tag " + tagname + "!"));
return;
}
mxpMode m = state.getMXPMode ();
//mode can be open or secure; locked mode is not possible here (or we're in a bug)
if (m == mxpMode.openMode)
//open mode - only open tags allowed
if (!openElement (tagname))
{
params.clear();
results.addToList (results.createError ("Received secure tag " + tagname +
" in open mode!"));
return;
}
if (internalElement (tagname))
{
//if the name is an alias for another tag, change the name
if (aliases.containsKey(tagname))
tagname = aliases.get(tagname);
//the <support> tag has to be handled separately :(
if (tagname.equals("support"))
{
processSupport(params);
return;
}
//identify all flags in the tag
identifyFlags(ielements.get(tagname).attdefault, params);
//correctly identify all parameters (assign names where necessary)
handleParams (tagname, params, ielements.get(tagname).attlist,
ielements.get(tagname).attdefault);
//separate out all the flags (flags are only valid for internal tags)
ArrayList<String> flags = new ArrayList<String>();
for ( int i =0; i < params.size();)
{
sParam item = params.get(i);
if (item.flag)
{
flags.add(item.name);
params.remove(i);
}
else
i++;
}
//okay, parsing done - send the tag for further processing
processInternalTag(tagname, params, flags);
}
else
{
handleParams (tagname, params, elements.get(tagname).attlist,
elements.get(tagname).attdefault);
processCustomTag(tagname, params);
}
params.clear ();
}
private void handleClosingTag (String name)
{
String n = name.toLowerCase();
if (!elementDefined (n))
{
results.addToList (results.createError ("Received unknown closing tag </" + n + ">!"));
return;
}
if (emptyElement (n))
{
results.addToList (results.createError ("Received closing tag for tag " + n +
", which doesn't need a closing tag!"));
return;
}
if (internalElement (n))
{
//if the name is an alias for another tag, change the name
if (aliases.containsKey(n))
{
n = aliases.get(n);
}
state.gotClosingTag(n);
}
else
{
//send closing flag, if needed
if (!elements.get(n).flag.isEmpty())
state.gotFlag (false, elements.get(n).flag);
//expand the closing tag...
for (String item : elements.get(n).closingseq)
{
handleClosingTag(item);
}
}
}
private void processSupport (List<sParam> params) throws Exception
{
List<String> pars = new ArrayList<String>();
for (sParam param : params)
{
pars.add(param.value);
}
state.gotSUPPORT(pars);
}
private void identifyFlags (HashMap<String, String> attdefault, List<sParam> args)
{
for (sParam param : args)
{
if ( param.name.isEmpty())
{
String s = param.value.toLowerCase();
if ( attdefault.containsKey(s) && (attdefault.get(s).isEmpty()))
{
param.name = s;
param.value = "";
param.flag = true;
}
}
}
}
private void handleParams (String tagname, List<sParam> args,
List<String> attlist, HashMap<String, String> attdefault)
{
//list<string>::const_iterator cur = attlist.begin();
//list<sParam>::iterator it;
int cur = 0;
for (sParam item : args)
{
//flag?
if (item.flag)
{
//only advance parameter iterator
cur++;
}
//not a flag
else
{
//empty name?
if (item.name.isEmpty())
{
//set the parameter name:
//find the correct attribute name, skipping all flags
while (cur < attlist.size())
{
if ((attdefault.containsKey(attlist.get(cur)))
&& (attdefault.get(attlist.get(cur)).isEmpty())) //flag
cur++;
else
break; //okay, found the correct parameter
}
if (cur == attlist.size()) //ARGH! Parameter not found :(
{
results.addToList (results.createError ("Received too many parameters for tag " +
tagname + "!"));
continue; //continue with the next parameter...
}
}
//non-empty name?
else
{
//set "cur" to the parameter following the given one
//to speed things up a bit, first look if the iterator is pointing at the right parameter
// (we won't need to traverse the whole list, if it does)
if ((cur == attlist.size()) || (item.name != attlist.get(cur)))
{
int cur2 = cur; //remember old "cur" value
for (cur = 0; cur < attlist.size(); cur++)
if (item.name.equals(attlist.get(cur)))
break;
if (cur == attlist.size()) //parameter name not found
{
//restore old iterator value
cur = cur2;
results.addToList (results.createError ("Received unknown parameter " +
item.name + " in tag " + tagname + "!"));
//clear name/value to avoid confusion in later stages
item.name = "";
item.value = "";
//proceed with next parameter
continue;
}
//if cur isn't attlist.end(), it's now set to the correct value...
}
}
//things common to all non-flag parameters...
//set parameter name
item.name = attlist.get(cur);
//if parameter value is empty, set it to default value (if any)
if (item.value.isEmpty() && (attdefault.containsKey(attlist.get(cur))))
item.value = attdefault.get(attlist.get(cur));
//advance parameter iterator
cur++;
}
}
//finally, we add default parameter values to the beginning of the list... these shall get
//overridden by given values, if any (those shall be later in the list)
for (Object item : attdefault.keySet().toArray())
{
if ( !attdefault.get(item).isEmpty())
{
sParam s = new sParam();
s.flag = false;
s.name = (String)item;
s.value = attdefault.get(item);
args.add(0, s);
}
}
}
private void processInternalTag (String name2, List<sParam> params,
List<String> flags)
{
//list<sParam>::const_iterator it;
//list<string>::const_iterator it2;
if (name2.equals("!element"))
{
String lname = "", definition = "", att = "", flag = "";
int tag = 0;
boolean fopen = false, fdelete = false, fempty = false;
for (sParam item : params)
{
String s = item.name;
if (s.equals("name")) lname = item.value.toLowerCase();
if (s.equals("definition")) definition = item.value;
if (s.equals("att")) att = item.value;
if (s.equals("flag")) flag = item.value;
if (s.equals("tag")) tag = Integer.parseInt(item.value);
}
for (String string : flags)
{
if (string.equals("open")) fopen = true;
if (string.equals("delete")) fdelete = true;
if (string.equals("empty")) fempty = true;
}
if (lname.isEmpty())
{
results.addToList (results.createError (
"Received an <!element> tag with no element name!"));
return;
}
//definition can be empty, that's no problem...
//if we want to delete the tag...
if (fdelete)
{
//sanity check
if (!elements.containsKey(lname))
{
results.addToList (results.createWarning (
"Received request to remove an undefined tag " + lname + "!"));
return;
}
removeElement (lname);
return;
}
//parse tag definition
parser.simpleParse(definition);
ArrayList<sElementPart> tagcontents = new ArrayList<sElementPart>();
while (parser.hasNext())
{
chunk ch = parser.getNext();
if (ch.chk == chunkType.chunkError)
results.addToList (results.createError (ch.text));
else
{
//create a new element part
sElementPart part = new sElementPart();
part.text = ch.text;
part.istag = (ch.chk == chunkType.chunkTag) ? true : false;
tagcontents.add(part);
}
}
//parse attribute list
ArrayList<String> attlist = new ArrayList<String>();
HashMap<String, String> attdefault = new HashMap<String, String>();
processParamList (att, attlist, attdefault);
//and do the real work
addElement(lname, tagcontents, attlist, attdefault, fopen, fempty, tag, flag);
}
else if (name2.equals("!attlist"))
{
String name = "", att = "";
for ( Iterator it = params.iterator(); it.hasNext();)
{
sParam item = (sParam)it.next();
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("att")) att = item.value;
}
if (name.isEmpty())
{
results.addToList (results.createError (
"Received an <!attlist> tag with no element name!"));
return;
}
//parse attribute list
ArrayList<String> attlist = new ArrayList<String>();
HashMap<String, String> attdefault = new HashMap<String, String>();
processParamList (att, attlist, attdefault);
//and do the real work
setAttList (name, attlist, attdefault);
}
else if (name2.equals("!entity"))
{
String name = "", value = "", desc;
boolean fpriv = false, fpub = false, fadd = false, fdel = false, frem = false;
for (sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("value")) value = item.value;
if (s.equals("desc")) desc = item.value;
}
for (String item : flags)
{
if (item.equals( "private")) fpriv = true;
if (item.equals( "publish")) fpub = true;
if (item.equals( "delete")) fdel = true;
if (item.equals( "add")) fadd = true;
if (item.equals( "remove")) frem = true;
}
if (name.isEmpty())
{
results.addToList (results.createError (
"Received an <!entity> tag with no variable name!"));
return;
}
//fpub is IGNORED...
//fadd and frem is IGNORED...
if (!(fadd) && !(frem))
{
if (fdel)
{
entities.deleteEntity (name);
if (!fpriv) //do not announce PRIVATE entities
state.gotVariable (name, "", true);
}
else
{
//we now have a new variable...
entities.addEntity (name, value);
if (!fpriv) //do not announce PRIVATE entities
state.gotVariable (name, value, false);
}
}
else
results.addToList (results.createWarning (
"Ignored <!ENTITY> tag with ADD or REMOVE flag."));
}
else if (name2.equals("var"))
{
//this is very similar to the !entity handler above...
String name = "", desc = "";
boolean fpriv = false, fpub = false, fadd = false, fdel = false, frem = false;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("desc")) desc = item.value;
}
for ( String item : flags)
{
if (item.equals("private")) fpriv = true;
if (item.equals("publish")) fpub = true;
if (item.equals("add")) fadd = true;
if (item.equals("delete")) fdel = true;
if (item.equals("remove")) frem = true;
}
if (name.isEmpty())
{
results.addToList (results.createError (
"Received an <var> tag with no variable name!"));
return;
}
//fpriv and fpub is IGNORED...
//fadd and fdel is IGNORED...
if (!(fadd) && !(fdel))
state.gotVAR (name);
else
results.addToList (results.createWarning ("Ignored <VAR> tag with ADD or REMOVE flag."));
}
else if (name2.equals("b"))
state.gotBOLD();
else if (name2.equals("i"))
state.gotITALIC();
else if (name2.equals("u"))
state.gotUNDERLINE();
else if (name2.equals("s"))
state.gotSTRIKEOUT();
else if (name2.equals("c"))
{
String fore = "", back = "";
for (sParam item : params)
{
String s = item.name;
if (s.equals("fore")) fore = item.value;
if (s.equals("back")) back = item.value;
}
Color fg = state.fgColor();
Color bg = state.bgColor();
if (!fore.isEmpty())
fg = allcolors.getColor(fore);
if (!back.isEmpty())
bg = allcolors.getColor(back);
state.gotCOLOR (fg, bg);
}
else if (name2.equals("h"))
state.gotHIGH();
else if (name2.equals("font"))
{
String face = "", fore="", back="";
int size = 0;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("face")) face = item.value;
if (s.equals("size")) size = Integer.parseInt(item.value);
if (s.equals("color")) fore = item.value;
if (s.equals("back")) back = item.value;
}
if (face.isEmpty())
face = state.fontFace();
if (size == 0)
size = state.fontSize();
Color fg = state.fgColor();
Color bg = state.bgColor();
if (!fore.isEmpty())
fg = allcolors.getColor(fore);
if (!back.isEmpty())
bg = allcolors.getColor(back);
state.gotFONT (face, size, fg, bg);
}
else if (name2.equals("p"))
state.gotP();
else if (name2.equals("br"))
state.gotBR();
else if (name2.equals("nobr"))
state.gotNOBR();
else if (name2.equals("sbr"))
state.gotSBR();
else if (name2.equals("a"))
{
String href = "", hint = "", expire = "";
for ( sParam item : params)
{
String s = item.name;
if (s.equals("href")) href = item.value;
if (s.equals("hint")) hint = item.value;
if (s.equals("expire")) expire = item.value;
}
state.gotA (href, hint, expire);
}
else if (name2.equals("send"))
{
String href = "", hint = "", expire = "";
boolean prompt = false;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("href")) href = item.value;
if (s.equals("hint")) hint = item.value;
if (s.equals("expire")) expire = item.value;
}
for ( String item : flags)
{
if (item.equals("prompt")) prompt = true;
}
state.gotSEND (href, hint, prompt, expire);
}
else if (name2.equals("expire"))
{
String name = "";
for ( sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
}
//name can be empty - all named links shall then expire
state.gotEXPIRE(name);
}
else if (name2.equals("version"))
state.gotVERSION();
else if (name2.equals("h1"))
state.gotHtag (1);
else if (name2.equals("h2"))
state.gotHtag (2);
else if (name2.equals("h3"))
state.gotHtag (3);
else if (name2.equals("h4"))
state.gotHtag (4);
else if (name2.equals("h5"))
state.gotHtag (5);
else if (name2.equals("h6"))
state.gotHtag (6);
else if (name2.equals("hr"))
state.gotHR();
else if (name2.equals("small"))
state.gotSMALL();
else if (name2.equals("tt"))
state.gotTT();
else if (name2.equals("sound"))
{
String fname = "", t = "", u = "";
int v = 0, l = 0, p = 0; //shall be overridden by defaults...
for ( sParam item : params)
{
String s = item.name;
if (s.equals("fname")) fname = item.value;
if (s.equals("t")) t = item.value;
if (s.equals("u")) u = item.value;
if (s.equals("v")) v = Integer.parseInt(item.value);
if (s.equals("l")) l = Integer.parseInt(item.value);
if (s.equals("p")) p = Integer.parseInt(item.value);
}
if (fname.isEmpty())
{
results.addToList (results.createError ("Received SOUND tag with no file name!"));
return;
}
if ((v < 0) || (v > 100))
{
results.addToList (results.createWarning ("Ignoring incorrect V param for SOUND tag."));
v = 100; //set default value
}
if ((l < -1) || (l > 100) || (l == 0))
{
results.addToList (results.createWarning ("Ignoring incorrect L param for SOUND tag."));
l = 1; //set default value
}
if ((p < 0) || (p > 100))
{
results.addToList (results.createWarning ("Ignoring incorrect P param for SOUND tag."));
p = 50; //set default value
}
state.gotSOUND (fname, v, l, p, t, u);
}
else if (name2.equals("music"))
{
String fname = "", t = "", u = "";
int v = 0, l = 0, c = 0; //shall be overridden by defaults...
for ( sParam item : params)
{
String s = item.name;
if (s.equals("fname")) fname = item.value;
if (s.equals("t")) t = item.value;
if (s.equals("u")) u = item.value;
if (s.equals("v")) v = Integer.parseInt(item.value);
if (s.equals("l")) l = Integer.parseInt(item.value);
if (s.equals("c")) c = Integer.parseInt(item.value);
}
if (fname.isEmpty())
{
results.addToList (results.createError ("Received MUSIC tag with no file name!"));
return;
}
if ((v < 0) || (v > 100))
{
results.addToList (results.createWarning ("Ignoring incorrect V param for MUSIC tag."));
v = 100; //set default value
}
if ((l < -1) || (l > 100) || (l == 0))
{
results.addToList (results.createWarning ("Ignoring incorrect L param for MUSIC tag."));
l = 1; //set default value
}
if ((c != 0) && (c != 1))
{
results.addToList (results.createWarning ("Ignoring incorrect C param for MUSIC tag."));
c = 1; //set default value
}
state.gotMUSIC (fname, v, l, (c!=0), t, u);
}
else if (name2.equals("gauge"))
{
String entity = "", max = "", caption = "", color = "";
for ( sParam item : params)
{
String s = item.name;
if (s.equals("entity")) entity = item.value;
if (s.equals("max")) max = item.value;
if (s.equals("caption")) caption = item.value;
if (s.equals("color")) color = item.value;
}
if (entity.isEmpty())
{
results.addToList (results.createError ("Received GAUGE with no entity name!"));
return;
}
Color c;
if (color.isEmpty()) color = "white";
c = allcolors.getColor(color);
state.gotGAUGE (entity, max, caption, c);
}
else if (name2.equals("stat"))
{
String entity = "", max = "", caption = "";
for ( sParam item : params)
{
String s = item.name;
if (s.equals("entity")) entity = item.value;
if (s.equals("max")) max = item.value;
if (s.equals("caption")) caption = item.value;
}
if (entity.isEmpty())
{
results.addToList (results.createError ("Received STAT with no entity name!"));
return;
}
state.gotSTAT (entity, max, caption);
}
else if (name2.equals("frame"))
{
String name = "", action = "", title = "", align = "";
int left = 0, top = 0, width = 0, height = 0;
boolean finternal = false, fscroll = false, ffloat = false;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("action")) action = item.value;
if (s.equals("title")) title = item.value;
if (s.equals("align")) align = item.value;
if (s.equals("left")) left = state.computeCoord (item.value, true,false);
if (s.equals("top")) top = state.computeCoord (item.value, false,false);
if (s.equals("width")) width = state.computeCoord (item.value, true,false);
if (s.equals("height")) height = state.computeCoord (item.value, false,false);
}
for ( String item : flags)
{
if (item.equals("internal")) finternal = true;
if (item.equals("scrolling")) fscroll = true;
if (item.equals("floating")) ffloat = true;
}
if (name.isEmpty())
{
results.addToList (results.createError ("Received FRAME tag with no frame name!"));
return;
}
state.gotFRAME (name, action, title, finternal, align, left, top, width, height,
fscroll, ffloat);
}
else if (name2.equals("dest"))
{
String name = "";
int x = 0, y = 0;
boolean feol = false, feof = false;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("x")) x = Integer.parseInt(item.value);
if (s.equals("y")) y = Integer.parseInt(item.value);
}
for ( String item : flags)
{
if (item.equals("eol")) feol = true;
if (item.equals("eof")) feof = true;
}
if (name.isEmpty())
{
results.addToList (results.createError ("Received DEST tag with no frame name!"));
return;
}
state.gotDEST (name, x, y, feol, feof);
}
else if (name2.equals("relocate"))
{
String name = "";
int port = 0;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("name")) name = item.value;
if (s.equals("port")) port = Integer.parseInt(item.value);
}
if (name.isEmpty())
{
results.addToList (results.createError ("Received RELOCATE tag with no server name!"));
return;
}
if (port == 0)
{
results.addToList (results.createError ("Received RELOCATE tag with no server port!"));
return;
}
state.gotRELOCATE (name, port);
}
else if (name2.equals("user"))
state.gotUSER();
else if (name2.equals("password"))
state.gotPASSWORD();
else if (name2.equals("image"))
{
String name="", url="", t="", align="";
int h = 0, w = 0, hspace = 0, vspace = 0;
boolean fismap = false;
for ( sParam item : params)
{
String s = item.name;
if (s.equals("fname")) name = item.value;
if (s.equals("url")) url = item.value;
if (s.equals("t")) t = item.value;
if (s.equals("align")) align = item.value;
if (s.equals("h")) h = state.computeCoord (item.value, true, true);
if (s.equals("w")) w = state.computeCoord (item.value, false, true);
if (s.equals("hspace")) hspace = Integer.parseInt(item.value);;
if (s.equals("vspace")) vspace = Integer.parseInt(item.value);;
}
for ( String item : flags)
{
if (item.equals("ismap")) fismap = true;
}
if (name.isEmpty())
{
results.addToList (results.createError ("Received IMAGE tag with no image name!"));
return;
}
state.gotIMAGE (name, url, t, h, w, hspace, vspace, align, fismap);
}
else if (name2.equals("filter"))
{
/*
String src, dest, name;
for (it = params.begin(); it != params.end(); ++it)
{
String s = (*it).name;
if (s.equals("src") src = (*it).value;
if (s.equals("dest") dest = (*it).value;
if (s.equals("name") name = (*it).value;
}
state.gotFILTER (src, dest, name);
*/
results.addToList (results.createWarning ("Ignoring unsupported FILTER tag."));
}
}
private void setAttList(String name, ArrayList<String> attlist,
HashMap<String, String> attdefault)
{
//sanity check
if (!elements.containsKey(name))
{
results.addToList (results.createWarning ("Received attribute list for undefined tag " +
name + "!"));
return;
}
sElement e = elements.get(name);
e.attlist.clear();
e.attdefault.clear();
e.attlist = attlist;
e.attdefault = attdefault;
}
private void addElement(String name, List<sElementPart> contents,
ArrayList<String> attlist, HashMap<String, String> attdefault,
boolean open, boolean empty, int tag, String flag)
{
//sanity checks
if (elementDefined (name))
{
results.addToList (results.createError ("Multiple definition of element " + name + "!"));
return;
}
sElement e = new sElement();
e.open = open;
e.empty = empty;
if ((tag >= 20) && (tag <= 99))
{
e.tag = tag;
if (lineTags.containsKey(tag))
results.addToList (results.createError ("Element " + name +
" uses an already assigned line tag!"));
lineTags.put(tag, name);
}
else
e.tag = 0;
e.flag = flag;
//assign element contents, generating the list of closing tags
e.element.clear();
for (sElementPart ep : contents)
{
if (ep.istag)
{
String tag1 = ep.text.split(" ")[0].toLowerCase();
if (elementDefined (tag1))
{
if (open && !(openElement (tag1)))
{
ep = null;
results.addToList (results.createError ("Definition of open " + name +
" tag contains secure tag " + tag1 + "!"));
}
else if (empty && !(emptyElement (tag1)))
{
ep = null;
results.addToList (results.createError ("Definition of empty " + name +
" tag contains non-empty tag " + tag1 + "!"));
}
else
{
e.element.add (ep);
if (!emptyElement(tag1)) e.closingseq.add(0,tag1);
}
}
else
{
//element doesn't exist yet - we must believe that it's correct
e.element.add(ep);
if (!empty) e.closingseq.add(0,tag1);
results.addToList (results.createWarning ("Definition of element " + name +
" contains undefined element " + tag1 + "!"));
}
}
else
e.element.add(ep);
}
//assign the element definition
elements.put(name,e);
//set attribute list
setAttList (name, attlist, attdefault);
}
private void processParamList(String params, ArrayList<String> attlist,
HashMap<String, String> attdefault)
{
//this is similar to the parser in gotTag(), but it's a bit simpler...
if (params==null) return;
String name = "", value = "";
char quote = 0;
paramParserState state = paramParserState.parNone;
for ( int i =0; i < params.length(); i++)
{
char ch = params.charAt(i);
//process character
switch (state) {
case parNone: {
if (ch != ' ')
{
state = paramParserState.parName;
name += ch;
}
break;
}
case parName: {
if (ch == '=')
state = paramParserState.parValue;
else if (ch == ' ')
{
//new parameter, no default value
attlist.add(name.toLowerCase());
name = "";
state = paramParserState.parNone;
}
else
name += ch;
break;
}
case parValue: {
if (ch == ' ')
{
//new parameter, with default value
attlist.add(name.toLowerCase());
attdefault.put(name, value);
name = "";
value = "";
state = paramParserState.parNone;
}
else if (value.isEmpty() && ((ch == '\'') || (ch == '"')))
{
state = paramParserState.parQuotedValue;
quote = ch;
}
else
value += ch;
break;
}
case parQuotedValue: {
if (ch == quote)
{
//new parameter, with default value
attlist.add(name.toLowerCase());
attdefault.put(name, value);
name = "";
value = "";
state = paramParserState.parNone;
}
else
value += ch;
break;
}
};
}
//last parameter...
switch (state) {
case parName: {
//new parameter, no default value
attlist.add(name.toLowerCase());
}
break;
case parValue: {
//new parameter, with default value
attlist.add(name.toLowerCase());
attdefault.put(name, value);
break;
}
case parQuotedValue:
results.addToList (results.createWarning (
"Received tag definition with unfinished quoted default parameter value!"));
//new parameter, with default value (unfinished, but hey...)
attlist.add(name.toLowerCase());
attdefault.put(name, value);
break;
};
//everything done...
}
private void processCustomTag(String name, List<sParam> params) throws Exception
{
//generate a mapping with all parameter values
paramexpander.reset(false);
for (sParam param : params)
{
//assign parameter value... default values and stuff were already expanded
paramexpander.addEntity (param.name, "'" + param.value + "'");
}
//process tag contents one by one
for (sElementPart sep : elements.get(name).element)
{
String part = sep.text;
//expand tag parameters first
part = paramexpander.expandEntities (part, true);
//parameters are expanded, process this part
if (sep.istag)
//this part is another tag - expand it recursively
gotTag(part);
else
//this part is regular text
state.gotText(part,true);
}
if (!elements.get(name).flag.isEmpty())
state.gotFlag (true, elements.get(name).flag);
}
void gotLineTag (int number) throws Exception
{
if ((number < 20) || (number > 99))
{
lastLineTag = 0;
return;
}
if (!lineTags.containsKey(number))
{
lastLineTag = 0;
return;
}
String tag = lineTags.get(number);
lastLineTag = number;
//behave as if we've just gotten the appropriate tag
gotTag(tag);
}
public void gotNewLine ()
{
if ((lastLineTag < 20) || (lastLineTag > 99))
{
lastLineTag = 0;
return;
}
if (!lineTags.containsKey(lastLineTag))
{
lastLineTag = 0;
return;
}
String tag = lineTags.get(lastLineTag);
lastLineTag = 0;
if (emptyElement (tag))
//no closing tag needed
return;
//okay, send out the appropriate closing tag
handleClosingTag (tag);
}
}
//----------------------------------------------------------------------------------------------------
private class chunk
{
public chunkType chk;
public String text;
}
//----------------------------------------------------------------------------------------------------
private class MXPParser
{
private parserState pstate;
private String str = "";
private ArrayList<chunk> chunks = new ArrayList<chunk>();
private char quoteChar;
private boolean wasBackslashR;
private MXPState state;
private ElementManager elements;
private ResultHandler results;
/** constructor */
public MXPParser (MXPState st, ElementManager elm, ResultHandler res )
{
state = st;
elements = elm;
results = res;
pstate = parserState.pText;
wasBackslashR = false;
}
public void simpleParse(String text)
{
if (text.isEmpty())
return;
chunk ch = new chunk();
pstate = parserState.pText;
str = "";
for ( int i =0; i < text.length(); i++ )
{
char c = text.charAt(i);
switch (pstate)
{
case pText: {
if (c == '<')
{
//end of text - got start of tag
if (!str.isEmpty())
{
ch.chk = chunkType.chunkText;
ch.text = str;
chunks.add(ch);
ch = new chunk();
str = "";
}
pstate = parserState.pTag;
}
else
str += c; //add new character to the text...
break;
}
case pTag: {
if (c == '>')
{
ch.chk = chunkType.chunkTag;
ch.text = str;
chunks.add(ch);
ch = new chunk();
str = "";
pstate = parserState.pText;
}
else
if ((c == '"') || (c == '\''))
{
pstate = parserState.pQuotedParam;
quoteChar = c;
str += c;
}
else
str += c;
break;
}
case pQuotedParam: {
if (c == quoteChar)
{
//quoted parameter ends... this simple approach will work correctly for correct
//tags, it may treat incorrect quotes as correct, but element manager will take care
//of that
pstate = parserState.pTag;
str += c;
}
else
str += c;
break;
}
};
}
//unfinished things...
if (pstate == parserState.pText)
{
ch.chk = chunkType.chunkText;
ch.text = str;
chunks.add(ch);
ch = new chunk();
}
if ((pstate == parserState.pTag) || (pstate == parserState.pQuotedParam))
{
ch.chk = chunkType.chunkError;
ch.text = "Tag definition contains unfinished tag <" + str;
chunks.add(ch);
ch = new chunk();
}
str = "";
}
public boolean hasNext()
{
return chunks.isEmpty() ? false : true;
}
public chunk getNext()
{
if (!hasNext())
{
chunk nochunk = new chunk();
nochunk.chk = chunkType.chunkNone;
return nochunk;
}
chunk ch = chunks.get(0);
chunks.remove(0);
return ch;
}
public void parse(String text) throws Exception
{
//WARNING: examine this function only at your own risk!
//it is advised to have a look at the simpleParse() function first - it's similar
//to this one, but much simpler...
if (text.isEmpty())
return;
for (int i = 0; i < text.length(); i++)
{
char c = text.charAt(i);
// Looks like number of brain-dead servers that send out \n\r is bigger than the
// number of servers that send out \r alone - the latter maybe don't exist at
// all. Hence, with this commented out, we can't handle the \r-only ones,
// but \n\r works.
/*
//handle \r not followed by \n - treated as a newline
if (wasBackslashR && (c != '\n'))
{
//"str" now certainly is empty, so we needn't care about that
//report new-line
elements->gotNewLine();
state->gotNewLine();
}
*/
wasBackslashR = false;
//we need current mode - parsing in LOCKED mode is limited
//mode is retrieved in every iteration to ensure that it's always up-to-date
mxpMode mode = state.getMXPMode();
switch (pstate) {
case pText: {
//tags not recognized in LOCKED mode...
if ((c == '\u001B') || ((mode != mxpMode.lockedMode) &&
(c == '<')) || (c == '\n') || (c == '\r'))
{
//end of text - got newline / ANSI seq / start of tag
if (!str.isEmpty())
{
state.gotText(str,true);
str = "";
}
if (c == '\u001B')
pstate = parserState.pAnsiSeq;
if ((c == '<') && (mode != mxpMode.lockedMode))
pstate = parserState.pTag;
if (c == '\n')
{
//report new-line
elements.gotNewLine();
state.gotNewLine();
}
if (c == '\r')
wasBackslashR = true;
}
else
str += c; //add new character to the text...
break;
}
case pAnsiSeq: {
if ((c == '\u001B') || (c == '\n') || (c == '\r'))
{
//the same as in pTag section...
results.addToList (results.createError ("Received unfinished ANSI sequence!"));
str = "";
if (c == '\u001B')
pstate = parserState.pAnsiSeq;
if (c == '\n')
{
//report new-line
elements.gotNewLine();
state.gotNewLine();
pstate = parserState.pText;
}
if (c == '\r')
{
pstate = parserState.pText;
wasBackslashR = true;
}
}
else
if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))
{
//ANSI sequence ends...
if (c == 'z') //line tag
{
if (str.isEmpty())
{
//invalid sequence
str = "\u001Bz";
}
else
{
//process this sequence
int len = str.length();
int num = 0;
for (int j = 1; j < len; j++) //str[0] is '[', which is SKIPPED
{
char cc = str.charAt(j);
if (cc == ';') //this shouldn't happen, but some MUD might want to use it...
{
if ((num >= 0) && (num <= 99)) //ensure that number lies in correct range
{
state.gotLineTag (num);
elements.gotLineTag (num);
}
else
results.addToList (results.createError ("Received invalid line tag!"));
num = 0;
}
else
num = num * 10 + (cc - 48); //48 is the code of '0'
}
//report last line tag (and usually the only one)
if ((num >= 0) && (num <= 99)) //ensure that number lies in correct range
{
state.gotLineTag (num);
elements.gotLineTag (num);
}
else
results.addToList (results.createError ("Received invalid line tag!"));
str = "";
}
}
else //something else
{
//'\u001B' and c are not in the string - add them there
str = '\u001B' + str + c;
}
pstate = parserState.pText;
}
else
if (c == '[') //this one is valid, but only at the beginning
{
if (str.isEmpty())
str += c;
else
{
//'[' in the middle of ANSI seq => not an ANSI seq...
pstate = parserState.pText;
str = '\u001B' + str + c;
}
}
else
if ((c == ';') || ((c >= '0') && (c <= '9'))) //correct char, unless str is empty
if (!str.isEmpty())
str += c; //here we go...
else
{
//ANSI seq must start with [ - therefore this is not an ANSI sequence after all
pstate = parserState.pText;
str += '\u001B';
str += c;
}
else
//incorrect character...
{
str = '\u001B' + str + c;
pstate = parserState.pText;
}
break;
}
case pTag: {
if (c == '>')
{
elements.gotTag (str);
str = "";
pstate = parserState.pText;
}
else
if ((c == '"') || (c == '\''))
{
pstate = parserState.pQuotedParam;
quoteChar = c;
str += c;
}
else if ((c == '\u001B') || (c == '\n') || (c == '\r'))
{
//handle incorrectly terminated tag and continue parsing...
results.addToList (results.createError ("Received unfinished tag <" + str));
str = "";
if (c == '\u001B')
pstate = parserState.pAnsiSeq;
if (c == '\n')
{
//report new-line
elements.gotNewLine();
state.gotNewLine();
pstate = parserState.pText;
}
if (c == '\r')
{
pstate = parserState.pText;
wasBackslashR = true;
}
}
else if (str.equals("!--")) //comment
{
str += c;
pstate = parserState.pComment;
}
else
str += c;
break;
}
case pComment: {
if (c == '>')
{
int l = str.length();
if ((str.charAt(l-2) == '-') && (str.charAt(l-1) == '-')) //okay, comment ends
{
str = "";
pstate = parserState.pText;
}
else
str += c;
}
else if ((c == '\u001B') || (c == '\n') || (c == '\r'))
{
//handle incorrectly terminated comment and continue parsing...
results.addToList (results.createError ("Received an unfinished comment!"));
str = "";
if (c == '\u001B')
pstate = parserState.pAnsiSeq;
if (c == '\n')
{
//report new-line
elements.gotNewLine();
state.gotNewLine();
pstate = parserState.pText;
}
if (c == '\r')
{
pstate = parserState.pText;
wasBackslashR = true;
}
}
else
str += c;
break;
}
case pQuotedParam: {
if (c == quoteChar)
{
//quoted parameter ends... this simple approach will work correctly for correct
//tags, it may treat incorrect quotes as correct, but element manager will take care
//of that
pstate = parserState.pTag;
str += c;
}
else
if ((c == '\u001B') || (c == '\n') || (c == '\r'))
{
//the same as in pTag section...
results.addToList (results.createError ("Received unfinished tag <" + str));
str = "";
if (c == '\u001B')
pstate = parserState.pAnsiSeq;
if (c == '\n')
{
//report new-line
elements.gotNewLine();
state.gotNewLine();
pstate = parserState.pText;
}
if (c == '\r')
{
pstate = parserState.pText;
wasBackslashR = true;
}
}
else
str += c;
break;
}
};
}
//report remaining text, if any (needed to improve speed of text displaying and to handle
//prompts correctly)
if ((pstate == parserState.pText) && (!str.isEmpty()))
{
state.gotText(str,true);
str = "";
}
}
}
//----------------------------------------------------------------------------------------------------
private class MXPProcessor
{
private ResultHandler results;
private MXPState state;
private MXPParser parser;
private EntityManager entities;
private ElementManager elements;
public MXPProcessor(String package_name, String version)
{
//create all the objects...
results = new ResultHandler();
entities = new EntityManager(false);
elements = new ElementManager(null, results, entities);
state = new MXPState(results, elements, entities, package_name, version);
elements.assignMXPState(state);
parser = new MXPParser(state, elements, results);
}
public void processText(String text) throws Exception
{
if (text.isEmpty()) return;
parser.parse(text);
}
public void setDefaultText(String font, int size, boolean _bold,
boolean _italic, boolean _underline, boolean _strikeout, Color fg,
Color bg)
{
state.setDefaultText (font, size, _bold, _italic, _underline, _strikeout, fg, bg);
}
public void setHeaderParams(int which, String font, int size,
boolean _bold, boolean _italic, boolean _underline,
boolean _strikeout, Color fg, Color bg)
{
state.setHeaderParams(which, font, size, _bold, _italic, _underline, _strikeout, fg, bg);
}
public void setDefaultGaugeColor(Color color)
{
state.setDefaultGaugeColor(color);
}
public void setNonProportFont(String font)
{
state.setNonProportFont(font);
}
public void setClient(String name, String version)
{
state.setClient(name,version);
}
public boolean hasResult()
{
return results.haveResults();
}
public MXPResult nextResult()
{
return results.nextResult();
}
public void switchToOpen ()
{
state.switchToOpen ();
}
public void setScreenProps (int sx, int sy, int wx, int wy, int fx, int fy)
{
state.setScreenProps (sx, sy, wx, wy, fx, fy);
}
public void supportsLink (boolean supports)
{
state.supportsLink (supports);
}
public void supportsGauge (boolean supports)
{
state.supportsGauge (supports);
}
public void supportsSound (boolean supports)
{
state.supportsSound (supports);
}
public void supportsStatus (boolean supports)
{
state.supportsStatus (supports);
}
public void supportsFrame (boolean supports)
{
state.supportsFrame (supports);
}
public void supportsImage (boolean supports)
{
state.supportsImage (supports);
}
public void supportsRelocate (boolean supports)
{
state.supportsRelocate (supports);
}
}
//----------------------------------------------------------------------------------------------------
private class ResultHandler
{
/**
* result that was most recently sent to the app
*/
private MXPResult returnedResult;
private ArrayList<MXPResult> results = new ArrayList<MXPResult>();
/**
* constructor
*/
public ResultHandler()
{
returnedResult = null;
}
public MXPResult createError(String error)
{
MXPResult res = new MXPResult();
res.type = -1;
res.data = error;
return res;
}
public void addToList(MXPResult res)
{
if (res!=null)
{
results.add(res);
}
}
public MXPResult createText(String t)
{
MXPResult res = new MXPResult();
res.type = 1;
res.data = t;
return res;
}
public MXPResult createWarning(String string)
{
MXPResult res = new MXPResult();
res.type = -2;
res.data = string;
return res;
}
public MXPResult createVariable(String varName, String varValue, boolean erase)
{
MXPResult res = new MXPResult();
res.type = 4;
varStruct vs = new varStruct();
vs.name = varName;
vs.value = varValue;
vs.erase = erase;
res.data = vs;
return res;
}
public void deleteResult(MXPResult res)
{
if (res == null)
return;
res.data = null;
res = null;
}
public MXPResult createSendThis(String text)
{
MXPResult res = new MXPResult();
res.type = 9;
res.data = text;
return res;
}
public MXPResult createFlag(boolean begin, String flag)
{
MXPResult res = new MXPResult();
res.type = 3;
flagStruct fs = new flagStruct();
fs.begin = begin;
fs.name = flag;
res.data = fs;
return res;
}
public MXPResult createFormatting(int usemask, int curattrib,
Color fgcolor, Color bgcolor, String font, int cursize)
{
MXPResult res = new MXPResult();
res.type = 5;
formatStruct fs = new formatStruct();
fs.usemask = usemask;
fs.attributes = curattrib;
fs.fg = fgcolor;
fs.bg = bgcolor;
fs.size = cursize;
fs.font = font;
res.data = fs;
return res;
}
public MXPResult createSetWindow(String curWindow)
{
MXPResult res = new MXPResult();
res.type = 15;
res.data = curWindow;
return res;
}
public MXPResult createLink(String name, String url, String text,
String hint)
{
MXPResult res = new MXPResult();
res.type = 6;
linkStruct ls = new linkStruct();
ls.name = name;
ls.url = url;
ls.text = text;
ls.hint = hint;
res.data = ls;
return res;
}
public MXPResult createSendLink(String name, String cmd, String text,
String hint, boolean prompt, boolean menu)
{
MXPResult res = new MXPResult();
res.type = 7;
SendStruct ss = new SendStruct();
ss.name = name;
ss.command = cmd;
ss.text = text;
ss.hint = hint;
ss.toprompt = prompt;
ss.ismenu = menu;
res.data = ss;
return res;
}
public MXPResult createExpire(String name)
{
MXPResult res = new MXPResult();
res.type = 8;
res.data = name;
return res;
}
public MXPResult createHorizLine()
{
MXPResult res = new MXPResult();
res.type = 10;
res.data = null;
return res;
}
public MXPResult createSound(boolean isSOUND, String fname, int vol, int count,
int priority, boolean contifrereq, String type, String url)
{
MXPResult res = new MXPResult();
res.type = 11;
soundStruct ss = new soundStruct();
ss.fname = fname;
ss.type = type;
ss.url = url;
ss.isSOUND = isSOUND;
ss.vol = vol;
ss.repeats = count;
ss.priority = priority;
ss.continuemusic = contifrereq;
res.data = ss;
return res;
}
public MXPResult createGauge(String variable, String maxvariable,
String caption, Color color)
{
MXPResult res = new MXPResult();
res.type = 22;
gaugeStruct gs = new gaugeStruct();
gs.variable = variable;
gs.maxvariable = maxvariable;
gs.caption = caption;
gs.color = color;
res.data = gs;
return res;
}
public MXPResult createMoveCursor(int x, int y)
{
MXPResult res = new MXPResult();
res.type = 16;
moveStruct ms = new moveStruct();
ms.x = x;
ms.y = y;
res.data = ms;
return res;
}
public MXPResult createEraseText(boolean feof)
{
MXPResult res = new MXPResult();
res.type = 17;
res.data = feof;
return res;
}
public MXPResult createStat(String variable, String maxvariable, String caption)
{
MXPResult res = new MXPResult();
res.type = 23;
statStruct ss = new statStruct();
ss.variable = variable;
ss.maxvariable = maxvariable;
ss.caption = caption;
res.data = ss;
return res;
}
public MXPResult createInternalWindow(String nm, String tt, alignType at,
boolean scrolling)
{
MXPResult res = new MXPResult();
res.type = 13;
internalWindowStruct ws = new internalWindowStruct();
ws.name = nm;
ws.align = at;
ws.scrolling = scrolling;
res.data = ws;
return res;
}
public MXPResult createWindow(String nm, String tt, int left, int top,
int width, int height, boolean scrolling, boolean floating)
{
MXPResult res = new MXPResult();
res.type = 12;
windowStruct ws = new windowStruct();
ws.name = nm;
ws.title = tt;
ws.left = left;
ws.top = top;
ws.width = width;
ws.height = height;
ws.scrolling = scrolling;
ws.floating = floating;
res.data = ws;
return res;
}
public MXPResult createCloseWindow(String nm)
{
MXPResult res = new MXPResult();
res.type = 14;
res.data = nm;
return res;
}
public MXPResult createRelocate(String hostname, int port)
{
MXPResult res = new MXPResult();
res.type = 18;
relocateStruct rs = new relocateStruct();
rs.server = hostname;
rs.port = port;
res.data = rs;
return res;
}
public MXPResult createSendLogin(boolean username)
{
MXPResult res = new MXPResult();
res.type = 19;
res.data = (Boolean)username;
return res;
}
public MXPResult createImageMap(String lastcmd)
{
MXPResult res = new MXPResult();
res.type = 21;
res.data = lastcmd;
return res;
}
public MXPResult createImage(String fname, String url, String type,
int height, int width, int hspace, int vspace, alignType at)
{
MXPResult res = new MXPResult();
res.type = 20;
imageStruct is = new imageStruct();
is.fname = fname;
is.url = url;
is.type = type;
is.height = height;
is.width = width;
is.hspace = hspace;
is.vspace = vspace;
is.align = at;
res.data = is;
return res;
}
public MXPResult createLineTag(int number)
{
MXPResult res = new MXPResult();
res.type = 2;
res.data = number;
return res;
}
public boolean haveResults()
{
return results.size() > 0;
}
public MXPResult nextResult()
{
returnedResult = results.get(0);
results.remove(0);
return returnedResult;
}
}
//----------------------------------------------------------------------------------------------------
private class MXPState
{
//initial LOCKED state?
boolean initiallyLocked;
// currently implemented MXP version
String mxpVersion;
String clientName, clientVersion;
int Hattribs[] = new int[6];
Color Hfg[] = new Color[6], Hbg[] = new Color[6];
String Hfont [] = new String[6];
int Hsize[] = new int[6];
int defaultsize;
String ttFont;
/** list of existing frames */
HashMap<String, Boolean> frames = new HashMap<String, Boolean>();
//screen and font parameters
int sX, sY; // width/height of the screen
int wX, wY; // width/height of the output window
int fX, fY; // width/height of character X
//user-defined values
Color defaultfg, defaultbg;
String defaultfont;
int defaultattribs;
Color gaugeColor;
/**
* current mode
*/
private mxpMode mode;
private ResultHandler results;
private ElementManager elements;
private EntityManager entities;
/** temporary secure mode? */
private boolean tempMode;
/** did we just leave secure mode?*/
private boolean wasSecureMode;
//variables
private boolean inVar;
/** current default mode */
private mxpMode defaultmode;
private String varName, varValue;
//links
private boolean inLink, isALink;
private String linkText;
/** list of closing tags */
private ArrayList<closingTag> closingTags = new ArrayList<closingTag>();
//text attributes
private boolean bold, italic, underline, strikeout;
private Color fgcolor, bgcolor;
private String curfont;
private int cursize;
//paragraphs
private boolean inParagraph; //in P tag; no method returns this
private boolean ignoreNextNewLine; //after NOBR; no method returns this
private String lastcmd;
private boolean gotmap;
//current window
private String curWindow, prevWindow;
//SUPPORTS stuff...
private boolean suplink, supgauge, supstatus, supsound, supframe, supimage, suprelocate;
private class closingTag
{
//tag name (lowercase)
String name;
//closing result, if there's exactly one
MXPResult closingresult;
//usually only zero or one element, but sometimes more :-)
List<MXPResult> closingresults;
};
public MXPState(ResultHandler resh, ElementManager elm,
EntityManager enm, String package_name, String version)
{
results = resh;
elements = elm;
entities = enm;
//currently implemented MXP version
mxpVersion = "1.0";
//starting MXP mode is LOCKED, to prevent problems with non-MXP MUDs).
//This goes against the MXP protocol, therefore there's a setting that will keep the OPEN
//mode, if desired - see public API.
mode = mxpMode.lockedMode;
defaultmode = mxpMode.lockedMode;
initiallyLocked = true;
tempMode = false;
wasSecureMode = false;
//some default values...
MXPColors colors = allcolors;
defaultfg = colors.getColor("gray");
defaultbg = colors.getColor("black");
defaultfont = "Courier";
defaultsize = 12;
defaultattribs = 0;
//by default, all headers are written in the same font (Courier), they are bold and they
//differ in sizes...
for (int i = 0; i < 6; i++)
{
Hfont[i] = "Courier";
Hfg[i] = defaultfg;
Hbg[i] = defaultbg;
Hattribs[i] = Bold;
}
Hsize[0] = 32;
Hsize[1] = 24;
Hsize[2] = 20;
Hsize[3] = 16;
Hsize[4] = 14;
Hsize[5] = 12;
ttFont = "Courier";
setDefaultGaugeColor (colors.getColor("white"));
//PACKAGE and VERSION are defined in config.h
clientName = package_name;
clientVersion = version;
//some default screen and font attributes...
fX = 16;
fY = 8;
sX = 800;
sY = 600;
suplink = supgauge = supstatus = supframe = supimage = suprelocate = false;
//params
reset();
}
private void reset()
{
bold = (defaultattribs & Bold) != 0;
italic = (defaultattribs & Italic) != 0;
underline = (defaultattribs & Underline) != 0;
strikeout = (defaultattribs & Strikeout) != 0;
fgcolor = defaultfg;
bgcolor = defaultbg;
curfont = defaultfont;
cursize = defaultsize;
inVar = false;
varValue = "";
inParagraph = false;
ignoreNextNewLine = false;
inLink = false;
isALink = false;
linkText = "";
gotmap = false;
curWindow = "";
prevWindow = "";
}
public void setDefaultGaugeColor(Color color)
{
gaugeColor = color;
}
/**
* return current mode
*/
public mxpMode getMXPMode()
{
return mode;
}
public void gotSUPPORT(List<String> params) throws Exception
{
commonTagHandler();
if (!params.isEmpty()) //some parameters - this is not supported at the moment
results.addToList(results.createWarning (
"Received <support> with parameters, but this isn't supported yet..."));
String res;
res = "\u001b[1z<SUPPORTS +!element +!attlist +!entity +var +b +i +u +s +c +h +font";
res += " +nobr +p +br +sbr +version +support +h1 +h2 +h3 +h4 +h5 +h6 +hr +small +tt";
if (suplink)
res += " +a +send +expire";
if (supgauge)
res += " +gauge";
if (supstatus)
res += " +status";
if (supsound)
res += " +sound +music";
if (supframe)
res += " +frame +dest";
if (supimage)
res += " +image";
if (suprelocate)
res += " +relocate +user +password";
res += ">\r\n";
results.addToList (results.createSendThis (res));
commonAfterTagHandler();
}
/** stuff common for all tags */
private void commonTagHandler()
{
//got a new tag - close outstanding entities, if any (unless we're in LOCKED mode)
if (mode != mxpMode.lockedMode)
{
String t = entities.expandEntities ("", true);
if (!(t.isEmpty()))
gotText(t, false);
}
//outstanding tags are closed, if we're going out of secure mode, unless a change back to secure
//mode occurs
if (wasSecureMode)
{
closeAllTags ();
wasSecureMode = false;
}
//error is reported, if we're inside VAR...
if (inVar)
results.addToList (results.createError ("Got a tag inside a variable!"));
}
public void gotText (String text, boolean expandentities)
{
if (text.isEmpty())
return;
//temp-secure mode . ERROR!
if (tempMode)
{
tempMode = false;
mode = defaultmode;
results.addToList (results.createError ("Temp-secure line tag not followed by a tag!"));
}
//outstanding tags are closed, if we're going out of secure mode, unless a change back to secure
//mode occurs
if (wasSecureMode)
{
closeAllTags ();
wasSecureMode = false;
}
//expand entities, if needed
String t;
if (expandentities && (mode != mxpMode.lockedMode))
t = entities.expandEntities (text, false);
else
t = text;
//special handling if we're in a variable or a link
if (inVar)
varValue += t;
if (inLink)
linkText += t;
//text can be sent is it's not a part of a link or of a variable
if (!(inVar || inLink))
//add text to the list of things to send
results.addToList (results.createText(t));
}
private void closeAllTags()
{
if (closingTags.isEmpty())
return;
//process open tags one by one...
while (!closingTags.isEmpty())
{
//closingTags is a FIFO queue, tho technically it's a list
int last = closingTags.size()-1;
closingTag tag = closingTags.get(last);
closingTags.remove(last);
results.addToList (results.createWarning ("Had to auto-close tag " + tag.name + "."));
closeTag(tag);
}
}
private void closeTag(closingTag tag)
{
//some tags need special handling...
if (tag.name.equals("p"))
{
inParagraph = false;
ignoreNextNewLine = false;
//also send a newline after end of paragraph... MXP docs say nothing about this :(
results.addToList (results.createText ("\r\n"));
}
if (tag.name.equals("var"))
{
tag.closingresult = null;
tag.closingresults = null;
results.addToList (results.createVariable (varName, varValue, false));
results.addToList (results.createText (varName + ": " + varValue));
entities.addEntity (varName, varValue);
inVar = false;
varName = "";
varValue = "";
}
if (tag.name.equals("a"))
{
if (inLink && isALink)
{
linkStruct ls = (linkStruct)tag.closingresult.data;
//assign text, using URL if no text given
String lt = linkText.isEmpty() ? (ls.url != null ? ls.url : "") : linkText;
lt = stripANSI (lt);
ls.text = lt;
}
else
//this should never happen
results.addToList (results.createError ("Received </A> tag, but I'm not in a link!"));
linkText = "";
inLink = false;
isALink = false;
}
if (tag.name.equals("send"))
{
if (gotmap)
{
//don't send this closing result
results.deleteResult (tag.closingresult);
tag.closingresult = null;
if (!linkText.isEmpty())
results.addToList (results.createError
("Received image map and a command in one SEND tag!"));
}
else if (inLink && (!isALink))
{
SendStruct ss = (SendStruct) tag.closingresult.data;
//assign text, also assign to command if none given
//assign linkText to ss.text
linkText = stripANSI (linkText);
ss.text = linkText;
if (ss.hint != null )
{
//expand &text; in hint
String hint = ss.hint;
boolean found = true, havematch = false;
while (found)
{
hint = hint.replaceFirst("&text;", linkText);
if ( hint.indexOf("&text;") < 0 ) found = false; //no more matches
}
if (havematch) //apply changes if needed
{
//assign hint to ss.hint
ss.hint = hint;
}
}
if (!ss.command.isEmpty())
{
String cmd = ss.command;
//also expand &text; in href
boolean found = true, havematch = false;
while (found)
{
if ( cmd.indexOf("&text;") > 0 )
{
cmd = cmd.replace("&text;", linkText);
havematch = true;
}
else
found = false; //no more matches
}
if (havematch) //apply changes if needed
{
//assign cmd to ss.command
ss.command = cmd;
}
}
else if (!linkText.isEmpty())
{
//assign linkText to ss.command
ss.command = linkText;
}
}
else
//this should never happen
results.addToList (results.createError ("Received </SEND> tag, but I'm not in a link!"));
linkText = "";
inLink = false;
isALink = false;
gotmap = false;
}
//handle applying/sending of closing results, is any
if (tag.closingresult!=null)
{
//apply result, reverting changes made by opening tag
applyResult(tag.closingresult);
//and send the changes to the client app
results.addToList (tag.closingresult);
}
if (tag.closingresults!=null)
{
//the same for remaining closing tags...
for (MXPResult item : tag.closingresults)
{
applyResult(item);
results.addToList(item);
}
}
//finally, the closing tag gets deleted
//note that this won't delete the results themselves - they will be deleted after
//they are processed by the client app
tag.closingresults = null;
tag = null;
}
private String stripANSI (String s)
{
// first of all, find out whether there are any ANSI sequences
boolean ansi = false;
for (int i = 0; i < s.length(); ++i)
if (s.charAt(i) == 27) ansi = true;
if (!ansi) return s;
// there are ANSI sequences - have to get rid of them
String res = "";
ansi = false;
for (int i = 0; i < s.length(); ++i) {
if (!ansi) {
if (s.charAt(i) == 27)
ansi = true;
else
res += s.charAt(i);
} else {
// ANSI seq is ended by a-z,A-Z
if ( Character.isLetter(s.charAt(i)) )
ansi = false;
}
}
return res;
}
private void applyResult (MXPResult what)
{
switch (what.type) {
case 5: {
formatStruct fs = (formatStruct) what.data;
int usemask = fs.usemask;
if ((usemask & formatStruct.USE_BOLD) != 0 )
bold = (fs.attributes & Bold) != 0;
if ((usemask & formatStruct.USE_ITALICS) != 0 )
italic = (fs.attributes & Italic) != 0;
if ((usemask & formatStruct.USE_UNDERLINE) != 0 )
underline = (fs.attributes & Underline) != 0;
if ((usemask & formatStruct.USE_STRIKEOUT) != 0 )
strikeout = (fs.attributes & Strikeout) != 0;
if ((usemask & formatStruct.USE_FG) != 0 )
fgcolor = fs.fg;
if ((usemask & formatStruct.USE_BG) != 0 )
bgcolor = fs.bg;
if ((usemask & formatStruct.USE_FONT) != 0 )
curfont = fs.font;
if ((usemask & formatStruct.USE_SIZE) != 0 )
cursize = fs.size;
break;
}
case 15:
{
prevWindow = curWindow;
if (what.data != null)
curWindow = (String)what.data;
else
curWindow = "";
break;
}
};
}
private void commonAfterTagHandler()
{
//secure mode for one tag?
if (tempMode)
{
tempMode = false;
//set mode back to default mode
mode = defaultmode;
}
}
public void gotClosingTag(String name)
{
String nm = name.toLowerCase();
//hack, to prevent an error from being reported when </var> or end-of-flag comes
//we cannot simply test for </var> and friends and disable it then, because
//we could have the var tag inside some element
boolean oldInVar = inVar;
inVar = false;
commonTagHandler();
//restore the inVar variable...
inVar = oldInVar;
boolean okay = false;
while (!okay)
{
if (closingTags.isEmpty())
break; //last one closed...
//closingTags is a FIFO queue, tho technically it's a list
int last = closingTags.size()-1;
closingTag tag = closingTags.get(last);
closingTags.remove(last);
if (tag.name.equals(nm))
okay = true; //good
else
results.addToList (results.createWarning ("Had to auto-close tag " + tag.name +
", because closing tag </" + name + "> was received."));
closeTag (tag);
}
if (!okay)
results.addToList (results.createError ("Received unpaired closing tag </" + name + ">."));
commonAfterTagHandler();
}
//we treat flag as another tag - this is needed to allow correct flag closing even if the //appropriate closing tag wasn't sent by the MUD (auto-closing of flag)
public void gotFlag(boolean begin, String flag)
{
boolean setFlag = false; //is this a set-variable flag?
String f = flag.toLowerCase();
if ( f.indexOf("set ") == 0 )
setFlag = true;
//disable inVar and remember old value, if this is a set-flag
//this is needed to prevent error report in commonTagHandler()
boolean oldInVar = inVar;
if (setFlag) inVar = false;
commonTagHandler();
//restore inVar value
inVar = oldInVar;
//no -> inform about the flag
if (begin)
{
MXPResult res = results.createFlag (true, flag);
MXPResult res2 = createClosingResult (res);
results.addToList (res);
addClosingTag ("flag", res2, null);
//"set xxx" type of flag?
if (setFlag)
{
if (inVar) //in variable already
{
results.addToList (results.createError
("Got a set-flag, but I'm already in a variable definition!"));
return;
}
//we are now in a variable
inVar = true;
varName = f.substring(f.lastIndexOf(' ') + 1); //last word
varValue = "";
}
}
else
{
//closing set-flag...
if (inVar && setFlag)
{
results.addToList (results.createVariable (varName, varValue, false));
//send variable value, but no varname as in </var>
results.addToList (results.createText (varValue));
entities.addEntity (varName, varValue);
inVar = false;
varName = "";
varValue = "";
}
gotClosingTag ("flag");
}
//no commonAfterTagHandler() here - this ain't no real tag :D
}
//mxpResult handling
MXPResult createClosingResult (MXPResult what)
{
MXPResult res = null;
switch (what.type)
{
case 3:
{
flagStruct fs = (flagStruct) what.data;
res = results.createFlag (false, fs.name);
break;
}
case 5:
{
formatStruct fs = (formatStruct)what.data;
//usemask is the most relevant thing here - things not enabled there won't be applied,
//so we can place anything there
int usemask = fs.usemask;
int curattrib = (bold?1:0) * Bold + (italic?1:0) * Italic +
(underline?1:0) * Underline + (strikeout?1:0) * Strikeout;
String font = "";
if ( (usemask & formatStruct.USE_FONT) != 0 )
font = curfont;
res = results.createFormatting (usemask, curattrib, fgcolor, bgcolor, font, cursize);
break;
}
case 15: {
res = results.createSetWindow (curWindow);
break;
}
};
return res;
}
private void addClosingTag(String name, MXPResult res, List<MXPResult> res2)
{
closingTag ctag = new closingTag();
ctag.name = name;
ctag.closingresult = res;
ctag.closingresults = res2;
closingTags.add(ctag);
}
public void gotVariable(String name, String string, boolean b)
{
commonTagHandler();
//send the variable value
results.addToList(results.createVariable (name, string, b));
commonAfterTagHandler();
}
/**
* called upon the VAR tag
*/
public void gotVAR(String name)
{
commonTagHandler();
if (inVar)
{
results.addToList (results.createError ("Nested VAR tags are not allowed!"));
commonAfterTagHandler();
return;
}
//we are now in a variable
inVar = true;
varName = name;
varValue = "";
//create a closing result; the variable name shall be updated when the tag will be closed
addClosingTag("var", null, null);
commonAfterTagHandler();
}
public void gotBOLD()
{
commonTagHandler();
MXPResult res = results.createFormatting(formatStruct.USE_BOLD, Bold,
allcolors.noColor(), allcolors.noColor(), "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("b", res2, null);
commonAfterTagHandler();
}
public void gotITALIC()
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_ITALICS, Italic,
allcolors.noColor(), allcolors.noColor(), "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("i", res2, null);
commonAfterTagHandler();
}
public void gotUNDERLINE()
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_UNDERLINE, Underline,
allcolors.noColor(), allcolors.noColor(), "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("u", res2, null);
commonAfterTagHandler();
}
public void gotSTRIKEOUT()
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_STRIKEOUT, Strikeout,
allcolors.noColor(),
allcolors.noColor(), "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("s", res2, null);
commonAfterTagHandler();
}
public Color bgColor()
{
return bgcolor;
}
public Color fgColor()
{
return fgcolor;
}
public void gotCOLOR(Color fg, Color bg)
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_FG | formatStruct.USE_BG,
0, fg, bg, "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("c", res2, null);
commonAfterTagHandler();
}
public void gotHIGH()
{
commonTagHandler();
Color color = fgcolor;
//High color is computed by adding 128 to each attribute...
//This is a very primitive way of doing it, and it's probably insufficient. We'll see.
int r,g,b;
r = (color.getRed() < 128) ? (color.getRed() + 128) : 255;
g = (color.getGreen() < 128) ? (color.getGreen() + 128) : 255;
b = (color.getBlue() < 128) ? (color.getBlue() + 128) : 255;
color = new Color(r,g,b);
MXPResult res = results.createFormatting (formatStruct.USE_FG, 0,
color, allcolors.noColor(), "", 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("h", res2, null);
commonAfterTagHandler();
}
public String fontFace()
{
return curfont;
}
public int fontSize()
{
return cursize;
}
public void gotFONT(String face, int size, Color fg, Color bg)
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_FG | formatStruct.USE_BG |
formatStruct.USE_FONT | formatStruct.USE_SIZE, 0, fg, bg,
face, size);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("font", res2, null);
commonAfterTagHandler();
}
public void gotP()
{
commonTagHandler();
//we're now in a paragraph
inParagraph = true;
addClosingTag ("p", null, null);
//no reporting to the client
commonAfterTagHandler();
}
public void gotBR() {
commonTagHandler();
//inform the client that we got a newline (but no mode changes shall occur)
results.addToList (results.createText ("\r\n"));
commonAfterTagHandler();
}
public void gotNOBR() {
commonTagHandler();
//next new-line is to be ignored
ignoreNextNewLine = true;
//no reporting to client
commonAfterTagHandler();
}
public void gotSBR() {
commonTagHandler();
//soft-break is represented as 0x1F
results.addToList (results.createText ("\u001f"));
commonAfterTagHandler();
}
public void gotA(String href, String hint, String expire) {
commonTagHandler();
inLink = true;
isALink = true;
linkText = "";
MXPResult res = results.createLink (expire, href, "", hint);
addClosingTag ("a", res, null);
commonAfterTagHandler();
}
public void gotSEND(String command, String hint, boolean prompt, String expire)
{
commonTagHandler();
inLink = true;
isALink = false;
linkText = "";
gotmap = false;
String cmd = stripANSI (command);
lastcmd = cmd;
MXPResult res = results.createSendLink (expire, cmd, "", hint, prompt,
(command.indexOf("|") < 0) ? false : true);
addClosingTag ("send", res, null);
commonAfterTagHandler();
}
public void gotEXPIRE(String name)
{
commonTagHandler();
results.addToList (results.createExpire(name));
commonAfterTagHandler();
}
public void gotVERSION()
{
commonTagHandler();
//this is to be sent...
results.addToList (results.createSendThis ("\u001b[1z<VERSION MXP=" + mxpVersion + " CLIENT=" +
clientName + " VERSION=" + clientVersion + ">\r\n"));
commonAfterTagHandler();
}
public void gotHtag(int which)
{
if ((which < 1) || (which > 6)) //BUG!!!
{
commonAfterTagHandler();
return;
}
commonTagHandler();
int idx = which - 1;
MXPResult res = results.createFormatting (formatStruct.USE_ALL, Hattribs[idx], Hfg[idx], Hbg[idx],
Hfont[idx], Hsize[idx]);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
String ct = "h" + (idx+1);
addClosingTag (ct, res2, null);
commonAfterTagHandler();
}
public void gotHR()
{
commonTagHandler();
results.addToList (results.createHorizLine ());
commonAfterTagHandler();
}
public void gotSMALL()
{
commonTagHandler();
//SMALL means 3/4 of standard size :)
MXPResult res = results.createFormatting (formatStruct.USE_SIZE, 0, allcolors.noColor(),
allcolors.noColor(), "", defaultsize * 3/4);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("small", res2, null);
commonAfterTagHandler();
}
public void gotTT()
{
commonTagHandler();
MXPResult res = results.createFormatting (formatStruct.USE_FONT, 0,
allcolors.noColor(), allcolors.noColor(), ttFont, 0);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
addClosingTag ("tt", res2, null);
commonAfterTagHandler();
}
public void gotSOUND(String fname, int vol, int count, int priority, String type, String url)
{
commonTagHandler();
results.addToList (results.createSound (true, fname, vol, count, priority, false, type, url));
commonAfterTagHandler();
}
public void gotMUSIC(String fname, int vol, int count, boolean contifrereq, String type,
String url)
{
commonTagHandler();
results.addToList (results.createSound (false, fname, vol, count, 0, contifrereq, type, url));
commonAfterTagHandler();
}
public void gotGAUGE(String entity, String maxentity, String caption, Color color)
{
commonTagHandler();
results.addToList (results.createGauge (entity, maxentity, caption, color));
commonAfterTagHandler();
}
public void gotDEST(String name, int x, int y, boolean feol, boolean feof)
{
commonTagHandler();
String nm = name.toLowerCase();
boolean nmExists = (frames.containsKey(nm));
if (!nmExists)
{
results.addToList(results.createError(
"Received a request to redirect to non-existing window " + nm));
return;
}
MXPResult res = results.createSetWindow(name);
MXPResult res2 = createClosingResult (res);
applyResult (res);
results.addToList (res);
int _x = x;
int _y = y;
if ((y >= 0) && (x < 0)) _x = 0;
if ((_x >= 0) && (_y >= 0))
results.addToList (results.createMoveCursor (_x, _y));
List<MXPResult> ls = null;
//erase AFTER displaying text
if (feol || feof)
{
ls = new ArrayList<MXPResult>();
ls.add(res2);
res2 = results.createEraseText(feof);
}
//closing tag...
addClosingTag ("dest", res2, ls);
commonAfterTagHandler();
}
public void gotSTAT(String entity, String max, String caption)
{
commonTagHandler();
results.addToList (results.createStat(entity, max, caption));
commonAfterTagHandler();
}
public int computeCoord(String coord, boolean isX, boolean inWindow )
{
int retval = Integer.parseInt(coord);
int len = coord.length();
char ch = coord.charAt(len - 1);
if (ch == 'c') retval *= (isX ? fX : fY);
if (ch == '%') retval = retval * (inWindow ? (isX ? wX : wY) : (isX ? sX : sY)) / 100;
return retval;
}
public void gotFRAME(String name, String action, String title,
boolean internal, String align, int left, int top, int width,
int height, boolean scrolling, boolean floating) {
commonTagHandler();
if (name.isEmpty())
{
results.addToList (results.createError ("Got FRAME tag without frame name!"));
commonAfterTagHandler();
return;
}
String nm = name.toLowerCase();
String act = action.toLowerCase();
String alg = align.toLowerCase();
String tt = title;
//name is the default title
if (tt.isEmpty())
tt = name;
//align
alignType at = alignType.Top;
if (!align.isEmpty())
{
boolean alignok = false;
if (align.equals("left")) { at = alignType.Left; alignok = true; }
if (align.equals("right")) { at = alignType.Right; alignok = true; }
if (align.equals("top")) { at = alignType.Top; alignok = true; }
if (align.equals("bottom")) { at = alignType.Bottom; alignok = true; }
if (!alignok)
results.addToList (results.createError ("Received FRAME tag with unknown ALIGN option!"));
}
//does the list of frames contain frame with name nm?
boolean nmExists = frames.containsKey(nm);
if (act.equals("open"))
{
if (nmExists)
{
results.addToList (results.createError ("Received request to create an existing frame!"));
commonAfterTagHandler();
return;
}
//cannot create _top or _previous
if ((nm.equals("_top")) || (nm.equals("_previous")))
{
results.addToList (results.createError ("Received request to create a frame with name " +
nm + ", which is invalid!"));
commonAfterTagHandler();
return;
}
if (internal)
{
//false for internal windows... value not used as of now, but it may be used later...
frames.put(nm, false);
results.addToList (results.createInternalWindow (nm, tt, at, scrolling));
}
else
{
//true for normal windows... value not used as of now, but it may be used later...
frames.put(nm, true);
results.addToList (results.createWindow (nm, tt, left, top, width, height,
scrolling, floating));
}
}
if (act.equals("close"))
{
if (nmExists)
{
frames.remove(nm);
results.addToList (results.createCloseWindow (nm));
}
else
results.addToList (results.createError
("Received request to close a non-existing frame!"));
}
if (act.equals("redirect"))
{
//if the frame exists, or if the name is either _top or _previous, we redirect to that window
if ((nm.equals("_top")) || (nm.equals("_previous")) || nmExists)
redirectTo (nm);
else
{
//create that window
if (internal)
{
//false for internal windows... value not used as of now, but it may be used later...
frames.put(nm,false);
results.addToList (results.createInternalWindow (nm, tt, at, scrolling));
}
else
{
//true for normal windows... value not used as of now, but it may be used later...
frames.put(nm,true);
results.addToList (results.createWindow (nm, tt, left, top, width, height,
scrolling, floating));
}
//then redirect to it
redirectTo (nm);
}
}
commonAfterTagHandler();
}
private void redirectTo(String nm)
{
nm = nm.toLowerCase();
String emptystring = "";
MXPResult res = null;
if (nm.equals("_top"))
res = results.createSetWindow(emptystring);
else
if (nm.equals("_previous"))
res = results.createSetWindow (prevWindow);
else
if (frames.containsKey(nm))
res = results.createSetWindow (nm);
else
res = results.createError ("Received request to redirect to non-existing window " + nm);
//apply result - will update info about previous window and so...
applyResult (res);
results.addToList (res);
}
public void gotRELOCATE(String hostname, int port)
{
commonTagHandler();
results.addToList (results.createRelocate (hostname, port));
commonAfterTagHandler();
}
public void gotUSER()
{
commonTagHandler();
results.addToList (results.createSendLogin (true));
commonAfterTagHandler();
}
public void gotPASSWORD()
{
commonTagHandler();
results.addToList (results.createSendLogin (false));
commonAfterTagHandler();
}
public void gotIMAGE(String fname, String url, String type, int height, int width,
int hspace, int vspace, String align, boolean ismap)
{
commonTagHandler();
//align
String alg = align.toLowerCase();
alignType at = alignType.Top;
if (!align.isEmpty())
{
boolean alignok = false;
if (align.equals("left")) { at = alignType.Left; alignok = true; }
if (align.equals("right")) { at = alignType.Right; alignok = true; }
if (align.equals("top")) { at = alignType.Top; alignok = true; }
if (align.equals("bottom")) { at = alignType.Bottom; alignok = true; }
if (align.equals("middle")) { at = alignType.Middle; alignok = true; }
if (!alignok)
results.addToList (results.createError ("Received IMAGE tag with unknown ALIGN option!"));
}
if (gotmap)
results.addToList (results.createError ("Received multiple image maps in one SEND tag!"));
if (ismap)
{
if (inLink && (!isALink))
{
results.addToList (results.createImageMap(lastcmd));
lastcmd = "";
gotmap = true;
}
else
results.addToList (results.createError ("Received an image map with no SEND tag!"));
}
results.addToList (results.createImage (fname, url, type, height, width, hspace, vspace, at));
commonAfterTagHandler();
}
public void gotNewLine()
{
//got a newline char - close outstanding entities, if any (unless we're in LOCKED mode)
if (mode != mxpMode.lockedMode)
{
String t = entities.expandEntities ("", true);
if (!t.isEmpty())
gotText (t, false);
}
//was temp-secure mode?
if (tempMode)
{
tempMode = false;
mode = defaultmode;
results.addToList (results.createError ("Temp-secure line tag followed by a newline!"));
}
//leaving secure mode?
wasSecureMode = false;
if ((mode == mxpMode.secureMode) && (defaultmode != mxpMode.secureMode))
wasSecureMode = true;
//ending line in OPEN mode - close all tags!
if (mode == mxpMode.openMode)
closeAllTags ();
//is we're in SECURE mode, some tags may need to be closed...
//line ended inside a link
if (inLink)
{
inLink = false;
isALink = false;
linkText = "";
results.addToList (results.createError ("Received an unterminated link!"));
}
if (inVar)
{
inVar = false;
results.addToList (results.createError ("Received an unterminated VAR tag!"));
varValue = "";
}
//should next newline be ignored?
if (ignoreNextNewLine)
{
ignoreNextNewLine = false;
return;
}
//if we're in a paragraph, don't report the new-line either
if (inParagraph)
return;
//set mode back to default mode
mode = defaultmode;
//neither NOBR nor P - report newline
results.addToList (results.createText ("\r\n"));
}
public void gotLineTag(int number)
{
//got a line tag - close outstanding entities, if any (unless we're in LOCKED mode)
if (mode != mxpMode.lockedMode)
{
String t = entities.expandEntities ("", true);
if (!t.isEmpty())
gotText (t, false);
}
//leaving secure mode
if (wasSecureMode && (number != 1))
closeAllTags ();
wasSecureMode = false;
if (number < 0) return;
if (number > 99) return;
if (number >= 10)
results.addToList (results.createLineTag(number));
else
{
switch (number) {
case 0:
setMXPMode(mxpMode.openMode);
break;
case 1:
setMXPMode (mxpMode.secureMode);
break;
case 2:
setMXPMode (mxpMode.lockedMode);
break;
case 3:
closeAllTags ();
//default mode remains the same...
setMXPMode (mxpMode.openMode);
reset ();
break;
case 4:
setMXPMode (mxpMode.secureMode);
tempMode = true;
break;
case 5:
setMXPMode (mxpMode.openMode);
defaultmode = mxpMode.openMode;
break;
case 6:
setMXPMode (mxpMode.secureMode);
defaultmode = mxpMode.secureMode;
break;
case 7:
setMXPMode (mxpMode.lockedMode);
defaultmode = mxpMode.lockedMode;
break;
default:
results.addToList (results.createWarning ("Received unrecognized line tag."));
break;
};
}
}
private void setMXPMode(mxpMode m)
{
mode = m;
tempMode = false;
wasSecureMode = false;
//if we start in LOCKED mode and mode change occurs, we set default mode
//to OPEN, so that we are compatible with the spec...
if (initiallyLocked)
{
initiallyLocked = false;
defaultmode = mxpMode.openMode;
}
}
public void setDefaultText(String font, int size, boolean _bold,
boolean _italic, boolean _underline, boolean _strikeout, Color fg,
Color bg)
{
if (curfont == defaultfont) curfont = font;
defaultfont = font;
if (cursize == defaultsize) cursize = size;
defaultsize = size;
int curattrib = (bold?1:0) * Bold + (italic?1:0) * Italic +
(underline?1:0) * Underline + (strikeout?1:0) * Strikeout;
int newattribs = (_bold?1:0) * Bold + (_italic?1:0) * Italic +
(_underline?1:0) * Underline + (_strikeout?1:0) * Strikeout;
if (curattrib == defaultattribs)
{
bold = _bold;
italic = _italic;
underline = _underline;
strikeout = _strikeout;
}
defaultattribs = newattribs;
if (fgcolor == defaultfg) fgcolor = fg;
defaultfg = fg;
if (bgcolor == defaultbg) bgcolor = bg;
defaultbg = bg;
}
public void setHeaderParams(int which, String font, int size,
boolean _bold, boolean _italic, boolean _underline,
boolean _strikeout, Color fg, Color bg)
{
//invalid H-num?
if ((which < 1) || (which > 6))
return;
Hfont[which - 1] = font;
Hsize[which - 1] = size;
int newattribs = (_bold?1:0) * Bold + (_italic?1:0) * Italic +
(_underline?1:0) * Underline + (_strikeout?1:0) * Strikeout;
Hattribs[which - 1] = newattribs;
Hfg[which - 1] = fg;
Hbg[which - 1] = bg;
}
public void setNonProportFont(String font)
{
ttFont = font;
}
public void setClient(String name, String version)
{
clientName = name;
clientVersion = version;
}
public void supportsLink (boolean supports)
{
suplink = supports;
}
public void supportsGauge (boolean supports)
{
supgauge = supports;
}
public void supportsStatus (boolean supports)
{
supstatus = supports;
}
public void supportsSound (boolean supports)
{
supsound = supports;
}
public void supportsFrame (boolean supports)
{
supframe = supports;
}
public void supportsImage (boolean supports)
{
supimage = supports;
}
public void supportsRelocate (boolean supports)
{
suprelocate = supports;
}
public void switchToOpen ()
{
mode = mxpMode.openMode;
defaultmode = mxpMode.openMode;
initiallyLocked = false;
//not we conform to MXP spec... use with care - only affects non-MXP MUDs, where it allows
//open tags - MUDs supporting MXP are NOT affected
}
public void setScreenProps (int sx, int sy, int wx, int wy, int fx, int fy)
{
sX = sx;
sY = sy;
wX = wx;
wY = wy;
fX = fx;
fY = fy;
}
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// Plugin class
private MXPProcessor proc;
public JMXPSingleClass()
{
allcolors = new MXPColors();
proc = new MXPProcessor("MyPlugin", "1.0");
}
public ArrayList<Byte> parseByteArray(ArrayList<Byte> bytes)
{
try{
byte[] array = new byte[bytes.size()];
for(int i=0; i < bytes.size(); i++){
array[i] = bytes.get(i).byteValue();
}
String input = new String(array,"ISO-8859-1"); // may be UTF-8?
proc.processText(input);
// no output
return null;
}
catch(Exception e)
{
e.printStackTrace();
return bytes;
}
}
}