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; } } }