Compare commits
4 Commits
7b5bc7ec11
...
v1.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
6296cf4341
|
|||
|
db6043cb39
|
|||
|
161364a95f
|
|||
|
a56aa5f059
|
+1
-3
@@ -131,9 +131,7 @@ public class TestRunner {
|
||||
summary.printTo(new PrintWriter(System.out));
|
||||
summary.printFailuresTo(new PrintWriter(System.err));
|
||||
|
||||
if (summary.getTotalFailureCount() > 0) {
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(summary.getTotalFailureCount() > 0 ? 1 : 0);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
@@ -145,12 +145,12 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
|
||||
// 3. View menu
|
||||
JMenu viewMenu = createMenu("View");
|
||||
viewMenu.add(createMenuItem("Font Size +", KeyEvent.VK_EQUALS, () -> adjustFontSize(2)));
|
||||
viewMenu.add(createMenuItem("Font Size -", KeyEvent.VK_MINUS, () -> adjustFontSize(-2)));
|
||||
viewMenu.add(createMenuItem("Font Size +", KeyEvent.VK_EQUALS, () -> adjustFontSize(2), true));
|
||||
viewMenu.add(createMenuItem("Font Size -", KeyEvent.VK_MINUS, () -> adjustFontSize(-2), true));
|
||||
viewMenu.add(createMenuItem("Reset Font", KeyEvent.VK_0, () -> {
|
||||
terminalPanel.setFontSize(16);
|
||||
terminalPanel.guardedPack();
|
||||
}));
|
||||
}, true));
|
||||
viewMenu.addSeparator();
|
||||
|
||||
// UI Theme Submenu
|
||||
@@ -178,6 +178,38 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
viewMenu.add(themeMenu);
|
||||
viewMenu.addSeparator();
|
||||
|
||||
JCheckBoxMenuItem rulerItem = new JCheckBoxMenuItem("Crosshair Ruler", terminalPanel.isCrosshairRulerEnabled());
|
||||
ThemeManager.styleMenuItem(rulerItem);
|
||||
rulerItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
|
||||
rulerItem.addActionListener(e -> {
|
||||
boolean en = rulerItem.isSelected();
|
||||
terminalPanel.setCrosshairRulerEnabled(en);
|
||||
haus.nightmare.j3270.config.Settings.setCrosshairRuler(en);
|
||||
});
|
||||
viewMenu.add(rulerItem);
|
||||
|
||||
JMenu cursorMenu = createMenu("Cursor Style");
|
||||
ButtonGroup cursorGroup = new ButtonGroup();
|
||||
JRadioButtonMenuItem blockCursorItem = new JRadioButtonMenuItem("Block Cursor", terminalPanel.getCursorStyle() == TerminalPanel.CursorStyle.BLOCK);
|
||||
ThemeManager.styleMenuItem(blockCursorItem);
|
||||
blockCursorItem.addActionListener(e -> {
|
||||
terminalPanel.setCursorStyle(TerminalPanel.CursorStyle.BLOCK);
|
||||
haus.nightmare.j3270.config.Settings.setCursorStyle("BLOCK");
|
||||
});
|
||||
cursorGroup.add(blockCursorItem);
|
||||
cursorMenu.add(blockCursorItem);
|
||||
|
||||
JRadioButtonMenuItem underlineCursorItem = new JRadioButtonMenuItem("Underline Cursor", terminalPanel.getCursorStyle() == TerminalPanel.CursorStyle.UNDERLINE);
|
||||
ThemeManager.styleMenuItem(underlineCursorItem);
|
||||
underlineCursorItem.addActionListener(e -> {
|
||||
terminalPanel.setCursorStyle(TerminalPanel.CursorStyle.UNDERLINE);
|
||||
haus.nightmare.j3270.config.Settings.setCursorStyle("UNDERLINE");
|
||||
});
|
||||
cursorGroup.add(underlineCursorItem);
|
||||
cursorMenu.add(underlineCursorItem);
|
||||
viewMenu.add(cursorMenu);
|
||||
viewMenu.addSeparator();
|
||||
|
||||
// CodePage Submenu
|
||||
JMenu cpMenu = createMenu("Code Page");
|
||||
String[] codePages = {
|
||||
@@ -234,17 +266,17 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
client.sendEnter();
|
||||
terminalPanel.repaint();
|
||||
}
|
||||
}));
|
||||
}, true));
|
||||
actionsMenu.add(createMenuItem("Clear", KeyEvent.VK_K, () -> {
|
||||
if (client != null)
|
||||
client.sendClear();
|
||||
terminalPanel.repaint();
|
||||
}));
|
||||
}, true));
|
||||
actionsMenu.add(createMenuItem("Reset", KeyEvent.VK_R, () -> {
|
||||
if (client != null)
|
||||
client.reset();
|
||||
terminalPanel.repaint();
|
||||
}));
|
||||
}, true));
|
||||
actionsMenu.add(createMenuItem("Erase Input", KeyEvent.VK_E, () -> {
|
||||
if (client != null && client.getConnectionState().isFullSession()) {
|
||||
client.eraseInput();
|
||||
@@ -272,7 +304,7 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
}, true));
|
||||
actionsMenu.addSeparator();
|
||||
actionsMenu.add(createMenuItem("Run Keystrokes / Script...", -1, this::showScriptDialog));
|
||||
actionsMenu.add(createMenuItem("File Transfer...", KeyEvent.VK_T, this::showFileTransferDialog));
|
||||
actionsMenu.add(createMenuItem("File Transfer...", KeyEvent.VK_T, this::showFileTransferDialog, true));
|
||||
menuBar.add(actionsMenu);
|
||||
|
||||
// 5. Help menu
|
||||
@@ -704,20 +736,21 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
"Delete — Delete character\n" +
|
||||
"Backspace — Backspace\n" +
|
||||
"Insert — Toggle insert mode\n" +
|
||||
"Escape — Reset\n" +
|
||||
"Escape / Alt+R — Reset\n" +
|
||||
"PageUp/Down — PF7/PF8\n" +
|
||||
"Alt+C / Ctrl+K — Clear\n" +
|
||||
"Alt+C / Alt+K — Clear\n" +
|
||||
"Alt+E — Erase Input\n" +
|
||||
"Alt+A — Attention\n" +
|
||||
"Alt+S — System Request\n" +
|
||||
"Alt+Q — Cursor Select\n" +
|
||||
"Alt+L — Toggle Light Pen\n" +
|
||||
"Alt+T — File Transfer\n" +
|
||||
"Alt+Shift+R — Crosshair Ruler\n" +
|
||||
"Alt+=/-/0 — Font size +/-/reset\n" +
|
||||
"Cmd/Ctrl+F — Find on Screen\n" +
|
||||
"Cmd/Ctrl+G / F3— Find Next\n" +
|
||||
"Cmd/Ctrl+T — File Transfer\n" +
|
||||
"Cmd/Ctrl+D — Disconnect\n" +
|
||||
"Cmd/Ctrl+Q — Quit\n" +
|
||||
"Cmd/Ctrl+=/-/0 — Font size +/-/reset";
|
||||
"Cmd/Ctrl+Q — Quit";
|
||||
|
||||
JTextArea area = new JTextArea(text);
|
||||
area.setEditable(false);
|
||||
@@ -893,10 +926,15 @@ public class J3270App extends JFrame implements ConnectionListener, ScreenUpdate
|
||||
}
|
||||
TerminalModel model = TerminalModel.IBM_3279_4;
|
||||
if (remainingArgs.size() >= 3) {
|
||||
try {
|
||||
int modelNum = Integer.parseInt(remainingArgs.get(2));
|
||||
model = TerminalModel.forModel(modelNum, true);
|
||||
} catch (Exception ignored) {}
|
||||
String mArg = remainingArgs.get(2).trim();
|
||||
if (mArg.equalsIgnoreCase("dynamic") || mArg.equals("0")) {
|
||||
model = TerminalModel.IBM_DYNAMIC;
|
||||
} else {
|
||||
try {
|
||||
int modelNum = Integer.parseInt(mArg);
|
||||
model = TerminalModel.forModel(modelNum, true);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
ConnectionConfig config = ConnectionConfig.parseHostString(hostArg, port, model);
|
||||
if (finalTls) {
|
||||
|
||||
@@ -113,6 +113,22 @@ public class Settings {
|
||||
prefs.put("codePage", (codePage != null && !codePage.trim().isEmpty()) ? codePage.trim() : "037");
|
||||
}
|
||||
|
||||
public static int getDynamicRows() {
|
||||
return prefs.getInt("dynamicRows", 62);
|
||||
}
|
||||
|
||||
public static void setDynamicRows(int rows) {
|
||||
prefs.putInt("dynamicRows", Math.max(1, rows));
|
||||
}
|
||||
|
||||
public static int getDynamicCols() {
|
||||
return prefs.getInt("dynamicCols", 160);
|
||||
}
|
||||
|
||||
public static void setDynamicCols(int cols) {
|
||||
prefs.putInt("dynamicCols", Math.max(1, cols));
|
||||
}
|
||||
|
||||
public static Color getColorOverride(int index, Color defaultColor) {
|
||||
String hex = prefs.get("color_" + index, null);
|
||||
try {
|
||||
@@ -233,6 +249,26 @@ public class Settings {
|
||||
prefs.putBoolean("blockSelectMode", block);
|
||||
}
|
||||
|
||||
// ========== Crosshair Ruler ==========
|
||||
|
||||
public static boolean getCrosshairRuler() {
|
||||
return prefs.getBoolean("crosshairRuler", false);
|
||||
}
|
||||
|
||||
public static void setCrosshairRuler(boolean enabled) {
|
||||
prefs.putBoolean("crosshairRuler", enabled);
|
||||
}
|
||||
|
||||
// ========== Cursor Style ==========
|
||||
|
||||
public static String getCursorStyle() {
|
||||
return prefs.get("cursorStyle", "BLOCK");
|
||||
}
|
||||
|
||||
public static void setCursorStyle(String style) {
|
||||
prefs.put("cursorStyle", style != null ? style.toUpperCase() : "BLOCK");
|
||||
}
|
||||
|
||||
private static void applyConfigEntry(String section, String key, String value) {
|
||||
switch (section) {
|
||||
case "appearance":
|
||||
@@ -244,6 +280,13 @@ public class Settings {
|
||||
case "uiTheme":
|
||||
setJavaUiTheme(UITheme.fromString(value));
|
||||
break;
|
||||
case "crosshairRuler":
|
||||
case "ruler":
|
||||
setCrosshairRuler(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "cursorStyle":
|
||||
setCursorStyle(value);
|
||||
break;
|
||||
default:
|
||||
log.warning("Unknown appearance key: " + key);
|
||||
}
|
||||
@@ -284,6 +327,14 @@ public class Settings {
|
||||
case "charset":
|
||||
setCodePage(value);
|
||||
break;
|
||||
case "dynamicRows":
|
||||
case "dynamic_rows":
|
||||
setDynamicRows(Integer.parseInt(value));
|
||||
break;
|
||||
case "dynamicCols":
|
||||
case "dynamic_cols":
|
||||
setDynamicCols(Integer.parseInt(value));
|
||||
break;
|
||||
case "blockSelectMode": setBlockSelectMode(Boolean.parseBoolean(value)); break;
|
||||
default:
|
||||
log.warning("Unknown behavior/connection key: " + key);
|
||||
@@ -340,6 +391,8 @@ public class Settings {
|
||||
w.println("javaUiTheme = " + getJavaUiTheme().name());
|
||||
w.println("fontFamily = " + getFontFamily());
|
||||
w.println("fontSize = " + getFontSize());
|
||||
w.println("crosshairRuler = " + getCrosshairRuler());
|
||||
w.println("cursorStyle = " + getCursorStyle());
|
||||
w.println();
|
||||
|
||||
// [behavior]
|
||||
@@ -354,6 +407,8 @@ public class Settings {
|
||||
w.println("autoConnectTn3270e = " + getAutoConnectTn3270e());
|
||||
}
|
||||
w.println("codePage = " + getCodePage());
|
||||
w.println("dynamicRows = " + getDynamicRows());
|
||||
w.println("dynamicCols = " + getDynamicCols());
|
||||
w.println("blockSelectMode = " + getBlockSelectMode());
|
||||
w.println();
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ public class ConnectDialog extends JDialog {
|
||||
private JTextField hostField;
|
||||
private JTextField portField;
|
||||
private JComboBox<TerminalModel> modelCombo;
|
||||
private JLabel dynamicDimLabel;
|
||||
private JPanel dynamicDimPanel;
|
||||
private JSpinner dynamicRowsSpinner;
|
||||
private JSpinner dynamicColsSpinner;
|
||||
private JComboBox<haus.nightmare.lib3270j.graphics.GraphicsMode> graphicsCombo;
|
||||
private JComboBox<String> codePageCombo;
|
||||
private JTextField luField;
|
||||
@@ -79,10 +83,49 @@ public class ConnectDialog extends JDialog {
|
||||
ThemeManager.styleComboBox(modelCombo);
|
||||
mainPanel.add(modelCombo, gbc);
|
||||
|
||||
// LU Name
|
||||
// Dynamic Dimensions (shown when IBM-DYNAMIC is selected)
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 3;
|
||||
gbc.weightx = 0;
|
||||
dynamicDimLabel = new JLabel("Screen Size:");
|
||||
dynamicDimLabel.setFont(labelFont);
|
||||
mainPanel.add(dynamicDimLabel, gbc);
|
||||
|
||||
gbc.gridx = 1;
|
||||
gbc.weightx = 1.0;
|
||||
dynamicDimPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
|
||||
dynamicDimPanel.setOpaque(false);
|
||||
|
||||
JLabel rowsLabel = new JLabel("Rows:");
|
||||
rowsLabel.setFont(labelFont);
|
||||
dynamicRowsSpinner = new JSpinner(new SpinnerNumberModel(haus.nightmare.j3270.config.Settings.getDynamicRows(), 24, 255, 1));
|
||||
ThemeManager.styleSpinner(dynamicRowsSpinner);
|
||||
|
||||
JLabel colsLabel = new JLabel("Cols:");
|
||||
colsLabel.setFont(labelFont);
|
||||
dynamicColsSpinner = new JSpinner(new SpinnerNumberModel(haus.nightmare.j3270.config.Settings.getDynamicCols(), 80, 255, 1));
|
||||
ThemeManager.styleSpinner(dynamicColsSpinner);
|
||||
|
||||
dynamicDimPanel.add(rowsLabel);
|
||||
dynamicDimPanel.add(dynamicRowsSpinner);
|
||||
dynamicDimPanel.add(colsLabel);
|
||||
dynamicDimPanel.add(dynamicColsSpinner);
|
||||
mainPanel.add(dynamicDimPanel, gbc);
|
||||
|
||||
Runnable updateDynamicVisibility = () -> {
|
||||
TerminalModel m = (TerminalModel) modelCombo.getSelectedItem();
|
||||
boolean isDyn = (m != null && m.isDynamic());
|
||||
dynamicDimLabel.setVisible(isDyn);
|
||||
dynamicDimPanel.setVisible(isDyn);
|
||||
pack();
|
||||
};
|
||||
modelCombo.addActionListener(e -> updateDynamicVisibility.run());
|
||||
updateDynamicVisibility.run();
|
||||
|
||||
// LU Name
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 4;
|
||||
gbc.weightx = 0;
|
||||
JLabel luLabel = new JLabel("LU Name:");
|
||||
luLabel.setFont(labelFont);
|
||||
mainPanel.add(luLabel, gbc);
|
||||
@@ -93,7 +136,7 @@ public class ConnectDialog extends JDialog {
|
||||
|
||||
// Graphics Mode
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 4;
|
||||
gbc.gridy = 5;
|
||||
gbc.weightx = 0;
|
||||
JLabel graphicsLabel = new JLabel("Graphics:");
|
||||
graphicsLabel.setFont(labelFont);
|
||||
@@ -108,7 +151,7 @@ public class ConnectDialog extends JDialog {
|
||||
|
||||
// Code Page
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 5;
|
||||
gbc.gridy = 6;
|
||||
gbc.weightx = 0;
|
||||
JLabel cpLabel = new JLabel("Code Page:");
|
||||
cpLabel.setFont(labelFont);
|
||||
@@ -129,14 +172,27 @@ public class ConnectDialog extends JDialog {
|
||||
"870 - Eastern Europe / Latin-2",
|
||||
"871 - Iceland",
|
||||
"875 - Greece (Greek)",
|
||||
"1026 - Turkey (Turkish)",
|
||||
"1026 - Turkey (Turkish Latin-5)",
|
||||
"1155 - Turkey (Turkish Latin-5 Euro \u20AC)",
|
||||
"905 - Turkey (Turkish Latin-3)",
|
||||
"420 - Arabic Bilingual",
|
||||
"424 - Hebrew (with Lowercase)",
|
||||
"803 - Hebrew Old / Standard",
|
||||
"838 - Thai",
|
||||
"1160 - Thai (Euro \u20AC)",
|
||||
"1025 - Cyrillic Multilingual",
|
||||
"1123 - Cyrillic Ukraine",
|
||||
"1154 - Cyrillic Multilingual (Euro \u20AC)",
|
||||
"880 - Cyrillic Russian",
|
||||
"1140 - US / Canada (Euro \u20AC)",
|
||||
"1141 - Germany / Austria (Euro \u20AC)",
|
||||
"1148 - International (Euro \u20AC)",
|
||||
"930 - Japanese Katakana Mixed DBCS",
|
||||
"939 - Japanese Latin Mixed DBCS",
|
||||
"935 - Simplified Chinese Mixed DBCS",
|
||||
"1388 - Simplified Chinese Extended Mixed DBCS",
|
||||
"937 - Traditional Chinese Mixed DBCS",
|
||||
"1371 - Traditional Chinese Extended Mixed DBCS",
|
||||
"933 - Korean Mixed DBCS"
|
||||
};
|
||||
codePageCombo = new JComboBox<>(commonCodePages);
|
||||
@@ -154,7 +210,7 @@ public class ConnectDialog extends JDialog {
|
||||
|
||||
// TLS / SSL Checkbox
|
||||
gbc.gridx = 1;
|
||||
gbc.gridy = 6;
|
||||
gbc.gridy = 7;
|
||||
gbc.weightx = 1.0;
|
||||
tlsCheckBox = new JCheckBox("Enable TLS/SSL");
|
||||
ThemeManager.styleCheckBox(tlsCheckBox);
|
||||
@@ -173,7 +229,7 @@ public class ConnectDialog extends JDialog {
|
||||
|
||||
// Verify Certificate Checkbox
|
||||
gbc.gridx = 1;
|
||||
gbc.gridy = 7;
|
||||
gbc.gridy = 8;
|
||||
verifyCertCheckBox = new JCheckBox("Verify Server Certificate");
|
||||
ThemeManager.styleCheckBox(verifyCertCheckBox);
|
||||
verifyCertCheckBox.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 13));
|
||||
@@ -183,7 +239,7 @@ public class ConnectDialog extends JDialog {
|
||||
|
||||
// TN3270E Checkbox
|
||||
gbc.gridx = 1;
|
||||
gbc.gridy = 8;
|
||||
gbc.gridy = 9;
|
||||
tn3270eCheckBox = new JCheckBox("Enable TN3270E (Extended 3270)");
|
||||
ThemeManager.styleCheckBox(tn3270eCheckBox);
|
||||
tn3270eCheckBox.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 13));
|
||||
@@ -210,7 +266,7 @@ public class ConnectDialog extends JDialog {
|
||||
buttonPanel.add(connectBtn);
|
||||
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 9;
|
||||
gbc.gridy = 10;
|
||||
gbc.gridwidth = 2;
|
||||
mainPanel.add(buttonPanel, gbc);
|
||||
|
||||
@@ -243,7 +299,15 @@ public class ConnectDialog extends JDialog {
|
||||
return;
|
||||
}
|
||||
|
||||
result = new ConnectionConfig(host, port, (TerminalModel) modelCombo.getSelectedItem());
|
||||
TerminalModel selectedModel = (TerminalModel) modelCombo.getSelectedItem();
|
||||
result = new ConnectionConfig(host, port, selectedModel);
|
||||
if (selectedModel != null && selectedModel.isDynamic()) {
|
||||
int dRows = (Integer) dynamicRowsSpinner.getValue();
|
||||
int dCols = (Integer) dynamicColsSpinner.getValue();
|
||||
result.setDynamicDimensions(dRows, dCols);
|
||||
haus.nightmare.j3270.config.Settings.setDynamicRows(dRows);
|
||||
haus.nightmare.j3270.config.Settings.setDynamicCols(dCols);
|
||||
}
|
||||
String lu = luField.getText().trim();
|
||||
if (!lu.isEmpty()) {
|
||||
result.setLuName(lu);
|
||||
|
||||
@@ -98,19 +98,21 @@ public class ScreenExporter {
|
||||
writer.write("<style>\n");
|
||||
writer.write("body { background-color: #0a0a0a; color: #32cd32; font-family: 'Courier New', Courier, monospace; font-size: 14px; margin: 20px; }\n");
|
||||
writer.write(".screen { background-color: #000; padding: 15px; border-radius: 4px; display: inline-block; box-shadow: 0 0 10px rgba(0,0,0,0.8); line-height: 1.2; }\n");
|
||||
writer.write(".c-blue { color: #5078ff; }\n");
|
||||
writer.write(".c-red { color: #ff3232; }\n");
|
||||
writer.write(".c-pink { color: #ff82b4; }\n");
|
||||
writer.write(".c-green { color: #32cd32; }\n");
|
||||
writer.write(".c-turq { color: #40e0d0; }\n");
|
||||
writer.write(".c-yellow { color: #ffff50; }\n");
|
||||
writer.write(".c-blue { color: #7890f0; }\n");
|
||||
writer.write(".c-red { color: #ff0000; }\n");
|
||||
writer.write(".c-pink { color: #ff00ff; }\n");
|
||||
writer.write(".c-green { color: #00ff00; }\n");
|
||||
writer.write(".c-turq { color: #00ffff; }\n");
|
||||
writer.write(".c-yellow { color: #ffff00; }\n");
|
||||
writer.write(".c-white { color: #ffffff; }\n");
|
||||
writer.write(".c-black { color: #000000; }\n");
|
||||
writer.write(".c-orange { color: #ffa500; }\n");
|
||||
writer.write(".c-purple { color: #b482ff; }\n");
|
||||
writer.write(".c-palegreen { color: #90ee90; }\n");
|
||||
writer.write(".c-paleturq { color: #afeeee; }\n");
|
||||
writer.write(".c-grey { color: #aaaaaa; }\n");
|
||||
writer.write(".c-deepblue { color: #000080; }\n");
|
||||
writer.write(".c-orange { color: #ffa200; }\n");
|
||||
writer.write(".c-purple { color: #800080; }\n");
|
||||
writer.write(".c-palegreen { color: #008000; }\n");
|
||||
writer.write(".c-paleturq { color: #008080; }\n");
|
||||
writer.write(".c-mustard { color: #a0a000; }\n");
|
||||
writer.write(".c-grey { color: #c0c0c0; }\n");
|
||||
writer.write(".bold { font-weight: bold; }\n");
|
||||
writer.write(".underline { text-decoration: underline; }\n");
|
||||
writer.write("</style>\n</head>\n<body>\n<div class=\"screen\"><pre>");
|
||||
@@ -209,17 +211,17 @@ public class ScreenExporter {
|
||||
case 6: return "c-yellow";
|
||||
case 7: return "c-white";
|
||||
case 8: return "c-black";
|
||||
case 9: return "c-blue";
|
||||
case 9: return "c-deepblue";
|
||||
case 10: return "c-orange";
|
||||
case 11: return "c-purple";
|
||||
case 12: return "c-palegreen";
|
||||
case 13: return "c-paleturq";
|
||||
case 14: return "c-grey";
|
||||
case 15: return "c-white";
|
||||
case 14: return "c-mustard";
|
||||
case 15: return "c-grey";
|
||||
}
|
||||
}
|
||||
if (faIsProtected(currentFA & 0xFF)) {
|
||||
return faIsHigh(currentFA & 0xFF) ? "c-white" : "c-blue";
|
||||
return faIsHigh(currentFA & 0xFF) ? "c-white" : "c-turq";
|
||||
}
|
||||
return faIsHigh(currentFA & 0xFF) ? "c-red" : "c-green";
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ public class SettingsDialog extends JDialog {
|
||||
private JTextField hostField;
|
||||
private JTextField portField;
|
||||
private JCheckBox blockSelectCheck;
|
||||
private JSpinner dynamicRowsSpinner;
|
||||
private JSpinner dynamicColsSpinner;
|
||||
|
||||
// Advanced tab state tracking
|
||||
private final Color[] tempHostColors = new Color[16];
|
||||
@@ -235,8 +237,30 @@ public class SettingsDialog extends JDialog {
|
||||
blockSelectCheck = new JCheckBox("Block selection mode (rectangular select)", Settings.getBlockSelectMode());
|
||||
panel.add(blockSelectCheck, gbc);
|
||||
|
||||
// Placeholder for potentially more behavior options below
|
||||
// Default Dynamic Screen Size
|
||||
gbc.gridy = 3;
|
||||
gbc.gridwidth = 1;
|
||||
gbc.gridx = 0;
|
||||
panel.add(new JLabel("Default Dynamic Screen:"), gbc);
|
||||
|
||||
JPanel dynDimPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 6, 0));
|
||||
dynDimPanel.setOpaque(false);
|
||||
dynDimPanel.add(new JLabel("Rows:"));
|
||||
dynamicRowsSpinner = new JSpinner(new SpinnerNumberModel(Settings.getDynamicRows(), 24, 255, 1));
|
||||
ThemeManager.styleSpinner(dynamicRowsSpinner);
|
||||
dynDimPanel.add(dynamicRowsSpinner);
|
||||
dynDimPanel.add(new JLabel("Cols:"));
|
||||
dynamicColsSpinner = new JSpinner(new SpinnerNumberModel(Settings.getDynamicCols(), 80, 255, 1));
|
||||
ThemeManager.styleSpinner(dynamicColsSpinner);
|
||||
dynDimPanel.add(dynamicColsSpinner);
|
||||
|
||||
gbc.gridx = 1;
|
||||
panel.add(dynDimPanel, gbc);
|
||||
|
||||
// Placeholder for potentially more behavior options below
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = 4;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.weighty = 1.0;
|
||||
panel.add(Box.createGlue(), gbc);
|
||||
|
||||
@@ -555,6 +579,12 @@ public class SettingsDialog extends JDialog {
|
||||
// Block select mode
|
||||
Settings.setBlockSelectMode(blockSelectCheck.isSelected());
|
||||
|
||||
// Default Dynamic screen dimensions
|
||||
if (dynamicRowsSpinner != null && dynamicColsSpinner != null) {
|
||||
Settings.setDynamicRows((Integer) dynamicRowsSpinner.getValue());
|
||||
Settings.setDynamicCols((Integer) dynamicColsSpinner.getValue());
|
||||
}
|
||||
|
||||
// Propagate visual changes to the app
|
||||
// Save Colors
|
||||
for (int i=0; i<16; i++) {
|
||||
|
||||
@@ -110,25 +110,25 @@ public class StatusBar extends JPanel {
|
||||
break;
|
||||
case CONNECTED_3270:
|
||||
connectionStatus.setText("TN3270");
|
||||
connectionStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
connectionStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
break;
|
||||
case CONNECTED_TN3270E:
|
||||
connectionStatus.setText("TN3270E");
|
||||
connectionStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
connectionStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
break;
|
||||
case CONNECTED_SSCP:
|
||||
connectionStatus.setText("SSCP-LU");
|
||||
connectionStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
connectionStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
break;
|
||||
case CONNECTED_NVT:
|
||||
case CONNECTED_NVT_CHAR:
|
||||
case CONNECTED_E_NVT:
|
||||
connectionStatus.setText("NVT");
|
||||
connectionStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
connectionStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
break;
|
||||
case CONNECTED_UNBOUND:
|
||||
connectionStatus.setText("Unbound");
|
||||
connectionStatus.setForeground(ThemeManager.getOiaFgWarn(theme));
|
||||
connectionStatus.setForeground(ThemeManager.getOiaAttention());
|
||||
break;
|
||||
default:
|
||||
connectionStatus.setText(state.name());
|
||||
@@ -144,11 +144,11 @@ public class StatusBar extends JPanel {
|
||||
String protocol = session != null ? session.getProtocol() : "TLS";
|
||||
if (verified) {
|
||||
tlsStatus.setText("🔒 TLS");
|
||||
tlsStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
tlsStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
tlsStatus.setToolTipText(protocol + " / " + cipher + " (Verified)");
|
||||
} else {
|
||||
tlsStatus.setText("🔓 TLS (Unverified)");
|
||||
tlsStatus.setForeground(ThemeManager.getOiaFgWarn(theme));
|
||||
tlsStatus.setForeground(ThemeManager.getOiaAttention());
|
||||
tlsStatus.setToolTipText(protocol + " / " + cipher + " (Verification Bypassed)");
|
||||
}
|
||||
} else {
|
||||
@@ -164,38 +164,46 @@ public class StatusBar extends JPanel {
|
||||
lu = "LU:" + client.getConfig().getLuName();
|
||||
}
|
||||
luName.setText(lu);
|
||||
luName.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
luName.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
|
||||
// Lock / Inhibit status
|
||||
int inhibit = client.getOIA().getInputInhibited();
|
||||
if (inhibit != ECLConstants.INHIBIT_NOT_INHIBITED) {
|
||||
Color lockFg = ThemeManager.getOiaInputInhibited(); // White (oII)
|
||||
switch (inhibit) {
|
||||
case ECLConstants.INHIBIT_SYSTEM_LOCK:
|
||||
lockStatus.setText("X SYSTEM");
|
||||
lockFg = ThemeManager.getOiaInputInhibited(); // White (oII)
|
||||
break;
|
||||
case ECLConstants.INHIBIT_COMM_CHECK:
|
||||
lockStatus.setText("X COMM");
|
||||
lockFg = ThemeManager.getOiaCommCheck(); // Red (oEI)
|
||||
break;
|
||||
case ECLConstants.INHIBIT_NUMERIC_ONLY:
|
||||
lockStatus.setText("X NUM");
|
||||
lockFg = ThemeManager.getOiaAttention(); // Yellow (oAI)
|
||||
break;
|
||||
case ECLConstants.INHIBIT_PROTECTED_FIELD:
|
||||
lockStatus.setText("X PROT");
|
||||
lockFg = ThemeManager.getOiaInputInhibited(); // White (oII)
|
||||
break;
|
||||
case ECLConstants.INHIBIT_OVERFLOW:
|
||||
lockStatus.setText("X >");
|
||||
lockFg = ThemeManager.getOiaAttention(); // Yellow (oAI)
|
||||
break;
|
||||
case ECLConstants.INHIBIT_OPERATOR_DUE:
|
||||
lockStatus.setText("X OP");
|
||||
lockFg = ThemeManager.getOiaAttention(); // Yellow (oAI)
|
||||
break;
|
||||
default:
|
||||
lockStatus.setText("X LOCKED");
|
||||
lockFg = ThemeManager.getOiaInputInhibited(); // White (oII)
|
||||
break;
|
||||
}
|
||||
lockStatus.setForeground(ThemeManager.getOiaFgAlert(theme));
|
||||
lockStatus.setForeground(lockFg);
|
||||
} else if (client.getInputProcessor().isInsertMode()) {
|
||||
lockStatus.setText("INSERT");
|
||||
lockStatus.setForeground(ThemeManager.getOiaFgNormal(theme));
|
||||
lockStatus.setForeground(ThemeManager.getOiaStatusSysAvail());
|
||||
} else {
|
||||
lockStatus.setText("");
|
||||
}
|
||||
@@ -223,7 +231,13 @@ public class StatusBar extends JPanel {
|
||||
ScreenBuffer sb = client.getScreenBuffer();
|
||||
int rows = sb.getDisplayRows();
|
||||
int cols = sb.getDisplayCols();
|
||||
modelInfo.setText(client.getConfig().getModel().name().replace('_', '-') + " [" + rows + "x" + cols + "]");
|
||||
String modelName;
|
||||
if (client.getConfig().isDynamicModel() || (client.getConfig().getModel() != null && client.getConfig().getModel().isDynamic())) {
|
||||
modelName = "IBM-DYNAMIC [" + rows + "x" + cols + "]";
|
||||
} else {
|
||||
modelName = client.getConfig().getModel().name().replace('_', '-') + " [" + rows + "x" + cols + "]";
|
||||
}
|
||||
modelInfo.setText(modelName);
|
||||
modelInfo.setForeground(ThemeManager.getOiaFgDim(theme));
|
||||
|
||||
// Cursor position and buffer address
|
||||
|
||||
@@ -57,11 +57,22 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
CHAR_STRINGS[i] = String.valueOf((char) i);
|
||||
}
|
||||
}
|
||||
public enum CursorStyle {
|
||||
BLOCK,
|
||||
UNDERLINE
|
||||
}
|
||||
private CursorStyle cursorStyle = CursorStyle.BLOCK;
|
||||
private static final Color CURSOR_COLOR = new Color(255, 255, 255, 180);
|
||||
private boolean crosshairRulerEnabled = false;
|
||||
private static final Color CROSSHAIR_RULER_COLOR = new Color(0, 255, 0, 102); // 40% alpha (cRC)
|
||||
private boolean textBlinkVisible = true;
|
||||
private Image wallpaperImage = null;
|
||||
private haus.nightmare.lib3270j.graphics.HODWallpaper hodWallpaper = null;
|
||||
|
||||
private int selectionStartRow = -1, selectionStartCol = -1;
|
||||
private int selectionEndRow = -1, selectionEndCol = -1;
|
||||
private boolean isDragging = false;
|
||||
private static final Color SELECTION_COLOR = new Color(75, 110, 175, 100);
|
||||
private static final Color SELECTION_COLOR = new Color(75, 110, 175, 102); // 40% alpha blend
|
||||
|
||||
// ========== Search Highlight state ==========
|
||||
private int searchHighlightAddr = -1;
|
||||
@@ -96,31 +107,31 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
return Math.max(padding, extra / 2);
|
||||
}
|
||||
|
||||
// Default Host color mapping
|
||||
// Default Host color mapping aligned 1:1 with IBM Host On-Demand ColorRemapModel3270
|
||||
public static final Color[] DEFAULT_HOST_COLORS = {
|
||||
new Color(0, 0, 0), // 0: Neutral Black
|
||||
new Color(80, 120, 255), // 1: Blue
|
||||
new Color(255, 50, 50), // 2: Red
|
||||
new Color(255, 130, 180), // 3: Pink
|
||||
new Color(50, 205, 50), // 4: Green
|
||||
new Color(64, 224, 208), // 5: Turquoise
|
||||
new Color(255, 255, 80), // 6: Yellow
|
||||
new Color(120, 144, 240), // 1: Blue (0x7890F0 CUSTOMBLUE)
|
||||
new Color(255, 0, 0), // 2: Red
|
||||
new Color(255, 0, 255), // 3: Pink
|
||||
new Color(0, 255, 0), // 4: Green
|
||||
new Color(0, 255, 255), // 5: Turquoise / Cyan
|
||||
new Color(255, 255, 0), // 6: Yellow
|
||||
new Color(255, 255, 255), // 7: Neutral White
|
||||
new Color(0, 0, 0), // 8: Black
|
||||
new Color(30, 60, 180), // 9: Deep Blue
|
||||
new Color(255, 165, 0), // 10: Orange
|
||||
new Color(180, 130, 255), // 11: Purple
|
||||
new Color(144, 238, 144), // 12: Pale Green
|
||||
new Color(175, 238, 238), // 13: Pale Turquoise
|
||||
new Color(170, 170, 170), // 14: Grey
|
||||
new Color(255, 255, 255), // 15: White
|
||||
new Color(0, 0, 128), // 9: Deep Blue
|
||||
new Color(255, 162, 0), // 10: Orange (0xFFFFA200)
|
||||
new Color(128, 0, 128), // 11: Purple
|
||||
new Color(0, 128, 0), // 12: Pale Green
|
||||
new Color(0, 128, 128), // 13: Pale Turquoise
|
||||
new Color(160, 160, 0), // 14: Mustard (0xFFA0A000)
|
||||
new Color(192, 192, 192), // 15: Grey (0xFFC0C0C0)
|
||||
};
|
||||
|
||||
// Default 3278 monochrome colors
|
||||
public static final Color DEFAULT_MONO_NORMAL = new Color(50, 205, 50);
|
||||
public static final Color DEFAULT_MONO_INTENSIFY = new Color(255, 255, 255);
|
||||
public static final Color DEFAULT_MONO_PROTECTED = new Color(80, 120, 255);
|
||||
public static final Color DEFAULT_MONO_PROTECTED_HIGH = new Color(255, 255, 255);
|
||||
// Default 3278 / base monochrome colors aligned with HoD
|
||||
public static final Color DEFAULT_MONO_NORMAL = new Color(0, 255, 0); // Green
|
||||
public static final Color DEFAULT_MONO_INTENSIFY = new Color(255, 0, 0); // Red
|
||||
public static final Color DEFAULT_MONO_PROTECTED = new Color(0, 255, 255); // Cyan / Turquoise
|
||||
public static final Color DEFAULT_MONO_PROTECTED_HIGH = new Color(255, 255, 255); // White
|
||||
|
||||
// Default Background
|
||||
public static final Color DEFAULT_BG_COLOR = Color.BLACK;
|
||||
@@ -138,6 +149,9 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
setupCursorBlink();
|
||||
|
||||
blockSelectMode = haus.nightmare.j3270.config.Settings.getBlockSelectMode();
|
||||
crosshairRulerEnabled = haus.nightmare.j3270.config.Settings.getCrosshairRuler();
|
||||
String cStyle = haus.nightmare.j3270.config.Settings.getCursorStyle();
|
||||
cursorStyle = "UNDERLINE".equalsIgnoreCase(cStyle) ? CursorStyle.UNDERLINE : CursorStyle.BLOCK;
|
||||
|
||||
// Handle mouse clicks to position cursor, selection, and grab focus
|
||||
MouseAdapter mouseHandler = new MouseAdapter() {
|
||||
@@ -730,6 +744,16 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
}
|
||||
}
|
||||
} else if (e.getID() == KeyEvent.KEY_PRESSED) {
|
||||
if (client.getNvtProcessor() != null && client.getNvtProcessor().isApplicationKeypad()) {
|
||||
String kp = client.getNvtProcessor().mapKeypadKey(e.getKeyCode());
|
||||
if (kp != null) {
|
||||
try {
|
||||
client.sendNVTString(kp);
|
||||
} catch (Exception ignored) {}
|
||||
e.consume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (e.isControlDown() && !e.isAltDown() && !e.isMetaDown()) {
|
||||
int code = e.getKeyCode();
|
||||
if (code >= KeyEvent.VK_A && code <= KeyEvent.VK_Z) {
|
||||
@@ -838,12 +862,20 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
if (client != null && client.getConnectionState().isFullSession()) {
|
||||
if (client.getConnectionState().isNvt()) {
|
||||
try {
|
||||
switch (dir) {
|
||||
case "up": client.sendNVTString("\u001B[A"); break;
|
||||
case "down": client.sendNVTString("\u001B[B"); break;
|
||||
case "left": client.sendNVTString("\u001B[D"); break;
|
||||
case "right": client.sendNVTString("\u001B[C"); break;
|
||||
case "home": client.sendNVTString("\u001B[H"); break;
|
||||
int vk = KeyEvent.VK_UP;
|
||||
if ("down".equals(dir)) vk = KeyEvent.VK_DOWN;
|
||||
else if ("left".equals(dir)) vk = KeyEvent.VK_LEFT;
|
||||
else if ("right".equals(dir)) vk = KeyEvent.VK_RIGHT;
|
||||
else if ("home".equals(dir)) vk = KeyEvent.VK_HOME;
|
||||
boolean handled = client.sendNVTKey(vk, '\0', false, false, false);
|
||||
if (!handled) {
|
||||
switch (dir) {
|
||||
case "up": client.sendNVTString("\u001B[A"); break;
|
||||
case "down": client.sendNVTString("\u001B[B"); break;
|
||||
case "left": client.sendNVTString("\u001B[D"); break;
|
||||
case "right": client.sendNVTString("\u001B[C"); break;
|
||||
case "home": client.sendNVTString("\u001B[H"); break;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return;
|
||||
@@ -863,7 +895,11 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
if (client != null && client.getConnectionState().isFullSession()) {
|
||||
if (client.getConnectionState().isNvt()) {
|
||||
try {
|
||||
client.sendNVTString(getNvtFunctionKeySequence(n));
|
||||
if (client.getNvtProcessor() != null) {
|
||||
client.sendNVTString(client.getNvtProcessor().getFunctionKeySequence(n));
|
||||
} else {
|
||||
client.sendNVTString(getNvtFunctionKeySequence(n));
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return;
|
||||
}
|
||||
@@ -1053,6 +1089,9 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
setupKeyBindings();
|
||||
setupFont();
|
||||
blockSelectMode = haus.nightmare.j3270.config.Settings.getBlockSelectMode();
|
||||
crosshairRulerEnabled = haus.nightmare.j3270.config.Settings.getCrosshairRuler();
|
||||
String cStyle = haus.nightmare.j3270.config.Settings.getCursorStyle();
|
||||
cursorStyle = "UNDERLINE".equalsIgnoreCase(cStyle) ? CursorStyle.UNDERLINE : CursorStyle.BLOCK;
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
@@ -1081,18 +1120,54 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
}
|
||||
|
||||
private void setupCursorBlink() {
|
||||
blinkTimer = new Timer(530, e -> {
|
||||
blinkTimer = new Timer(500, e -> {
|
||||
cursorVisible = !cursorVisible;
|
||||
textBlinkVisible = !textBlinkVisible;
|
||||
repaint();
|
||||
});
|
||||
blinkTimer.start();
|
||||
}
|
||||
|
||||
public Telnet3270Client getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public void setClient(Telnet3270Client client) {
|
||||
this.client = client;
|
||||
if (client != null) {
|
||||
setupGraphicsPlaneRenderer();
|
||||
updateCellSize();
|
||||
|
||||
client.setNvtClipboardHandler(new haus.nightmare.lib3270j.nvt.NvtProcessor.ClipboardHandler() {
|
||||
@Override
|
||||
public String getClipboardText() {
|
||||
try {
|
||||
return (String) Toolkit.getDefaultToolkit().getSystemClipboard()
|
||||
.getData(DataFlavor.stringFlavor);
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClipboardText(String text) {
|
||||
if (text != null) {
|
||||
try {
|
||||
StringSelection ss = new StringSelection(text);
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.addNvtTitleListener(title -> {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
Container top = getTopLevelAncestor();
|
||||
if (top instanceof JFrame) {
|
||||
((JFrame) top).setTitle(title != null && !title.isEmpty() ? ("j3270 - " + title) : "j3270");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1194,7 +1269,18 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
int cols = sb.getDisplayCols();
|
||||
boolean isColorModel = client.getConfig().getModel().isColor();
|
||||
|
||||
// Draw Vector Graphics Plane under text if present
|
||||
// Layer 0: Optional Wallpaper / Background Image
|
||||
if (hodWallpaper != null) {
|
||||
int gridW = cols * cellWidth;
|
||||
int gridH = rows * cellHeight;
|
||||
hodWallpaper.paint(this, g2, ox, oy, gridW, gridH);
|
||||
} else if (wallpaperImage != null) {
|
||||
int gridW = cols * cellWidth;
|
||||
int gridH = rows * cellHeight;
|
||||
g2.drawImage(wallpaperImage, ox, oy, gridW, gridH, null);
|
||||
}
|
||||
|
||||
// Layer 1: Draw Vector Graphics Plane under text if present
|
||||
if (client.getGraphicsPlane() != null && client.getGraphicsPlane().hasContent()) {
|
||||
int gridW = cols * cellWidth;
|
||||
int gridH = rows * cellHeight;
|
||||
@@ -1216,6 +1302,22 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
}
|
||||
}
|
||||
|
||||
// Layer 2: Optional Crosshair Ruler under character glyphs
|
||||
if (crosshairRulerEnabled && client.getConnectionState().isFullSession()) {
|
||||
int curAddr = sb.getDisplayCursorAddress();
|
||||
int curRow = curAddr / cols;
|
||||
int curCol = curAddr % cols;
|
||||
int cx = ox + curCol * cellWidth;
|
||||
int cy = oy + curRow * cellHeight;
|
||||
int gridW = cols * cellWidth;
|
||||
int gridH = rows * cellHeight;
|
||||
|
||||
g2.setColor(CROSSHAIR_RULER_COLOR);
|
||||
g2.fillRect(ox, cy, gridW, cellHeight);
|
||||
g2.fillRect(cx, oy, cellWidth, gridH);
|
||||
}
|
||||
|
||||
// Layer 3: Character / Text Plane
|
||||
byte currentFA = 0;
|
||||
ExtendedAttribute currentFieldEa = null;
|
||||
|
||||
@@ -1243,7 +1345,7 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine foreground color
|
||||
// Determine foreground and background colors
|
||||
if (isColorModel) {
|
||||
fgColor = getColorForAttribute(ea, currentFieldEa, currentFA);
|
||||
bgColor = getBackgroundForAttribute(ea, currentFieldEa);
|
||||
@@ -1252,6 +1354,9 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
bgColor = this.bgColor;
|
||||
}
|
||||
|
||||
int rawBg = ea.bg != 0 ? (ea.bg & 0xFF) : (currentFieldEa != null ? (currentFieldEa.bg & 0xFF) : 0);
|
||||
boolean bgIsExplicit = (rawBg >= 0xF0 && rawBg <= 0xFF && rawBg != HOST_COLOR_NEUTRAL_BLACK && rawBg != HOST_COLOR_BLACK);
|
||||
|
||||
// Graphics rendition
|
||||
byte gr = ea.gr != 0 ? ea.gr : (currentFieldEa != null ? currentFieldEa.gr : 0);
|
||||
if (gr != 0) {
|
||||
@@ -1281,22 +1386,26 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
|
||||
if (reverse) {
|
||||
Color tmp = fgColor;
|
||||
fgColor = bgColor;
|
||||
fgColor = (rawBg == 0) ? this.bgColor : bgColor;
|
||||
bgColor = tmp;
|
||||
}
|
||||
|
||||
if (!bgColor.equals(this.bgColor) || reverse) {
|
||||
g2.setColor(bgColor);
|
||||
g2.fillRect(x, y, cellWidth, cellHeight);
|
||||
} else if (bgIsExplicit || !bgColor.equals(this.bgColor)) {
|
||||
g2.setColor(bgColor);
|
||||
g2.fillRect(x, y, cellWidth, cellHeight);
|
||||
}
|
||||
|
||||
// Check text blink (500ms cycle)
|
||||
boolean blink = (gr & GR_BLINK) != 0;
|
||||
boolean suppressGlyph = blink && !textBlinkVisible;
|
||||
|
||||
// Draw character or Programmed Symbol
|
||||
int cs = (ea.cs != 0) ? (ea.cs & 0xFF) : (currentFieldEa != null ? (currentFieldEa.cs & 0xFF) : 0);
|
||||
boolean drawnAsPs = false;
|
||||
if (cs >= 0x40 && client.getProgramSymbolManager() != null) {
|
||||
if (cs >= 0x40 && client.getProgramSymbolManager() != null && !suppressGlyph) {
|
||||
haus.nightmare.lib3270j.graphics.ProgramSymbolSet.SymbolSlot slot = client.getProgramSymbolManager().getSymbol(cs, ea.ec & 0xFF);
|
||||
if (slot != null) {
|
||||
int symBg = (!bgColor.equals(this.bgColor) || reverse) ? bgColor.getRGB() : 0;
|
||||
int symBg = (bgIsExplicit || reverse) ? bgColor.getRGB() : 0;
|
||||
java.awt.image.BufferedImage img = slot.getScaledImage(cellWidth, cellHeight, fgColor.getRGB(), symBg);
|
||||
if (img != null) {
|
||||
g2.drawImage(img, x, y, null);
|
||||
@@ -1305,7 +1414,7 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
}
|
||||
}
|
||||
|
||||
if (!drawnAsPs) {
|
||||
if (!drawnAsPs && !suppressGlyph) {
|
||||
char ch = ea.ucs4;
|
||||
if (ch > 0x20 && ch != 0xFF) {
|
||||
Font f = bold ? boldTerminalFont : terminalFont;
|
||||
@@ -1332,7 +1441,7 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
g2.fillRect(x, y, cellWidth, cellHeight);
|
||||
}
|
||||
|
||||
// Draw selection highlight
|
||||
// Draw selection highlight (40% alpha blend over cell)
|
||||
if (isCellSelected(row, col)) {
|
||||
g2.setColor(SELECTION_COLOR);
|
||||
g2.fillRect(x, y, cellWidth, cellHeight);
|
||||
@@ -1341,9 +1450,15 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
}
|
||||
|
||||
// Draw Graphic Cursor if active
|
||||
if (client.getGocaDecoder() != null && client.getGocaDecoder().isGraphicsCursorActive() && client.getGraphicsPlane() != null) {
|
||||
int gocaX = client.getGocaDecoder().getGraphicCursorX();
|
||||
int gocaY = client.getGocaDecoder().getGraphicCursorY();
|
||||
boolean isGraphicCursor = (client.getGocaDecoder() != null && client.getGocaDecoder().isGraphicsCursorActive())
|
||||
|| (client.getGraphicsPlane() != null && client.getGraphicsPlane().isGraphicCursorAttached());
|
||||
if (isGraphicCursor && client.getGraphicsPlane() != null) {
|
||||
int gocaX = (client.getGocaDecoder() != null && client.getGocaDecoder().isGraphicsCursorActive())
|
||||
? client.getGocaDecoder().getGraphicCursorX()
|
||||
: client.getGraphicsPlane().getGraphicCursorX();
|
||||
int gocaY = (client.getGocaDecoder() != null && client.getGocaDecoder().isGraphicsCursorActive())
|
||||
? client.getGocaDecoder().getGraphicCursorY()
|
||||
: client.getGraphicsPlane().getGraphicCursorY();
|
||||
int canvasPx = client.getGraphicsPlane().mapX(gocaX);
|
||||
int canvasPy = client.getGraphicsPlane().mapY(gocaY);
|
||||
int gridW = cols * cellWidth;
|
||||
@@ -1355,12 +1470,19 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
|
||||
g2.setColor(Color.WHITE);
|
||||
g2.setXORMode(Color.BLACK);
|
||||
g2.drawLine(px - 6, py, px + 6, py);
|
||||
g2.drawLine(px, py - 6, px, py + 6);
|
||||
int shape = client.getGraphicsPlane().getHodCursorShape();
|
||||
if (shape == 2) {
|
||||
// Shape 2: Box cursor per HoD
|
||||
g2.drawRect(px - 3, py - 3, 6, 6);
|
||||
} else {
|
||||
// Shape 1 (default): Crosshair per HoD
|
||||
g2.drawLine(px - 8, py, px + 8, py);
|
||||
g2.drawLine(px, py - 8, px, py + 8);
|
||||
}
|
||||
g2.setPaintMode();
|
||||
}
|
||||
|
||||
// Draw 3270 text cursor
|
||||
// Draw 3270 text cursor with alpha blending (Block / Underline)
|
||||
if (cursorVisible && client.getConnectionState().isFullSession()) {
|
||||
int curAddr = sb.getDisplayCursorAddress();
|
||||
int curRow = curAddr / cols;
|
||||
@@ -1368,13 +1490,79 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
int cx = ox + curCol * cellWidth;
|
||||
int cy = oy + curRow * cellHeight;
|
||||
|
||||
boolean isUnderline = (cursorStyle == CursorStyle.UNDERLINE) ||
|
||||
(client.getInputProcessor() != null && client.getInputProcessor().isInsertMode());
|
||||
g2.setColor(CURSOR_COLOR);
|
||||
g2.setXORMode(bgColor);
|
||||
g2.fillRect(cx, cy, cellWidth, cellHeight);
|
||||
g2.setPaintMode();
|
||||
if (isUnderline) {
|
||||
int ulH = Math.max(2, cellHeight / 6);
|
||||
g2.fillRect(cx, cy + cellHeight - ulH, cellWidth, ulH);
|
||||
} else {
|
||||
g2.fillRect(cx, cy, cellWidth, cellHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCrosshairRulerEnabled() {
|
||||
return crosshairRulerEnabled;
|
||||
}
|
||||
|
||||
public void setCrosshairRulerEnabled(boolean enabled) {
|
||||
this.crosshairRulerEnabled = enabled;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void toggleCrosshairRuler() {
|
||||
setCrosshairRulerEnabled(!crosshairRulerEnabled);
|
||||
}
|
||||
|
||||
public CursorStyle getCursorStyle() {
|
||||
return cursorStyle;
|
||||
}
|
||||
|
||||
public void setCursorStyle(CursorStyle style) {
|
||||
this.cursorStyle = (style != null) ? style : CursorStyle.BLOCK;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public Image getWallpaperImage() {
|
||||
return wallpaperImage;
|
||||
}
|
||||
|
||||
public void setWallpaperImage(Image wallpaperImage) {
|
||||
this.wallpaperImage = wallpaperImage;
|
||||
if (wallpaperImage != null) {
|
||||
if (this.hodWallpaper == null) {
|
||||
this.hodWallpaper = new haus.nightmare.lib3270j.graphics.HODWallpaper(wallpaperImage, haus.nightmare.lib3270j.graphics.HODWallpaper.HOD_STRETCH);
|
||||
} else {
|
||||
this.hodWallpaper.setImage(wallpaperImage);
|
||||
}
|
||||
} else {
|
||||
this.hodWallpaper = null;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.graphics.HODWallpaper getHodWallpaper() {
|
||||
return hodWallpaper;
|
||||
}
|
||||
|
||||
public void setHodWallpaper(haus.nightmare.lib3270j.graphics.HODWallpaper wallpaper) {
|
||||
this.hodWallpaper = wallpaper;
|
||||
if (wallpaper != null) {
|
||||
this.wallpaperImage = wallpaper.getHODImage();
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setWallpaperMode(int displayMode) {
|
||||
if (this.hodWallpaper == null && this.wallpaperImage != null) {
|
||||
this.hodWallpaper = new haus.nightmare.lib3270j.graphics.HODWallpaper(this.wallpaperImage, displayMode);
|
||||
} else if (this.hodWallpaper != null) {
|
||||
this.hodWallpaper.setDisplay(displayMode);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
private Color getColorForAttribute(ExtendedAttribute ea, ExtendedAttribute currentFieldEa, byte currentFA) {
|
||||
int fg = ea.fg != 0 ? (ea.fg & 0xFF)
|
||||
: (currentFieldEa != null && currentFieldEa.fg != 0 ? (currentFieldEa.fg & 0xFF) : 0);
|
||||
@@ -1382,7 +1570,7 @@ public class TerminalPanel extends JPanel implements java.awt.print.Printable {
|
||||
return hostColors[fg - 0xf0];
|
||||
}
|
||||
if (faIsProtected(currentFA & 0xFF)) {
|
||||
return faIsHigh(currentFA & 0xFF) ? hostColors[HOST_COLOR_WHITE] : hostColors[HOST_COLOR_BLUE];
|
||||
return faIsHigh(currentFA & 0xFF) ? hostColors[HOST_COLOR_WHITE] : hostColors[HOST_COLOR_TURQUOISE];
|
||||
}
|
||||
return faIsHigh(currentFA & 0xFF) ? hostColors[HOST_COLOR_RED] : hostColors[HOST_COLOR_GREEN];
|
||||
}
|
||||
|
||||
@@ -244,6 +244,19 @@ public final class ThemeManager {
|
||||
return t == UITheme.DARK ? new Color(255, 190, 70) : new Color(180, 100, 0);
|
||||
}
|
||||
|
||||
// Host On-Demand OIA Category Colors (oSI, oII, oAI, oEI, oOB)
|
||||
public static final Color HOD_OIA_STATUS_SYS_AVAIL = new Color(120, 144, 240); // oSI: CUSTOMBLUE
|
||||
public static final Color HOD_OIA_INPUT_INHIBITED = new Color(255, 255, 255); // oII: White
|
||||
public static final Color HOD_OIA_ATTENTION_WARN = new Color(255, 255, 0); // oAI: Yellow
|
||||
public static final Color HOD_OIA_COMM_CHECK_ERROR = new Color(255, 0, 0); // oEI: Red
|
||||
public static final Color HOD_OIA_BG_BLACK = new Color(0, 0, 0); // oOB: Black
|
||||
|
||||
public static Color getOiaStatusSysAvail() { return HOD_OIA_STATUS_SYS_AVAIL; }
|
||||
public static Color getOiaInputInhibited() { return HOD_OIA_INPUT_INHIBITED; }
|
||||
public static Color getOiaAttention() { return HOD_OIA_ATTENTION_WARN; }
|
||||
public static Color getOiaCommCheck() { return HOD_OIA_COMM_CHECK_ERROR; }
|
||||
public static Color getOiaBackground() { return HOD_OIA_BG_BLACK; }
|
||||
|
||||
// =========================================================================
|
||||
// Button Variants & Color helpers
|
||||
// =========================================================================
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package haus.nightmare.j3270.ui;
|
||||
|
||||
import haus.nightmare.j3270.J3270App;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class MenuBarShortcutsTest {
|
||||
|
||||
private Map<String, JMenuItem> collectMenuItems(JMenu menu) {
|
||||
Map<String, JMenuItem> map = new HashMap<>();
|
||||
for (int i = 0; i < menu.getItemCount(); i++) {
|
||||
JMenuItem item = menu.getItem(i);
|
||||
if (item != null) {
|
||||
map.put(item.getText(), item);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionAndViewShortcutsUseAlt() {
|
||||
J3270App app;
|
||||
try {
|
||||
app = new J3270App();
|
||||
} catch (HeadlessException e) {
|
||||
// In automated/headless environments, JFrame cannot be initialized
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JMenuBar mb = app.getJMenuBar();
|
||||
assertNotNull(mb, "JMenuBar should be present");
|
||||
|
||||
JMenu viewMenu = null;
|
||||
JMenu actionsMenu = null;
|
||||
JMenu fileMenu = null;
|
||||
JMenu editMenu = null;
|
||||
|
||||
for (int i = 0; i < mb.getMenuCount(); i++) {
|
||||
JMenu m = mb.getMenu(i);
|
||||
if (m != null) {
|
||||
if ("View".equals(m.getText())) viewMenu = m;
|
||||
else if ("Actions".equals(m.getText())) actionsMenu = m;
|
||||
else if ("File".equals(m.getText())) fileMenu = m;
|
||||
else if ("Edit".equals(m.getText())) editMenu = m;
|
||||
}
|
||||
}
|
||||
|
||||
assertNotNull(viewMenu, "View menu should exist");
|
||||
assertNotNull(actionsMenu, "Actions menu should exist");
|
||||
assertNotNull(fileMenu, "File menu should exist");
|
||||
assertNotNull(editMenu, "Edit menu should exist");
|
||||
|
||||
// Verify View Menu items
|
||||
Map<String, JMenuItem> viewItems = collectMenuItems(viewMenu);
|
||||
assertAcceleratorUsesAlt(viewItems.get("Font Size +"), KeyEvent.VK_EQUALS);
|
||||
assertAcceleratorUsesAlt(viewItems.get("Font Size -"), KeyEvent.VK_MINUS);
|
||||
assertAcceleratorUsesAlt(viewItems.get("Reset Font"), KeyEvent.VK_0);
|
||||
|
||||
// Crosshair Ruler must use Alt+Shift+R
|
||||
JMenuItem rulerItem = viewItems.get("Crosshair Ruler");
|
||||
assertNotNull(rulerItem, "Crosshair Ruler menu item must exist");
|
||||
KeyStroke rulerKs = rulerItem.getAccelerator();
|
||||
assertNotNull(rulerKs, "Crosshair Ruler should have an accelerator");
|
||||
assertEquals(KeyEvent.VK_R, rulerKs.getKeyCode(), "Key code mismatch for Crosshair Ruler");
|
||||
int rulerMods = rulerKs.getModifiers();
|
||||
assertTrue((rulerMods & (KeyEvent.ALT_DOWN_MASK | KeyEvent.ALT_MASK)) != 0,
|
||||
"Crosshair Ruler accelerator must have ALT modifier");
|
||||
assertTrue((rulerMods & (KeyEvent.SHIFT_DOWN_MASK | KeyEvent.SHIFT_MASK)) != 0,
|
||||
"Crosshair Ruler accelerator must have SHIFT modifier");
|
||||
assertEquals(0, rulerMods & (KeyEvent.CTRL_DOWN_MASK | KeyEvent.CTRL_MASK | KeyEvent.META_DOWN_MASK | KeyEvent.META_MASK),
|
||||
"Crosshair Ruler accelerator must NOT have CTRL or META modifiers");
|
||||
|
||||
// Verify Actions Menu items use ALT_DOWN_MASK
|
||||
Map<String, JMenuItem> actionItems = collectMenuItems(actionsMenu);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Send Enter"), KeyEvent.VK_ENTER);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Clear"), KeyEvent.VK_K);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Reset"), KeyEvent.VK_R);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Erase Input"), KeyEvent.VK_E);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Attention"), KeyEvent.VK_A);
|
||||
assertAcceleratorUsesAlt(actionItems.get("System Request"), KeyEvent.VK_S);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Cursor Select"), KeyEvent.VK_Q);
|
||||
assertAcceleratorUsesAlt(actionItems.get("Toggle Light Pen (Alt+L)"), KeyEvent.VK_L);
|
||||
assertAcceleratorUsesAlt(actionItems.get("File Transfer..."), KeyEvent.VK_T);
|
||||
|
||||
// Ensure Crosshair Ruler and Reset do not collide
|
||||
assertNotEquals(rulerKs, actionItems.get("Reset").getAccelerator(),
|
||||
"Crosshair Ruler and Reset accelerators must not collide");
|
||||
} finally {
|
||||
// Dispose frame
|
||||
app.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAcceleratorUsesAlt(JMenuItem item, int expectedKeyCode) {
|
||||
assertNotNull(item, "Menu item must exist");
|
||||
KeyStroke ks = item.getAccelerator();
|
||||
assertNotNull(ks, "Menu item " + item.getText() + " should have an accelerator");
|
||||
assertEquals(expectedKeyCode, ks.getKeyCode(), "Key code mismatch for " + item.getText());
|
||||
int mods = ks.getModifiers();
|
||||
assertTrue((mods & (KeyEvent.ALT_DOWN_MASK | KeyEvent.ALT_MASK)) != 0,
|
||||
"Menu item " + item.getText() + " accelerator must have ALT modifier");
|
||||
assertEquals(0, mods & (KeyEvent.SHIFT_DOWN_MASK | KeyEvent.SHIFT_MASK),
|
||||
"Menu item " + item.getText() + " accelerator must NOT have SHIFT modifier");
|
||||
assertEquals(0, mods & (KeyEvent.CTRL_DOWN_MASK | KeyEvent.CTRL_MASK | KeyEvent.META_DOWN_MASK | KeyEvent.META_MASK),
|
||||
"Menu item " + item.getText() + " accelerator must NOT have CTRL or META modifiers");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package haus.nightmare.j3270.ui;
|
||||
|
||||
import haus.nightmare.j3270.config.Settings;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.HeadlessException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Verification test suite for Phase 1 UI Overlays and Color Alignment.
|
||||
* Covers items 1.1, 1.2, and 1.5 of the PhasedUpdates specification.
|
||||
*/
|
||||
public class Phase1UiOverlayTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Item 1.1 & 1.2: TerminalPanel host and mono colors match IBM Host On-Demand specs")
|
||||
public void testTerminalPanelColorAlignment() {
|
||||
// Index 10: Orange (255, 162, 0)
|
||||
assertEquals(new Color(255, 162, 0), TerminalPanel.DEFAULT_HOST_COLORS[10]);
|
||||
|
||||
// Index 14: Mustard (160, 160, 0)
|
||||
assertEquals(new Color(160, 160, 0), TerminalPanel.DEFAULT_HOST_COLORS[14]);
|
||||
|
||||
// Index 1: Blue (120, 144, 240)
|
||||
assertEquals(new Color(120, 144, 240), TerminalPanel.DEFAULT_HOST_COLORS[1]);
|
||||
|
||||
// Base 4-Color mono defaults
|
||||
assertEquals(new Color(0, 255, 0), TerminalPanel.DEFAULT_MONO_NORMAL);
|
||||
assertEquals(new Color(255, 0, 0), TerminalPanel.DEFAULT_MONO_INTENSIFY);
|
||||
assertEquals(new Color(0, 255, 255), TerminalPanel.DEFAULT_MONO_PROTECTED);
|
||||
assertEquals(new Color(255, 255, 255), TerminalPanel.DEFAULT_MONO_PROTECTED_HIGH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Item 1.5: ThemeManager HoD OIA category colors match specification")
|
||||
public void testThemeManagerOiaColors() {
|
||||
// oSI: Status / System Available -> CUSTOMBLUE (120, 144, 240)
|
||||
assertEquals(new Color(120, 144, 240), ThemeManager.getOiaStatusSysAvail());
|
||||
|
||||
// oII: Input Inhibited / X SYSTEM -> White (255, 255, 255)
|
||||
assertEquals(new Color(255, 255, 255), ThemeManager.getOiaInputInhibited());
|
||||
|
||||
// oAI: Attention / Reminders / Message Waiting -> Yellow (255, 255, 0)
|
||||
assertEquals(new Color(255, 255, 0), ThemeManager.getOiaAttention());
|
||||
|
||||
// oEI: Error Checks / Comm Check -> Red (255, 0, 0)
|
||||
assertEquals(new Color(255, 0, 0), ThemeManager.getOiaCommCheck());
|
||||
|
||||
// oOB: OIA Separator / Background -> Black (0, 0, 0)
|
||||
assertEquals(new Color(0, 0, 0), ThemeManager.getOiaBackground());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Item 1.5: TerminalPanel Crosshair Ruler and Cursor Style controls")
|
||||
public void testTerminalPanelRulerAndCursorStyle() {
|
||||
try {
|
||||
TerminalPanel panel = new TerminalPanel();
|
||||
|
||||
// Default cursor style is BLOCK
|
||||
assertEquals(TerminalPanel.CursorStyle.BLOCK, panel.getCursorStyle());
|
||||
panel.setCursorStyle(TerminalPanel.CursorStyle.UNDERLINE);
|
||||
assertEquals(TerminalPanel.CursorStyle.UNDERLINE, panel.getCursorStyle());
|
||||
|
||||
// Crosshair ruler toggling
|
||||
assertFalse(panel.isCrosshairRulerEnabled());
|
||||
panel.setCrosshairRulerEnabled(true);
|
||||
assertTrue(panel.isCrosshairRulerEnabled());
|
||||
panel.toggleCrosshairRuler();
|
||||
assertFalse(panel.isCrosshairRulerEnabled());
|
||||
|
||||
// Wallpaper image setter
|
||||
assertNull(panel.getWallpaperImage());
|
||||
} catch (HeadlessException e) {
|
||||
// Handled gracefully in headless CI environments
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Settings persistence for Crosshair Ruler and Cursor Style")
|
||||
public void testSettingsPersistence() {
|
||||
boolean originalRuler = Settings.getCrosshairRuler();
|
||||
String originalCursor = Settings.getCursorStyle();
|
||||
|
||||
try {
|
||||
Settings.setCrosshairRuler(true);
|
||||
assertTrue(Settings.getCrosshairRuler());
|
||||
|
||||
Settings.setCrosshairRuler(false);
|
||||
assertFalse(Settings.getCrosshairRuler());
|
||||
|
||||
Settings.setCursorStyle("UNDERLINE");
|
||||
assertEquals("UNDERLINE", Settings.getCursorStyle());
|
||||
|
||||
Settings.setCursorStyle("BLOCK");
|
||||
assertEquals("BLOCK", Settings.getCursorStyle());
|
||||
} finally {
|
||||
Settings.setCrosshairRuler(originalRuler);
|
||||
Settings.setCursorStyle(originalCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package haus.nightmare.j3270.ui;
|
||||
|
||||
import haus.nightmare.lib3270j.graphics.GocaConstants;
|
||||
import haus.nightmare.lib3270j.graphics.GraphicsPlane;
|
||||
import haus.nightmare.lib3270j.graphics.HODWallpaper;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Verification test suite for Phase 2 UI Vector Graphics, Wallpaper, and Cursor Overlays.
|
||||
*/
|
||||
public class Phase2UiGraphicsTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Test TerminalPanel Wallpaper Integration (Tile, Center, Stretch)")
|
||||
public void testTerminalPanelWallpaperModes() {
|
||||
try {
|
||||
TerminalPanel panel = new TerminalPanel();
|
||||
assertNull(panel.getHodWallpaper());
|
||||
assertNull(panel.getWallpaperImage());
|
||||
|
||||
BufferedImage img = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
|
||||
panel.setWallpaperImage(img);
|
||||
assertNotNull(panel.getWallpaperImage());
|
||||
assertNotNull(panel.getHodWallpaper());
|
||||
assertEquals(HODWallpaper.HOD_STRETCH, panel.getHodWallpaper().getDisplay());
|
||||
|
||||
panel.setWallpaperMode(HODWallpaper.HOD_TILE);
|
||||
assertEquals(HODWallpaper.HOD_TILE, panel.getHodWallpaper().getDisplay());
|
||||
|
||||
panel.setWallpaperMode(HODWallpaper.HOD_CENTER);
|
||||
assertEquals(HODWallpaper.HOD_CENTER, panel.getHodWallpaper().getDisplay());
|
||||
|
||||
HODWallpaper customWp = new HODWallpaper(img, HODWallpaper.HOD_TILE);
|
||||
panel.setHodWallpaper(customWp);
|
||||
assertSame(customWp, panel.getHodWallpaper());
|
||||
|
||||
// Clear wallpaper
|
||||
panel.setWallpaperImage(null);
|
||||
assertNull(panel.getHodWallpaper());
|
||||
assertNull(panel.getWallpaperImage());
|
||||
} catch (HeadlessException e) {
|
||||
// Handled gracefully in headless environments
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test Graphics Plane Cursor Synchronization and Rendering")
|
||||
public void testGraphicsCursorOverlay() {
|
||||
try {
|
||||
TerminalPanel panel = new TerminalPanel();
|
||||
panel.setSize(new Dimension(800, 600));
|
||||
panel.setClient(new haus.nightmare.lib3270j.Telnet3270Client(new haus.nightmare.lib3270j.ConnectionConfig("localhost", 23)));
|
||||
|
||||
GraphicsPlane plane = panel.getClient() != null ? panel.getClient().getGraphicsPlane() : null;
|
||||
if (plane != null) {
|
||||
// Attach graphics cursor
|
||||
plane.attachGraphicCursor(100, 100);
|
||||
plane.setHodCursorShape(GocaConstants.GCURSOR_SHAPE_CROSSHAIR);
|
||||
assertTrue(plane.isGraphicCursorAttached());
|
||||
assertEquals(100, plane.getGraphicCursorX());
|
||||
assertEquals(100, plane.getGraphicCursorY());
|
||||
assertEquals(1, plane.getHodCursorShape());
|
||||
|
||||
// Paint component to verify no exceptions during rendering
|
||||
BufferedImage offscreen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = offscreen.createGraphics();
|
||||
panel.paint(g2);
|
||||
g2.dispose();
|
||||
|
||||
// Change cursor shape to box
|
||||
plane.setHodCursorShape(GocaConstants.GCURSOR_SHAPE_BOX);
|
||||
assertEquals(2, plane.getHodCursorShape());
|
||||
offscreen = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
|
||||
g2 = offscreen.createGraphics();
|
||||
panel.paint(g2);
|
||||
g2.dispose();
|
||||
|
||||
// Detach graphics cursor
|
||||
plane.detachGraphicCursor();
|
||||
assertFalse(plane.isGraphicCursorAttached());
|
||||
}
|
||||
} catch (HeadlessException e) {
|
||||
// Handled gracefully in headless environments
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,41 +14,49 @@ public class StatusBarTest {
|
||||
|
||||
@Test
|
||||
public void testStatusBarDoesNotContainLightPenButton() {
|
||||
StatusBar statusBar = new StatusBar();
|
||||
|
||||
// Ensure no JButton exists in StatusBar components (lightpen button removed)
|
||||
for (Component comp : statusBar.getComponents()) {
|
||||
assertFalse(comp instanceof JButton, "StatusBar should not contain any JButton (lightpen removed from bottom bar)");
|
||||
try {
|
||||
StatusBar statusBar = new StatusBar();
|
||||
|
||||
// Ensure no JButton exists in StatusBar components (lightpen button removed)
|
||||
for (Component comp : statusBar.getComponents()) {
|
||||
assertFalse(comp instanceof JButton, "StatusBar should not contain any JButton (lightpen removed from bottom bar)");
|
||||
}
|
||||
} catch (HeadlessException e) {
|
||||
// Ignored in headless environments
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatusBarUpdatesWithClient() {
|
||||
ConnectionConfig config = new ConnectionConfig("mvs.example.com", 23, TerminalModel.IBM_3279_4, false);
|
||||
config.setLuName("TSU001");
|
||||
config.setCodePage("1047");
|
||||
Telnet3270Client client = new Telnet3270Client(config);
|
||||
try {
|
||||
ConnectionConfig config = new ConnectionConfig("mvs.example.com", 23, TerminalModel.IBM_3279_4, false);
|
||||
config.setLuName("TSU001");
|
||||
config.setCodePage("1047");
|
||||
Telnet3270Client client = new Telnet3270Client(config);
|
||||
|
||||
StatusBar statusBar = new StatusBar();
|
||||
statusBar.setClient(client, null);
|
||||
statusBar.updateStatus();
|
||||
StatusBar statusBar = new StatusBar();
|
||||
statusBar.setClient(client, null);
|
||||
statusBar.updateStatus();
|
||||
|
||||
// Check labels
|
||||
boolean foundCodePage = false;
|
||||
boolean foundModel = false;
|
||||
for (Component comp : statusBar.getComponents()) {
|
||||
if (comp instanceof JLabel) {
|
||||
JLabel label = (JLabel) comp;
|
||||
if ("CP1047".equals(label.getText())) {
|
||||
foundCodePage = true;
|
||||
}
|
||||
if (label.getText() != null && label.getText().contains("3279-4")) {
|
||||
foundModel = true;
|
||||
// Check labels
|
||||
boolean foundCodePage = false;
|
||||
boolean foundModel = false;
|
||||
for (Component comp : statusBar.getComponents()) {
|
||||
if (comp instanceof JLabel) {
|
||||
JLabel label = (JLabel) comp;
|
||||
if ("CP1047".equals(label.getText())) {
|
||||
foundCodePage = true;
|
||||
}
|
||||
if (label.getText() != null && label.getText().contains("3279-4")) {
|
||||
foundModel = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(foundCodePage, "Should display CP1047");
|
||||
assertTrue(foundModel, "Should display IBM-3279-4 model info");
|
||||
assertTrue(foundCodePage, "Should display CP1047");
|
||||
assertTrue(foundModel, "Should display IBM-3279-4 model info");
|
||||
} catch (HeadlessException e) {
|
||||
// Ignored in headless environments
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,80 +98,88 @@ public class ThemeManagerTest {
|
||||
|
||||
@Test
|
||||
public void testComponentStyling() {
|
||||
JButton btn = new JButton("Test");
|
||||
ThemeManager.styleButton(btn, ThemeManager.ButtonVariant.PRIMARY);
|
||||
assertNotNull(btn.getUI());
|
||||
assertTrue(btn.getUI() instanceof ThemeManager.StyledButtonUI);
|
||||
try {
|
||||
JButton btn = new JButton("Test");
|
||||
ThemeManager.styleButton(btn, ThemeManager.ButtonVariant.PRIMARY);
|
||||
assertNotNull(btn.getUI());
|
||||
assertTrue(btn.getUI() instanceof ThemeManager.StyledButtonUI);
|
||||
|
||||
JTextField tf = new JTextField("Test");
|
||||
ThemeManager.styleTextField(tf);
|
||||
assertNotNull(tf.getCaretColor());
|
||||
JTextField tf = new JTextField("Test");
|
||||
ThemeManager.styleTextField(tf);
|
||||
assertNotNull(tf.getCaretColor());
|
||||
|
||||
JTextArea ta = new JTextArea("Test area");
|
||||
ThemeManager.styleTextArea(ta);
|
||||
assertNotNull(ta.getCaretColor());
|
||||
JTextArea ta = new JTextArea("Test area");
|
||||
ThemeManager.styleTextArea(ta);
|
||||
assertNotNull(ta.getCaretColor());
|
||||
|
||||
JComboBox<String> cb = new JComboBox<>(new String[]{"A", "B"});
|
||||
ThemeManager.styleComboBox(cb);
|
||||
assertNotNull(cb.getUI());
|
||||
JComboBox<String> cb = new JComboBox<>(new String[]{"A", "B"});
|
||||
ThemeManager.styleComboBox(cb);
|
||||
assertNotNull(cb.getUI());
|
||||
|
||||
JTable table = new JTable(new DefaultTableModel(new Object[]{"Col1"}, 1));
|
||||
ThemeManager.styleTable(table);
|
||||
assertNotNull(table.getSelectionBackground());
|
||||
JTable table = new JTable(new DefaultTableModel(new Object[]{"Col1"}, 1));
|
||||
ThemeManager.styleTable(table);
|
||||
assertNotNull(table.getSelectionBackground());
|
||||
|
||||
JTabbedPane tp = new JTabbedPane();
|
||||
tp.addTab("Tab1", new JPanel());
|
||||
ThemeManager.styleTabbedPane(tp);
|
||||
assertNotNull(tp.getUI());
|
||||
JTabbedPane tp = new JTabbedPane();
|
||||
tp.addTab("Tab1", new JPanel());
|
||||
ThemeManager.styleTabbedPane(tp);
|
||||
assertNotNull(tp.getUI());
|
||||
|
||||
JMenuBar mb = new JMenuBar();
|
||||
ThemeManager.styleMenuBar(mb);
|
||||
JMenuBar mb = new JMenuBar();
|
||||
ThemeManager.styleMenuBar(mb);
|
||||
|
||||
JMenu menu = new JMenu("File");
|
||||
ThemeManager.styleMenu(menu);
|
||||
JMenu menu = new JMenu("File");
|
||||
ThemeManager.styleMenu(menu);
|
||||
|
||||
JMenuItem mi = new JMenuItem("Open");
|
||||
ThemeManager.styleMenuItem(mi);
|
||||
JMenuItem mi = new JMenuItem("Open");
|
||||
ThemeManager.styleMenuItem(mi);
|
||||
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
ThemeManager.stylePopupMenu(popup);
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
ThemeManager.stylePopupMenu(popup);
|
||||
|
||||
JCheckBox chk = new JCheckBox("Check");
|
||||
ThemeManager.styleCheckBox(chk);
|
||||
JCheckBox chk = new JCheckBox("Check");
|
||||
ThemeManager.styleCheckBox(chk);
|
||||
|
||||
JRadioButton rb = new JRadioButton("Radio");
|
||||
ThemeManager.styleRadioButton(rb);
|
||||
JRadioButton rb = new JRadioButton("Radio");
|
||||
ThemeManager.styleRadioButton(rb);
|
||||
|
||||
Border tb = ThemeManager.createTitledBorder("Title");
|
||||
assertNotNull(tb);
|
||||
Border tb = ThemeManager.createTitledBorder("Title");
|
||||
assertNotNull(tb);
|
||||
} catch (HeadlessException e) {
|
||||
// Ignored in headless environments
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveApplyTheme() {
|
||||
JPanel root = new JPanel(new BorderLayout());
|
||||
JButton b = new JButton("OK");
|
||||
JTextField f = new JTextField("Data");
|
||||
JTabbedPane tp = new JTabbedPane();
|
||||
JPanel tabContent = new JPanel();
|
||||
JLabel lbl = new JLabel("Label");
|
||||
tabContent.add(lbl);
|
||||
tp.addTab("T1", tabContent);
|
||||
try {
|
||||
JPanel root = new JPanel(new BorderLayout());
|
||||
JButton b = new JButton("OK");
|
||||
JTextField f = new JTextField("Data");
|
||||
JTabbedPane tp = new JTabbedPane();
|
||||
JPanel tabContent = new JPanel();
|
||||
JLabel lbl = new JLabel("Label");
|
||||
tabContent.add(lbl);
|
||||
tp.addTab("T1", tabContent);
|
||||
|
||||
root.add(b, BorderLayout.NORTH);
|
||||
root.add(f, BorderLayout.CENTER);
|
||||
root.add(tp, BorderLayout.SOUTH);
|
||||
root.add(b, BorderLayout.NORTH);
|
||||
root.add(f, BorderLayout.CENTER);
|
||||
root.add(tp, BorderLayout.SOUTH);
|
||||
|
||||
ThemeManager.setTheme(UITheme.LIGHT);
|
||||
ThemeManager.applyTheme(root);
|
||||
ThemeManager.setTheme(UITheme.LIGHT);
|
||||
ThemeManager.applyTheme(root);
|
||||
|
||||
assertEquals(ThemeManager.getBgPanel(UITheme.LIGHT), root.getBackground());
|
||||
assertEquals(ThemeManager.getFgMain(UITheme.LIGHT), lbl.getForeground());
|
||||
assertEquals(ThemeManager.getBgPanel(UITheme.LIGHT), root.getBackground());
|
||||
assertEquals(ThemeManager.getFgMain(UITheme.LIGHT), lbl.getForeground());
|
||||
|
||||
ThemeManager.setTheme(UITheme.DARK);
|
||||
ThemeManager.applyTheme(root);
|
||||
ThemeManager.setTheme(UITheme.DARK);
|
||||
ThemeManager.applyTheme(root);
|
||||
|
||||
assertEquals(ThemeManager.getBgPanel(UITheme.DARK), root.getBackground());
|
||||
assertEquals(ThemeManager.getFgMain(UITheme.DARK), lbl.getForeground());
|
||||
assertEquals(ThemeManager.getBgPanel(UITheme.DARK), root.getBackground());
|
||||
assertEquals(ThemeManager.getFgMain(UITheme.DARK), lbl.getForeground());
|
||||
} catch (HeadlessException e) {
|
||||
// Ignored in headless environments
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,16 @@ public class ConnectionConfig {
|
||||
private boolean tlsVerifyCert = true;
|
||||
private haus.nightmare.lib3270j.tls.TlsCertificateVerifier certificateVerifier = null;
|
||||
private String sslProtocol = "TLS";
|
||||
private String keyStorePath = null;
|
||||
private String keyStorePassword = null;
|
||||
private String keyStoreType = null;
|
||||
private String keyStoreAlias = null;
|
||||
private String trustStorePath = null;
|
||||
private String trustStorePassword = null;
|
||||
private String trustStoreType = null;
|
||||
private ClassLoader customizedCAsClassLoader = null;
|
||||
private java.util.List<String> enabledProtocols = new java.util.ArrayList<>();
|
||||
private java.util.List<String> enabledCipherSuites = new java.util.ArrayList<>();
|
||||
private int connectTimeoutMs = 15000;
|
||||
private int nopIntervalSeconds = 0;
|
||||
private String terminalName = null; // override terminal type string
|
||||
@@ -27,8 +37,8 @@ public class ConnectionConfig {
|
||||
private int soTimeoutMs = 0;
|
||||
private java.util.List<String> luNames = new java.util.ArrayList<>();
|
||||
private boolean dynamicModel = false;
|
||||
private int dynamicRows = 24;
|
||||
private int dynamicCols = 80;
|
||||
private int dynamicRows = 62;
|
||||
private int dynamicCols = 160;
|
||||
private haus.nightmare.lib3270j.graphics.GraphicsMode graphicsMode = haus.nightmare.lib3270j.graphics.GraphicsMode.BOTH;
|
||||
private String codePage = "037";
|
||||
private String associatedPrinterLu = null;
|
||||
@@ -81,7 +91,12 @@ public class ConnectionConfig {
|
||||
public void setPort(int port) { this.port = port; }
|
||||
|
||||
public TerminalModel getModel() { return model; }
|
||||
public void setModel(TerminalModel model) { this.model = model; }
|
||||
public void setModel(TerminalModel model) {
|
||||
this.model = model;
|
||||
if (model != null && model.isDynamic()) {
|
||||
this.dynamicModel = true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getLuName() { return luName; }
|
||||
public void setLuName(String luName) { this.luName = luName; }
|
||||
@@ -104,6 +119,52 @@ public class ConnectionConfig {
|
||||
public String getSslProtocol() { return sslProtocol; }
|
||||
public void setSslProtocol(String protocol) { this.sslProtocol = protocol; }
|
||||
|
||||
public String getKeyStorePath() { return keyStorePath; }
|
||||
public void setKeyStorePath(String path) { this.keyStorePath = path; }
|
||||
|
||||
public String getKeyStorePassword() { return keyStorePassword; }
|
||||
public void setKeyStorePassword(String password) { this.keyStorePassword = password; }
|
||||
|
||||
public String getKeyStoreType() { return keyStoreType; }
|
||||
public void setKeyStoreType(String type) { this.keyStoreType = type; }
|
||||
|
||||
public String getKeyStoreAlias() { return keyStoreAlias; }
|
||||
public void setKeyStoreAlias(String alias) { this.keyStoreAlias = alias; }
|
||||
|
||||
public String getTrustStorePath() { return trustStorePath; }
|
||||
public void setTrustStorePath(String path) { this.trustStorePath = path; }
|
||||
|
||||
public String getTrustStorePassword() { return trustStorePassword; }
|
||||
public void setTrustStorePassword(String password) { this.trustStorePassword = password; }
|
||||
|
||||
public String getTrustStoreType() { return trustStoreType; }
|
||||
public void setTrustStoreType(String type) { this.trustStoreType = type; }
|
||||
|
||||
public ClassLoader getCustomizedCAsClassLoader() { return customizedCAsClassLoader; }
|
||||
public void setCustomizedCAsClassLoader(ClassLoader cl) { this.customizedCAsClassLoader = cl; }
|
||||
|
||||
public java.util.List<String> getEnabledProtocols() { return enabledProtocols; }
|
||||
public void setEnabledProtocols(java.util.List<String> protocols) {
|
||||
this.enabledProtocols = protocols != null ? new java.util.ArrayList<>(protocols) : new java.util.ArrayList<>();
|
||||
}
|
||||
public void setEnabledProtocols(String... protocols) {
|
||||
this.enabledProtocols = new java.util.ArrayList<>();
|
||||
if (protocols != null) {
|
||||
for (String p : protocols) if (p != null) this.enabledProtocols.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
public java.util.List<String> getEnabledCipherSuites() { return enabledCipherSuites; }
|
||||
public void setEnabledCipherSuites(java.util.List<String> cipherSuites) {
|
||||
this.enabledCipherSuites = cipherSuites != null ? new java.util.ArrayList<>(cipherSuites) : new java.util.ArrayList<>();
|
||||
}
|
||||
public void setEnabledCipherSuites(String... cipherSuites) {
|
||||
this.enabledCipherSuites = new java.util.ArrayList<>();
|
||||
if (cipherSuites != null) {
|
||||
for (String c : cipherSuites) if (c != null) this.enabledCipherSuites.add(c);
|
||||
}
|
||||
}
|
||||
|
||||
public int getConnectTimeoutMs() { return connectTimeoutMs; }
|
||||
public void setConnectTimeoutMs(int ms) { this.connectTimeoutMs = ms; }
|
||||
|
||||
@@ -145,15 +206,30 @@ public class ConnectionConfig {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDynamicModel() { return dynamicModel; }
|
||||
public void setDynamicModel(boolean dynamicModel) { this.dynamicModel = dynamicModel; }
|
||||
public boolean isDynamicModel() {
|
||||
return dynamicModel || (model != null && model.isDynamic());
|
||||
}
|
||||
|
||||
public void setDynamicModel(boolean dynamicModel) {
|
||||
this.dynamicModel = dynamicModel;
|
||||
if (dynamicModel && (model == null || !model.isDynamic())) {
|
||||
this.model = TerminalModel.IBM_DYNAMIC;
|
||||
} else if (!dynamicModel && model != null && model.isDynamic()) {
|
||||
this.model = TerminalModel.IBM_3279_4;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDynamic(boolean dynamic) {
|
||||
setDynamicModel(dynamic);
|
||||
}
|
||||
|
||||
public int getDynamicRows() { return dynamicRows; }
|
||||
public int getDynamicCols() { return dynamicCols; }
|
||||
public void setDynamicDimensions(int rows, int cols) {
|
||||
this.dynamicModel = true;
|
||||
this.dynamicRows = rows;
|
||||
this.dynamicCols = cols;
|
||||
this.dynamicRows = Math.max(1, rows);
|
||||
this.dynamicCols = Math.max(1, cols);
|
||||
this.model = TerminalModel.IBM_DYNAMIC;
|
||||
}
|
||||
|
||||
public ProxyType getProxyType() { return proxyType; }
|
||||
@@ -216,6 +292,9 @@ public class ConnectionConfig {
|
||||
String s = hostStr.trim();
|
||||
boolean tls = false;
|
||||
boolean tn3270e = true;
|
||||
boolean dynamic = false;
|
||||
int dynRows = 62;
|
||||
int dynCols = 160;
|
||||
|
||||
// Parse --proxy=<url> or -proxy=<url> flags
|
||||
ProxyType pType = ProxyType.NONE;
|
||||
@@ -287,6 +366,29 @@ public class ConnectionConfig {
|
||||
int colon = s.indexOf(':');
|
||||
s = s.substring(colon + 1);
|
||||
prefixFound = true;
|
||||
} else if (s.startsWith("D:") || s.startsWith("d:")) {
|
||||
dynamic = true;
|
||||
s = s.substring(2);
|
||||
prefixFound = true;
|
||||
} else if (s.toLowerCase().startsWith("dyn:") || s.toLowerCase().startsWith("dynamic:") ||
|
||||
s.toLowerCase().startsWith("dyn[") || s.toLowerCase().startsWith("dynamic[")) {
|
||||
int colon = s.indexOf(':');
|
||||
if (colon > 0) {
|
||||
String prefix = s.substring(0, colon);
|
||||
s = s.substring(colon + 1);
|
||||
prefixFound = true;
|
||||
dynamic = true;
|
||||
if (prefix.contains("[") && prefix.contains("]")) {
|
||||
String dim = prefix.substring(prefix.indexOf('[') + 1, prefix.indexOf(']'));
|
||||
String[] parts = dim.toLowerCase().split("x");
|
||||
if (parts.length == 2) {
|
||||
try {
|
||||
dynRows = Integer.parseInt(parts[0].trim());
|
||||
dynCols = Integer.parseInt(parts[1].trim());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +417,9 @@ public class ConnectionConfig {
|
||||
ConnectionConfig config = new ConnectionConfig(host, port, defaultModel != null ? defaultModel : TerminalModel.IBM_3279_4);
|
||||
config.setUseTls(tls);
|
||||
config.setTn3270eEnabled(tn3270e);
|
||||
if (dynamic) {
|
||||
config.setDynamicDimensions(dynRows, dynCols);
|
||||
}
|
||||
if (pType != ProxyType.NONE && pHost != null) {
|
||||
config.setProxy(pType, pHost, pPort, pUser, pPass);
|
||||
}
|
||||
@@ -328,7 +433,7 @@ public class ConnectionConfig {
|
||||
if (terminalName != null) {
|
||||
return terminalName;
|
||||
}
|
||||
if (dynamicModel) {
|
||||
if (isDynamicModel()) {
|
||||
return extendedDataStream ? "IBM-DYNAMIC-E" : "IBM-DYNAMIC";
|
||||
}
|
||||
return extendedDataStream ? model.getTerminalType() : model.getBaseTerminalType();
|
||||
|
||||
@@ -59,4 +59,32 @@ public enum ConnectionState {
|
||||
public boolean isFullSession() {
|
||||
return isNvt() || is3270();
|
||||
}
|
||||
|
||||
/**
|
||||
* Map to IBM Host On-Demand ECL connection state integer codes.
|
||||
* 0 = Disconnected, 1 = Connecting/Resolving, 2 = Connected (NVT/Unbound), 3 = Bound (Full 3270 session).
|
||||
*/
|
||||
public int toHoDStateCode() {
|
||||
switch (this) {
|
||||
case NOT_CONNECTED:
|
||||
return 0;
|
||||
case RECONNECTING:
|
||||
case RESOLVING:
|
||||
case TCP_PENDING:
|
||||
case TLS_PENDING:
|
||||
case PROXY_PENDING:
|
||||
case TELNET_PENDING:
|
||||
return 1;
|
||||
case CONNECTED_NVT:
|
||||
case CONNECTED_NVT_CHAR:
|
||||
case CONNECTED_UNBOUND:
|
||||
case CONNECTED_E_NVT:
|
||||
case CONNECTED_SSCP:
|
||||
return 2;
|
||||
case CONNECTED_3270:
|
||||
case CONNECTED_TN3270E:
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,16 @@ public class Telnet3270Client {
|
||||
public Telnet3270Client(ConnectionConfig config) {
|
||||
this.config = config;
|
||||
this.translator = new EbcdicTranslator(config.getCodePage());
|
||||
this.screenBuffer = new ScreenBuffer(config.getModel(), translator);
|
||||
if (config.isDynamicModel() || (config.getModel() != null && config.getModel().isDynamic())) {
|
||||
this.screenBuffer = new ScreenBuffer(
|
||||
haus.nightmare.lib3270j.protocol.DS3270Constants.MODEL_2_ROWS,
|
||||
haus.nightmare.lib3270j.protocol.DS3270Constants.MODEL_2_COLS,
|
||||
config.getDynamicRows(),
|
||||
config.getDynamicCols(),
|
||||
translator);
|
||||
} else {
|
||||
this.screenBuffer = new ScreenBuffer(config.getModel(), translator);
|
||||
}
|
||||
this.dsProcessor = new DataStreamProcessor(screenBuffer, translator);
|
||||
this.dsProcessor.getQueryReplyBuilder().setGraphicsMode(config.getGraphicsMode());
|
||||
this.fsm = new TelnetFSM(config, screenBuffer, dsProcessor);
|
||||
@@ -63,11 +72,21 @@ public class Telnet3270Client {
|
||||
inputProcessor.setGraphicsPlane(dsProcessor.getGraphicsPlane());
|
||||
inputProcessor.setGocaDecoder(dsProcessor.getGocaDecoder());
|
||||
|
||||
// Wire screen update to ECLXfer for CUT mode screen tracking
|
||||
// Wire screen update to ECLXfer for CUT mode screen tracking and ECLPS for event dispatching
|
||||
addScreenUpdateListener(new haus.nightmare.lib3270j.listener.ScreenUpdateListener() {
|
||||
@Override public void onScreenUpdated() { xfer.onScreenUpdated(); }
|
||||
@Override public void onScreenSizeChanged(int rows, int cols) {}
|
||||
@Override public void onSoundAlarm() {}
|
||||
@Override public void onScreenUpdated() {
|
||||
xfer.onScreenUpdated();
|
||||
ps.notifyPSUpdate(0, 0, screenBuffer.getRows() - 1, screenBuffer.getCols() - 1, true);
|
||||
}
|
||||
@Override public void onCursorMoved(int oldAddress, int newAddress) {
|
||||
ps.notifyCursorMoved(oldAddress, newAddress);
|
||||
}
|
||||
@Override public void onScreenSizeChanged(int rows, int cols) {
|
||||
ps.notifyScreenResized(rows, cols);
|
||||
}
|
||||
@Override public void onSoundAlarm() {
|
||||
ps.notifyAlarm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,6 +109,52 @@ public class Telnet3270Client {
|
||||
fsm.onConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the configured host synchronously, blocking until the full data session is established
|
||||
* (or timeout expires).
|
||||
* @param timeoutMs maximum time to wait in milliseconds
|
||||
* @return true if successfully connected, false if timed out
|
||||
* @throws IOException if network connection fails
|
||||
*/
|
||||
public boolean connect(long timeoutMs) throws IOException {
|
||||
connect();
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - start < timeoutMs) {
|
||||
ConnectionState state = getConnectionState();
|
||||
if (state.isFullSession() || (state.isFullyConnected() && isConnected())) {
|
||||
return true;
|
||||
}
|
||||
if (state == ConnectionState.NOT_CONNECTED && !isConnected()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(25);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return getConnectionState().isFullSession() || isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the configured host synchronously and block until the presentation space matches
|
||||
* the specified screen descriptor.
|
||||
* @param timeoutMs maximum time to wait in milliseconds
|
||||
* @param desc ECLScreenDesc descriptor to match against
|
||||
* @return true if successfully connected and screen matched, false otherwise
|
||||
* @throws IOException if network connection fails
|
||||
*/
|
||||
public boolean connect(long timeoutMs, haus.nightmare.lib3270j.ecl.ECLScreenDesc desc) throws IOException {
|
||||
long start = System.currentTimeMillis();
|
||||
if (!connect(timeoutMs)) {
|
||||
return false;
|
||||
}
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
long remaining = Math.max(1, timeoutMs - elapsed);
|
||||
return ps.waitForScreen(desc, remaining);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the host.
|
||||
*/
|
||||
@@ -101,6 +166,35 @@ public class Telnet3270Client {
|
||||
fsm.onDisconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from host with synchronous teardown.
|
||||
* @param timeoutMs maximum time to wait for graceful disconnect in milliseconds
|
||||
*/
|
||||
public void disconnect(long timeoutMs) {
|
||||
disconnect();
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - start < timeoutMs) {
|
||||
if (getConnectionState() == ConnectionState.NOT_CONNECTED && !isConnected()) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** HoD StopCommunication compatibility alias. */
|
||||
public void stopCommunication() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
public void stopCommunication(long timeoutMs) {
|
||||
disconnect(timeoutMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if connected (any state past TCP pending).
|
||||
*/
|
||||
@@ -114,11 +208,20 @@ public class Telnet3270Client {
|
||||
fsm.addConnectionListener(l);
|
||||
}
|
||||
|
||||
public void removeConnectionListener(ConnectionListener l) {
|
||||
fsm.removeConnectionListener(l);
|
||||
}
|
||||
|
||||
public void addScreenUpdateListener(ScreenUpdateListener l) {
|
||||
fsm.addScreenUpdateListener(l);
|
||||
dsProcessor.addScreenUpdateListener(l);
|
||||
}
|
||||
|
||||
public void removeScreenUpdateListener(ScreenUpdateListener l) {
|
||||
fsm.removeScreenUpdateListener(l);
|
||||
dsProcessor.removeScreenUpdateListener(l);
|
||||
}
|
||||
|
||||
public void addSCSInboundListener(haus.nightmare.lib3270j.listener.SCSInboundListener l) {
|
||||
fsm.addSCSInboundListener(l);
|
||||
}
|
||||
@@ -150,6 +253,9 @@ public class Telnet3270Client {
|
||||
/** Get the data stream processor. */
|
||||
public DataStreamProcessor getDataStreamProcessor() { return dsProcessor; }
|
||||
|
||||
/** Get the underlying telnet connection. */
|
||||
public TelnetConnection getConnection() { return connection; }
|
||||
|
||||
/** Get the connection config. */
|
||||
public ConnectionConfig getConfig() { return config; }
|
||||
|
||||
@@ -198,6 +304,37 @@ public class Telnet3270Client {
|
||||
fsm.sendNVTString(s);
|
||||
}
|
||||
|
||||
/** Send an NVT key event mapped through NVT processor. */
|
||||
public boolean sendNVTKey(int keyCode, char keyChar, boolean shift, boolean ctrl, boolean alt) throws IOException {
|
||||
haus.nightmare.lib3270j.nvt.NvtProcessor nvt = getNvtProcessor();
|
||||
if (nvt != null) {
|
||||
String seq = nvt.mapKey(keyCode, keyChar, shift, ctrl, alt);
|
||||
if (seq != null && !seq.isEmpty()) {
|
||||
fsm.sendNvtData(seq.getBytes(java.nio.charset.StandardCharsets.US_ASCII));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addNvtTitleListener(haus.nightmare.lib3270j.nvt.NvtProcessor.NvtTitleListener l) {
|
||||
if (getNvtProcessor() != null) {
|
||||
getNvtProcessor().addTitleListener(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNvtTitleListener(haus.nightmare.lib3270j.nvt.NvtProcessor.NvtTitleListener l) {
|
||||
if (getNvtProcessor() != null) {
|
||||
getNvtProcessor().removeTitleListener(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void setNvtClipboardHandler(haus.nightmare.lib3270j.nvt.NvtProcessor.ClipboardHandler h) {
|
||||
if (getNvtProcessor() != null) {
|
||||
getNvtProcessor().setClipboardHandler(h);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Convenience input methods & HoD compatibility ==========
|
||||
|
||||
/** Type a character at the cursor position. */
|
||||
|
||||
@@ -14,7 +14,8 @@ public enum TerminalModel {
|
||||
IBM_3279_2(2, true, MODEL_2_ROWS, MODEL_2_COLS, MODEL_2_ROWS, MODEL_2_COLS),
|
||||
IBM_3279_3(3, true, MODEL_2_ROWS, MODEL_2_COLS, MODEL_3_ROWS, MODEL_3_COLS),
|
||||
IBM_3279_4(4, true, MODEL_2_ROWS, MODEL_2_COLS, MODEL_4_ROWS, MODEL_4_COLS),
|
||||
IBM_3279_5(5, true, MODEL_2_ROWS, MODEL_2_COLS, MODEL_5_ROWS, MODEL_5_COLS);
|
||||
IBM_3279_5(5, true, MODEL_2_ROWS, MODEL_2_COLS, MODEL_5_ROWS, MODEL_5_COLS),
|
||||
IBM_DYNAMIC(0, true, MODEL_2_ROWS, MODEL_2_COLS, 62, 160);
|
||||
|
||||
private final int modelNumber;
|
||||
private final boolean color;
|
||||
@@ -40,12 +41,17 @@ public enum TerminalModel {
|
||||
public int getDefaultCols() { return defaultCols; }
|
||||
public int getAlternateRows() { return alternateRows; }
|
||||
public int getAlternateCols() { return alternateCols; }
|
||||
public boolean isDynamic() { return modelNumber == 0; }
|
||||
|
||||
/**
|
||||
* Returns the terminal type string for TN3270E negotiation.
|
||||
* e.g., "IBM-3279-4-E" for a color model 4 with extended data stream.
|
||||
* e.g., "IBM-3279-4-E" for a color model 4 with extended data stream,
|
||||
* or "IBM-DYNAMIC-E" for dynamic model.
|
||||
*/
|
||||
public String getTerminalType() {
|
||||
if (modelNumber == 0) {
|
||||
return "IBM-DYNAMIC-E";
|
||||
}
|
||||
return String.format("IBM-327%c-%d-E", color ? '9' : '8', modelNumber);
|
||||
}
|
||||
|
||||
@@ -53,6 +59,9 @@ public enum TerminalModel {
|
||||
* Returns the base terminal type without "-E" suffix (for non-extended mode).
|
||||
*/
|
||||
public String getBaseTerminalType() {
|
||||
if (modelNumber == 0) {
|
||||
return "IBM-DYNAMIC";
|
||||
}
|
||||
return String.format("IBM-327%c-%d", color ? '9' : '8', modelNumber);
|
||||
}
|
||||
|
||||
@@ -60,6 +69,9 @@ public enum TerminalModel {
|
||||
* Look up a model by number and color mode.
|
||||
*/
|
||||
public static TerminalModel forModel(int number, boolean isColor) {
|
||||
if (number == 0) {
|
||||
return IBM_DYNAMIC;
|
||||
}
|
||||
for (TerminalModel m : values()) {
|
||||
if (m.modelNumber == number && m.color == isColor) {
|
||||
return m;
|
||||
|
||||
@@ -106,6 +106,19 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
|
||||
@Override
|
||||
public String ebcdicToString(byte[] ebcdic, int offset, int length) {
|
||||
return ebcdicToString(ebcdic, offset, length, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an EBCDIC byte array slice to a Unicode String with optional SO/SI escape preservation.
|
||||
*
|
||||
* @param ebcdic source byte array
|
||||
* @param offset start offset
|
||||
* @param length number of bytes
|
||||
* @param preserveSOSI if true, preserves Shift-Out (\u000E) and Shift-In (\u000F) control characters
|
||||
* @return translated Unicode String
|
||||
*/
|
||||
public String ebcdicToString(byte[] ebcdic, int offset, int length, boolean preserveSOSI) {
|
||||
if (ebcdic == null || length <= 0) return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
@@ -117,9 +130,15 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
int b = ebcdic[i] & 0xFF;
|
||||
if (b == SO) {
|
||||
inDBCS = true;
|
||||
if (preserveSOSI) {
|
||||
sb.append((char) SO);
|
||||
}
|
||||
i++;
|
||||
} else if (b == SI) {
|
||||
inDBCS = false;
|
||||
if (preserveSOSI) {
|
||||
sb.append((char) SI);
|
||||
}
|
||||
i++;
|
||||
} else if (inDBCS) {
|
||||
if (i + 1 < end) {
|
||||
@@ -127,13 +146,22 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
if (b2 == SI) {
|
||||
// Orphaned single byte before SI
|
||||
inDBCS = false;
|
||||
if (preserveSOSI) {
|
||||
sb.append(ebcdicToUnicode(b));
|
||||
sb.append((char) SI);
|
||||
}
|
||||
i += 2;
|
||||
} else if (b2 == SO) {
|
||||
// Unmatched byte followed by another SO
|
||||
sb.append(ebcdicToUnicode(b));
|
||||
i++;
|
||||
} else {
|
||||
sb.append(dbcsToUnicode(b, b2));
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
// Trailing byte
|
||||
// Trailing single byte inside unclosed DBCS shift
|
||||
sb.append(ebcdicToUnicode(b));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
@@ -147,14 +175,39 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
|
||||
@Override
|
||||
public byte[] stringToEbcdic(String s) {
|
||||
return stringToEbcdic(s, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a Unicode String to EBCDIC byte array with optional parsing of embedded SO/SI markers.
|
||||
*
|
||||
* @param s input Unicode string
|
||||
* @param parseSOSIMarkers whether to interpret embedded \u000E (SO) and \u000F (SI) characters
|
||||
* @return EBCDIC byte array with balanced SO/SI framing
|
||||
*/
|
||||
public byte[] stringToEbcdic(String s, boolean parseSOSIMarkers) {
|
||||
if (s == null || s.isEmpty()) return new byte[0];
|
||||
|
||||
// Manual state machine encoding
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(s.length() * 2);
|
||||
boolean inDBCS = false;
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
if (parseSOSIMarkers && c == (char) SO) {
|
||||
if (!inDBCS) {
|
||||
out.write(SO);
|
||||
inDBCS = true;
|
||||
}
|
||||
continue;
|
||||
} else if (parseSOSIMarkers && c == (char) SI) {
|
||||
if (inDBCS) {
|
||||
out.write(SI);
|
||||
inDBCS = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int dbcsCode = unicodeToDbcs(c);
|
||||
|
||||
if (dbcsCode >= 0) {
|
||||
@@ -175,10 +228,26 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-close unclosed DBCS shift sequence
|
||||
if (inDBCS) {
|
||||
out.write(SI);
|
||||
}
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to decode an EBCDIC byte array to UTF-8 String preserving SO/SI control codes.
|
||||
*/
|
||||
public String ebcdicToUtf8WithSOSI(byte[] ebcdic) {
|
||||
if (ebcdic == null) return "";
|
||||
return ebcdicToString(ebcdic, 0, ebcdic.length, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to encode a UTF-8/Unicode String with embedded SO/SI markers to EBCDIC.
|
||||
*/
|
||||
public byte[] utf8WithSOSIToEbcdic(String s) {
|
||||
return stringToEbcdic(s, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +69,88 @@ public interface CodePage {
|
||||
* Returns -1 if unmappable.
|
||||
*/
|
||||
int unicodeToDbcs(char unicode);
|
||||
|
||||
/**
|
||||
* Convert an EBCDIC byte buffer to a char array matching IBM HoD conversion.
|
||||
*/
|
||||
default char[] convBuffByte2Char(byte[] buf, int offset, int length) {
|
||||
if (buf == null || length <= 0) return new char[0];
|
||||
char[] out = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
out[i] = ebcdicToUnicode(buf[offset + i] & 0xFF);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a char array to an EBCDIC byte array matching IBM HoD conversion.
|
||||
*/
|
||||
default byte[] convBuffChar2Byte(char[] buf, int offset, int length) {
|
||||
if (buf == null || length <= 0) return new byte[0];
|
||||
byte[] out = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
out[i] = unicodeToEbcdicSafe(buf[offset + i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a HODByteToCharConverter instance backed by this CodePage.
|
||||
*/
|
||||
default haus.nightmare.lib3270j.converters.HODByteToCharConverter getByteToCharConverter() {
|
||||
if (isDBCS()) {
|
||||
return new haus.nightmare.lib3270j.converters.ByteToCharDBCS_EBCDIC(this);
|
||||
} else {
|
||||
return new haus.nightmare.lib3270j.converters.ByteToCharSingleByte(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a HODCharToByteConverter instance backed by this CodePage.
|
||||
*/
|
||||
default haus.nightmare.lib3270j.converters.HODCharToByteConverter getCharToByteConverter() {
|
||||
if (isDBCS()) {
|
||||
return new haus.nightmare.lib3270j.converters.CharToByteDBCS_EBCDIC(this);
|
||||
} else {
|
||||
return new haus.nightmare.lib3270j.converters.CharToByteSingleByte(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to test if a pair of characters forms a Unicode surrogate pair.
|
||||
*/
|
||||
static boolean isSurrogate(char high, char low) {
|
||||
return Character.isSurrogatePair(high, low);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to test if a character is a high surrogate.
|
||||
*/
|
||||
static boolean isHighSurrogate(char c) {
|
||||
return Character.isHighSurrogate(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to test if a character is a low surrogate.
|
||||
*/
|
||||
static boolean isLowSurrogate(char c) {
|
||||
return Character.isLowSurrogate(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper matching IBM HoD CodePage.ComposeChar to combine characters.
|
||||
*/
|
||||
static boolean ComposeChar(char[] chars) {
|
||||
if (chars == null || chars.length < 2) return false;
|
||||
if (chars[1] >= '\u0300' && chars[1] <= '\u036F') {
|
||||
String decomposed = new String(chars, 0, 2);
|
||||
String normalized = java.text.Normalizer.normalize(decomposed, java.text.Normalizer.Form.NFC);
|
||||
if (normalized.length() == 1) {
|
||||
chars[0] = normalized.charAt(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ public class CodePageRegistry {
|
||||
register(new Cp937.Cp1371());
|
||||
register(new Cp933());
|
||||
|
||||
// Register Phase 8 Extended EBCDIC Codepages (Arabic, Hebrew, Thai, Cyrillic, Turkish, Extended DBCS)
|
||||
registerExtendedCodepages();
|
||||
|
||||
// Setup common aliases
|
||||
addAlias("us", "037");
|
||||
addAlias("usa", "037");
|
||||
@@ -154,7 +157,25 @@ public class CodePageRegistry {
|
||||
|
||||
public static String normalizeKey(String name) {
|
||||
if (name == null) return "";
|
||||
String s = name.trim().toLowerCase();
|
||||
String s = name.trim();
|
||||
// Strip package qualifiers if present (e.g. com.ibm.eNetwork.HOD.converters.onea.ByteToCharCp273)
|
||||
int lastDot = Math.max(s.lastIndexOf('.'), s.lastIndexOf('/'));
|
||||
if (lastDot >= 0 && lastDot < s.length() - 1) {
|
||||
s = s.substring(lastDot + 1);
|
||||
}
|
||||
|
||||
// Strip HoD converter class prefixes
|
||||
for (String pfx : new String[]{
|
||||
"HODByteToChar", "HODCharToByte", "ByteToChar", "CharToByte",
|
||||
"ConverterBIDIPrinter", "ConverterFT", "ConverterJDK", "ConverterVT", "PrtConverter"
|
||||
}) {
|
||||
if (s.startsWith(pfx)) {
|
||||
s = s.substring(pfx.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s = s.toLowerCase();
|
||||
s = s.replace("_", "").replace("-", "");
|
||||
if (s.startsWith("ebcdiccp")) {
|
||||
s = s.substring(8);
|
||||
@@ -171,13 +192,12 @@ public class CodePageRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a code page by ID or alias.
|
||||
* If not found in built-ins, attempts to load via java.nio.charset.Charset.
|
||||
* Falls back to CP037 if completely unresolvable.
|
||||
* Look up a code page by ID, alias, or converter name without fallback to CP037.
|
||||
* Returns null if unresolvable.
|
||||
*/
|
||||
public static CodePage getCodePage(String name) {
|
||||
public static CodePage resolveCodePage(String name) {
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
return CODE_PAGES.get("037");
|
||||
return null;
|
||||
}
|
||||
|
||||
String raw = name.trim();
|
||||
@@ -195,6 +215,9 @@ public class CodePageRegistry {
|
||||
if (targetId != null) {
|
||||
cp = CODE_PAGES.get(targetId);
|
||||
if (cp != null) return cp;
|
||||
String normTarget = normalizeKey(targetId);
|
||||
cp = CODE_PAGES.get(normTarget);
|
||||
if (cp != null) return cp;
|
||||
}
|
||||
|
||||
// Try standard NIO Charset dynamic adapter
|
||||
@@ -202,22 +225,217 @@ public class CodePageRegistry {
|
||||
if (Charset.isSupported(raw)) {
|
||||
return new NioCodePageAdapter(raw);
|
||||
}
|
||||
if (Charset.isSupported(norm)) {
|
||||
return new NioCodePageAdapter(norm);
|
||||
}
|
||||
String ibmName = "IBM" + norm;
|
||||
if (Charset.isSupported(ibmName)) {
|
||||
return new NioCodePageAdapter(ibmName);
|
||||
}
|
||||
String ibmDashName = "IBM-" + norm;
|
||||
if (Charset.isSupported(ibmDashName)) {
|
||||
return new NioCodePageAdapter(ibmDashName);
|
||||
}
|
||||
String cpName = "Cp" + norm;
|
||||
if (Charset.isSupported(cpName)) {
|
||||
return new NioCodePageAdapter(cpName);
|
||||
}
|
||||
String isoName = "ISO-8859-" + norm.replace("8859", "");
|
||||
if (Charset.isSupported(isoName)) {
|
||||
return new NioCodePageAdapter(isoName);
|
||||
}
|
||||
String winName = "windows-" + norm;
|
||||
if (Charset.isSupported(winName)) {
|
||||
return new NioCodePageAdapter(winName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.fine("Dynamic charset loading failed for " + name + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up a code page by ID or alias.
|
||||
* If not found in built-ins, attempts to load via java.nio.charset.Charset.
|
||||
* Falls back to CP037 if completely unresolvable.
|
||||
*/
|
||||
public static CodePage get(String name) {
|
||||
return getCodePage(name);
|
||||
}
|
||||
|
||||
public static CodePage getDefault() {
|
||||
return getCodePage("037");
|
||||
}
|
||||
|
||||
public static CodePage getCodePage(String name) {
|
||||
CodePage cp = resolveCodePage(name);
|
||||
if (cp != null) {
|
||||
return cp;
|
||||
}
|
||||
|
||||
log.warning("CodePage not recognized: '" + name + "'; falling back to CP037");
|
||||
return CODE_PAGES.get("037");
|
||||
}
|
||||
|
||||
/**
|
||||
* Register extended EBCDIC codepages from HoD v14 converters:
|
||||
* - Arabic: Cp420, Cp424
|
||||
* - Hebrew: Cp424, Cp803
|
||||
* - Thai: Cp838, Cp1160
|
||||
* - Cyrillic: Cp1025, Cp1123, Cp1154, Cp880
|
||||
* - Turkish: Cp1155, Cp905
|
||||
* - Extended Chinese DBCS: Cp1388, Cp1371
|
||||
*/
|
||||
public static void registerExtendedCodepages() {
|
||||
// Arabic & Hebrew
|
||||
register(new Cp420());
|
||||
register(new Cp424());
|
||||
register(new Cp803());
|
||||
|
||||
// Thai
|
||||
register(new Cp838());
|
||||
register(new Cp1160());
|
||||
|
||||
// Cyrillic / Russian / Ukrainian
|
||||
register(new Cp1025());
|
||||
register(new Cp1123());
|
||||
register(new Cp1154());
|
||||
register(new Cp880());
|
||||
|
||||
// Turkish
|
||||
register(new Cp1155());
|
||||
register(new Cp905());
|
||||
|
||||
// Extended Chinese DBCS
|
||||
register(new Cp1388());
|
||||
register(new Cp1371());
|
||||
|
||||
// Setup Extended Aliases
|
||||
addAlias("ar", "420");
|
||||
addAlias("arabic", "420");
|
||||
addAlias("ebcdic-cp-ar", "420");
|
||||
|
||||
addAlias("he", "424");
|
||||
addAlias("hebrew", "424");
|
||||
addAlias("hebrew-lowercase", "424");
|
||||
addAlias("ebcdic-cp-he", "424");
|
||||
|
||||
addAlias("hebrew-old", "803");
|
||||
addAlias("israel", "803");
|
||||
addAlias("iw", "803");
|
||||
addAlias("ebcdic-cp-he-old", "803");
|
||||
|
||||
addAlias("th", "838");
|
||||
addAlias("thai", "838");
|
||||
addAlias("ebcdic-cp-th", "838");
|
||||
addAlias("thai-euro", "1160");
|
||||
|
||||
addAlias("ru", "1025");
|
||||
addAlias("russian", "1025");
|
||||
addAlias("cyrillic", "1025");
|
||||
addAlias("ebcdic-cp-ru", "1025");
|
||||
|
||||
addAlias("ukraine", "1123");
|
||||
addAlias("ukrainian", "1123");
|
||||
addAlias("ebcdic-cp-ua", "1123");
|
||||
|
||||
addAlias("cyrillic-euro", "1154");
|
||||
addAlias("ru-euro", "1154");
|
||||
addAlias("russian-euro", "1154");
|
||||
|
||||
addAlias("cyrillic-russian", "880");
|
||||
addAlias("ru-old", "880");
|
||||
|
||||
addAlias("turkish-euro", "1155");
|
||||
addAlias("tr-euro", "1155");
|
||||
addAlias("turkish-latin3", "905");
|
||||
addAlias("tr-latin3", "905");
|
||||
|
||||
addAlias("chinese-ext-simplified", "1388");
|
||||
addAlias("zh-simplified-ext", "1388");
|
||||
addAlias("zh-ext", "1388");
|
||||
addAlias("chinese-ext-traditional", "1371");
|
||||
addAlias("zh-traditional-ext", "1371");
|
||||
addAlias("zh-tw-ext", "1371");
|
||||
|
||||
// HoD Converter aliases mapping all HoD converter names to CodePage / Charset
|
||||
addAlias("1390", "930");
|
||||
addAlias("1390jis2004", "930");
|
||||
addAlias("1399", "939");
|
||||
addAlias("1399jis2004", "939");
|
||||
addAlias("937macau", "937");
|
||||
addAlias("1364", "933");
|
||||
addAlias("1379", "937");
|
||||
addAlias("274", "500");
|
||||
addAlias("275", "037");
|
||||
addAlias("924", "1047");
|
||||
addAlias("1153", "870");
|
||||
addAlias("1156", "1025");
|
||||
addAlias("1157", "1025");
|
||||
addAlias("1158", "1025");
|
||||
addAlias("1166", "1025");
|
||||
addAlias("1112", "1025");
|
||||
addAlias("1122", "1025");
|
||||
addAlias("1137", "037");
|
||||
addAlias("1008", "420");
|
||||
addAlias("449", "420");
|
||||
addAlias("1089", "420");
|
||||
addAlias("1134", "424");
|
||||
addAlias("1349", "424");
|
||||
addAlias("8585", "875");
|
||||
addAlias("8586", "875");
|
||||
addAlias("220", "284");
|
||||
addAlias("big5550", "937");
|
||||
addAlias("cns", "937");
|
||||
addAlias("tca", "937");
|
||||
addAlias("ks25550", "933");
|
||||
addAlias("jis", "930");
|
||||
addAlias("euc", "937");
|
||||
addAlias("singlebyte", "037");
|
||||
addAlias("dbcsebcdic", "930");
|
||||
addAlias("dbcsebcdicnibm", "930");
|
||||
addAlias("dbcsebcdicibm", "930");
|
||||
addAlias("dbcsascii", "930");
|
||||
addAlias("encodings", "037");
|
||||
addAlias("1011", "037");
|
||||
addAlias("1012", "037");
|
||||
addAlias("1020", "037");
|
||||
addAlias("1021", "037");
|
||||
addAlias("1023", "037");
|
||||
addAlias("1090", "037");
|
||||
addAlias("1101", "037");
|
||||
addAlias("1102", "037");
|
||||
addAlias("1103", "037");
|
||||
addAlias("1104", "037");
|
||||
addAlias("1105", "037");
|
||||
addAlias("1106", "037");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a code page or converter is registered or resolvable.
|
||||
*/
|
||||
public static boolean hasCodePage(String name) {
|
||||
if (name == null || name.trim().isEmpty()) return false;
|
||||
return resolveCodePage(name) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience factory method to get a HODByteToCharConverter by name or alias.
|
||||
*/
|
||||
public static haus.nightmare.lib3270j.converters.HODByteToCharConverter getByteToCharConverter(String name)
|
||||
throws haus.nightmare.lib3270j.converters.HODUnsupportedCodepageException {
|
||||
return haus.nightmare.lib3270j.converters.HODByteToCharConverter.getHODConverter(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience factory method to get a HODCharToByteConverter by name or alias.
|
||||
*/
|
||||
public static haus.nightmare.lib3270j.converters.HODCharToByteConverter getCharToByteConverter(String name)
|
||||
throws haus.nightmare.lib3270j.converters.HODUnsupportedCodepageException {
|
||||
return haus.nightmare.lib3270j.converters.HODCharToByteConverter.getHODConverter(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an unmodifiable list of all registered built-in CodePages.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1025 (Cyrillic Multilingual EBCDIC - Russian, Bulgarian, Belarusian, Serbian, Macedonian).
|
||||
* CCSID / CPGID: 1025, GCSGID: 1150.
|
||||
*/
|
||||
public class Cp1025 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1025";
|
||||
public static final String DESCRIPTION = "Cyrillic Multilingual EBCDIC";
|
||||
public static final int CPGID = 1025;
|
||||
public static final int GCSGID = 1150;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x044F, 0x044E, 0x044D, 0x044C, 0x044B, 0x044A, 0x0449,
|
||||
0x0448, 0x0447, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x0446, 0x0445, 0x0444, 0x0443, 0x0442, 0x0441, 0x0440,
|
||||
0x043F, 0x043E, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x043D, 0x043C, 0x043B, 0x043A, 0x0439, 0x0438,
|
||||
0x0437, 0x0436, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x0435, 0x0434, 0x0433, 0x0432, 0x0431, 0x0430, 0x0451, 0x0453,
|
||||
0x0452, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x0454, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A,
|
||||
// 90-9F
|
||||
0x045B, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x045C, 0x045E, 0x045F, 0x0401, 0x0402, 0x0403,
|
||||
// A0-AF
|
||||
0x0404, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040A,
|
||||
// B0-BF
|
||||
0x040B, 0x00A3, 0x040C, 0x00B7, 0x00A9, 0x040E, 0x040F, 0x0410,
|
||||
0x0411, 0x0412, 0x00AC, 0x007C, 0x0413, 0x0414, 0x0415, 0x0416,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
|
||||
};
|
||||
|
||||
public Cp1025() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "1025", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1123 (Cyrillic Ukraine EBCDIC).
|
||||
* CCSID / CPGID: 1123, GCSGID: 1399.
|
||||
*/
|
||||
public class Cp1123 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1123";
|
||||
public static final String DESCRIPTION = "Cyrillic Ukraine EBCDIC";
|
||||
public static final int CPGID = 1123;
|
||||
public static final int GCSGID = 1399;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x044F, 0x044E, 0x044D, 0x044C, 0x044B, 0x044A, 0x0449,
|
||||
0x0448, 0x0447, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x0446, 0x0445, 0x0444, 0x0443, 0x0442, 0x0441, 0x0440,
|
||||
0x043F, 0x043E, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x043D, 0x043C, 0x043B, 0x043A, 0x0439, 0x0438,
|
||||
0x0437, 0x0436, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x0435, 0x0434, 0x0433, 0x0432, 0x0431, 0x0430, 0x0451, 0x0491,
|
||||
0x0454, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x0456, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x0457, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
|
||||
// 90-9F
|
||||
0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
|
||||
// A0-AF
|
||||
0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
|
||||
// B0-BF
|
||||
0x00A2, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
|
||||
0x00BD, 0x00BE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
|
||||
};
|
||||
|
||||
public Cp1123() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "1123", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1154 (Cyrillic Multilingual with Euro \u20AC).
|
||||
* CCSID / CPGID: 1154, GCSGID: 1305.
|
||||
*/
|
||||
public class Cp1154 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1154";
|
||||
public static final String DESCRIPTION = "Cyrillic Multilingual EBCDIC (with Euro \u20AC)";
|
||||
public static final int CPGID = 1154;
|
||||
public static final int GCSGID = 1305;
|
||||
|
||||
public static final int[] MAPPING = new int[256];
|
||||
|
||||
static {
|
||||
System.arraycopy(Cp1025.MAPPING, 0, MAPPING, 0, 256);
|
||||
MAPPING[0x9F] = 0x20AC; // Euro character \u20AC
|
||||
}
|
||||
|
||||
public Cp1154() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "1154", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1155 (Turkey - Turkish Latin-5 with Euro \u20AC).
|
||||
* CCSID / CPGID: 1155, GCSGID: 1306.
|
||||
*/
|
||||
public class Cp1155 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1155";
|
||||
public static final String DESCRIPTION = "Turkey - Turkish Latin-5 (with Euro \u20AC)";
|
||||
public static final int CPGID = 1155;
|
||||
public static final int GCSGID = 1306;
|
||||
|
||||
public static final int[] MAPPING = new int[256];
|
||||
|
||||
static {
|
||||
System.arraycopy(Cp1026.MAPPING, 0, MAPPING, 0, 256);
|
||||
MAPPING[0x9F] = 0x20AC; // Euro character \u20AC
|
||||
}
|
||||
|
||||
public Cp1155() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "1155", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1160 (Thai EBCDIC with Euro \u20AC).
|
||||
* CCSID / CPGID: 1160, GCSGID: 1176.
|
||||
*/
|
||||
public class Cp1160 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1160";
|
||||
public static final String DESCRIPTION = "Thai EBCDIC (with Euro \u20AC)";
|
||||
public static final int CPGID = 1160;
|
||||
public static final int GCSGID = 1176;
|
||||
|
||||
public static final int[] MAPPING = new int[256];
|
||||
|
||||
static {
|
||||
System.arraycopy(Cp838.MAPPING, 0, MAPPING, 0, 256);
|
||||
MAPPING[0x9F] = 0x20AC; // Euro character \u20AC
|
||||
}
|
||||
|
||||
public Cp1160() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "1160", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1371 (Traditional Chinese Extended Mixed DBCS).
|
||||
* CCSID / CPGID: 1371, GCSGID: 1174.
|
||||
*/
|
||||
public class Cp1371 extends AbstractDBCSCodePage {
|
||||
|
||||
public static final String ID = "1371";
|
||||
public static final String DESCRIPTION = "Traditional Chinese Extended Mixed DBCS";
|
||||
public static final int CPGID = 1371;
|
||||
public static final int GCSGID = 1174;
|
||||
|
||||
public Cp1371() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp037.MAPPING, "x-IBM1371");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1388 (Simplified Chinese Extended Mixed DBCS).
|
||||
* CCSID / CPGID: 1388, GCSGID: 1175.
|
||||
*/
|
||||
public class Cp1388 extends AbstractDBCSCodePage {
|
||||
|
||||
public static final String ID = "1388";
|
||||
public static final String DESCRIPTION = "Simplified Chinese Extended Mixed DBCS";
|
||||
public static final int CPGID = 1388;
|
||||
public static final int GCSGID = 1175;
|
||||
|
||||
public Cp1388() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp037.MAPPING, "x-IBM1388");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 420 (Arabic Bilingual EBCDIC).
|
||||
* CCSID / CPGID: 420, GCSGID: 235.
|
||||
*/
|
||||
public class Cp420 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "420";
|
||||
public static final String DESCRIPTION = "Arabic Bilingual EBCDIC";
|
||||
public static final int CPGID = 420;
|
||||
public static final int GCSGID = 235;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x0640, 0xFE83, 0xFE87, 0xFE85, 0xFE81, 0xFE80, 0x0621,
|
||||
0xFE8D, 0xFE8B, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0xFE8E, 0xFE8F, 0xFE91, 0xFE93, 0xFE95, 0xFE97, 0xFE99,
|
||||
0xFE9B, 0xFE9D, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0xFE9F, 0xFEA1, 0xFEA3, 0xFEA5, 0xFEA7, 0xFEA9,
|
||||
0xFEAB, 0xFEAD, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0xFEAF, 0xFEB1, 0xFEB3, 0xFEB5, 0xFEB7, 0xFEB9, 0xFEBB, 0xFEBD,
|
||||
0xFEBF, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0xFEC1, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0xFEC3, 0xFEC5, 0xFEC7, 0xFEC9, 0xFECB, 0xFECD,
|
||||
// 90-9F
|
||||
0xFECF, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0xFED1, 0xFED3, 0xFED5, 0xFED7, 0xFED9, 0xFEDB,
|
||||
// A0-AF
|
||||
0xFEDD, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0xFEDF, 0xFEE1, 0xFEE3, 0xFEE5, 0xFEE7, 0xFEE9,
|
||||
// B0-BF
|
||||
0xFEEB, 0xFEED, 0xFEEF, 0xFEF1, 0xFEF3, 0xFEF5, 0xFEF7, 0xFEF9,
|
||||
0xFEFB, 0x00AE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x060C, 0x061B, 0x061F, 0x0628, 0x062A, 0x062B,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631,
|
||||
// E0-EF
|
||||
0x005C, 0x0632, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, 0x0638,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x0639, 0x063A, 0x0641, 0x0642, 0x0643, 0x009F,
|
||||
};
|
||||
|
||||
public Cp420() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "420", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 424 (Hebrew with Lowercase EBCDIC).
|
||||
* CCSID / CPGID: 424, GCSGID: 941.
|
||||
*/
|
||||
public class Cp424 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "424";
|
||||
public static final String DESCRIPTION = "Hebrew (with Lowercase) EBCDIC";
|
||||
public static final int CPGID = 424;
|
||||
public static final int GCSGID = 941;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6,
|
||||
0x05D7, 0x05D8, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||
0x05E0, 0x05E1, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
|
||||
0x05E8, 0x05E9, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x05EA, 0x00A0, 0x2017, 0x00B8, 0x00A8, 0x00B4, 0x00AA, 0x00BA,
|
||||
0x00DF, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
|
||||
// 90-9F
|
||||
0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
|
||||
// A0-AF
|
||||
0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
|
||||
// B0-BF
|
||||
0x00A2, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
|
||||
0x00BD, 0x00BE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F,
|
||||
};
|
||||
|
||||
public Cp424() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "424", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 803 (Hebrew Old / Standard EBCDIC).
|
||||
* CCSID / CPGID: 803, GCSGID: 1147.
|
||||
*/
|
||||
public class Cp803 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "803";
|
||||
public static final String DESCRIPTION = "Hebrew Old / Standard EBCDIC";
|
||||
public static final int CPGID = 803;
|
||||
public static final int GCSGID = 1147;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
|
||||
0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00EC, 0x00DF, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5,
|
||||
0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x00D8, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6,
|
||||
0x05D7, 0x05D8, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
|
||||
// 90-9F
|
||||
0x00B0, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||
0x05E0, 0x05E1, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
|
||||
// A0-AF
|
||||
0x00B5, 0x007E, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
|
||||
0x05E8, 0x05E9, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
|
||||
// B0-BF
|
||||
0x05EA, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
|
||||
0x00BD, 0x00BE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F,
|
||||
};
|
||||
|
||||
public Cp803() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "803", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 838 (Thai EBCDIC).
|
||||
* CCSID / CPGID: 838, GCSGID: 1176.
|
||||
*/
|
||||
public class Cp838 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "838";
|
||||
public static final String DESCRIPTION = "Thai EBCDIC";
|
||||
public static final int CPGID = 838;
|
||||
public static final int GCSGID = 1176;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
|
||||
0x0E08, 0x0E09, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, 0x0E10,
|
||||
0x0E11, 0x0E12, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, 0x0E18,
|
||||
0x0E19, 0x0E1A, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, 0x0E20, 0x0E21, 0x0E22,
|
||||
0x0E23, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x0E24, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x0E25, 0x0E26, 0x0E27, 0x0E28, 0x0E29, 0x0E2A,
|
||||
// 90-9F
|
||||
0x0E2B, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, 0x0E30, 0x0E31,
|
||||
// A0-AF
|
||||
0x0E32, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, 0x0E38,
|
||||
// B0-BF
|
||||
0x0E39, 0x0E3A, 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45,
|
||||
0x0E46, 0x0E47, 0x00AC, 0x007C, 0x0E48, 0x0E49, 0x0E4A, 0x0E4B,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, 0x0E50, 0x0E51,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x00D3, 0x00D5,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F,
|
||||
};
|
||||
|
||||
public Cp838() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "838", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 880 (Cyrillic Russian EBCDIC).
|
||||
* CCSID / CPGID: 880, GCSGID: 960.
|
||||
*/
|
||||
public class Cp880 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "880";
|
||||
public static final String DESCRIPTION = "Cyrillic Russian EBCDIC";
|
||||
public static final int CPGID = 880;
|
||||
public static final int GCSGID = 960;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x00A0, 0x044F, 0x044E, 0x044D, 0x044C, 0x044B, 0x044A,
|
||||
0x0449, 0x0448, 0x005B, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x0447, 0x0446, 0x0445, 0x0444, 0x0443, 0x0442, 0x0441,
|
||||
0x0440, 0x043F, 0x005D, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x043E, 0x043D, 0x043C, 0x043B, 0x043A, 0x0439,
|
||||
0x0438, 0x0437, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x0436, 0x0435, 0x0434, 0x0433, 0x0432, 0x0431, 0x0430, 0x0451,
|
||||
0x045E, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x045F, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x0456, 0x0458, 0x0459, 0x045A, 0x045C, 0x045B,
|
||||
// 90-9F
|
||||
0x0402, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x0403, 0x0404, 0x0405, 0x0406, 0x0408, 0x0409,
|
||||
// A0-AF
|
||||
0x040A, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x040C, 0x040B, 0x040F, 0x040E, 0x0401, 0x00AE,
|
||||
// B0-BF
|
||||
0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
|
||||
0x00BD, 0x00BE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424,
|
||||
// D0-DF
|
||||
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A,
|
||||
// E0-EF
|
||||
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0410,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x009F,
|
||||
};
|
||||
|
||||
public Cp880() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "880", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 905 (Turkey - Turkish Latin-3 EBCDIC).
|
||||
* CCSID / CPGID: 905, GCSGID: 1151.
|
||||
*/
|
||||
public class Cp905 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "905";
|
||||
public static final String DESCRIPTION = "Turkey - Turkish Latin-3 EBCDIC";
|
||||
public static final int CPGID = 905;
|
||||
public static final int GCSGID = 1151;
|
||||
|
||||
public static final int[] MAPPING = {
|
||||
// 00-0F
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F,
|
||||
0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
|
||||
// 10-1F
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
|
||||
0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
|
||||
// 20-2F
|
||||
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B,
|
||||
0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
|
||||
// 30-3F
|
||||
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004,
|
||||
0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
|
||||
// 40-4F
|
||||
0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
|
||||
0x00E7, 0x00F1, 0x011E, 0x002E, 0x003C, 0x0028, 0x002B, 0x0021,
|
||||
// 50-5F
|
||||
0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00EC, 0x00DF, 0x0130, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E,
|
||||
// 60-6F
|
||||
0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5,
|
||||
0x00C7, 0x00D1, 0x015E, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
|
||||
// 70-7F
|
||||
0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
|
||||
// 80-8F
|
||||
0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
||||
0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
|
||||
// 90-9F
|
||||
0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070,
|
||||
0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
|
||||
// A0-AF
|
||||
0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
|
||||
0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
|
||||
// B0-BF
|
||||
0x00A2, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC,
|
||||
0x00BD, 0x00BE, 0x00AC, 0x007C, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
|
||||
// C0-CF
|
||||
0x011F, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
||||
0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5,
|
||||
// D0-DF
|
||||
0x0131, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
|
||||
0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF,
|
||||
// E0-EF
|
||||
0x015F, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
|
||||
0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
|
||||
// F0-FF
|
||||
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
||||
0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F,
|
||||
};
|
||||
|
||||
public Cp905() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, "905", MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* EBCDIC ↔ Unicode character translator conforming to IBM Host On-Demand (HoD v14).
|
||||
* Modular architecture delegating to pluggable CodePage implementations (SBCS and DBCS).
|
||||
* Supports custom per-instance character translation override tables and complete
|
||||
* IBM 3270 APL / Graphic Escape (GA23-0059) character mappings.
|
||||
* Default: Code Page 037 (US/Canada EBCDIC).
|
||||
*/
|
||||
public class EbcdicTranslator {
|
||||
@@ -15,6 +18,8 @@ public class EbcdicTranslator {
|
||||
public static final int[] CP037_TO_UNICODE = Cp037.MAPPING;
|
||||
|
||||
private CodePage activeCodePage;
|
||||
private final Map<Integer, Character> customEbcdicToUnicode = new ConcurrentHashMap<>();
|
||||
private final Map<Character, Integer> customUnicodeToEbcdic = new ConcurrentHashMap<>();
|
||||
|
||||
public EbcdicTranslator() {
|
||||
this("037");
|
||||
@@ -85,6 +90,107 @@ public class EbcdicTranslator {
|
||||
return isDBCSCodePage();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Custom Character Translation Overrides
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Set a bidirectional custom character translation override.
|
||||
* Maps an EBCDIC byte value to a Unicode character, and vice versa.
|
||||
*/
|
||||
public synchronized void setCustomOverride(int ebcdicByte, char unicodeChar) {
|
||||
int b = ebcdicByte & 0xFF;
|
||||
customEbcdicToUnicode.put(b, unicodeChar);
|
||||
customUnicodeToEbcdic.put(unicodeChar, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a one-way custom EBCDIC byte to Unicode character override.
|
||||
*/
|
||||
public synchronized void setCustomEbcdicToUnicodeOverride(int ebcdicByte, char unicodeChar) {
|
||||
customEbcdicToUnicode.put(ebcdicByte & 0xFF, unicodeChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a one-way custom Unicode character to EBCDIC byte override.
|
||||
*/
|
||||
public synchronized void setCustomUnicodeToEbcdicOverride(char unicodeChar, int ebcdicByte) {
|
||||
customUnicodeToEbcdic.put(unicodeChar, ebcdicByte & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom translation overrides in bulk.
|
||||
*/
|
||||
public synchronized void setCustomOverrides(Map<Integer, Character> ebcToUni, Map<Character, Integer> uniToEbc) {
|
||||
if (ebcToUni != null) {
|
||||
for (Map.Entry<Integer, Character> entry : ebcToUni.entrySet()) {
|
||||
if (entry.getKey() != null && entry.getValue() != null) {
|
||||
setCustomOverride(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uniToEbc != null) {
|
||||
for (Map.Entry<Character, Integer> entry : uniToEbc.entrySet()) {
|
||||
if (entry.getKey() != null && entry.getValue() != null) {
|
||||
setCustomUnicodeToEbcdicOverride(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove custom translation override for a specific EBCDIC byte.
|
||||
*/
|
||||
public synchronized void removeCustomOverride(int ebcdicByte) {
|
||||
Character removed = customEbcdicToUnicode.remove(ebcdicByte & 0xFF);
|
||||
if (removed != null) {
|
||||
customUnicodeToEbcdic.remove(removed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove custom translation override for a specific Unicode character.
|
||||
*/
|
||||
public synchronized void removeCustomUnicodeOverride(char unicodeChar) {
|
||||
Integer removed = customUnicodeToEbcdic.remove(unicodeChar);
|
||||
if (removed != null) {
|
||||
customEbcdicToUnicode.remove(removed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all registered custom translation overrides.
|
||||
*/
|
||||
public synchronized void clearCustomOverrides() {
|
||||
customEbcdicToUnicode.clear();
|
||||
customUnicodeToEbcdic.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any custom translation overrides are active.
|
||||
*/
|
||||
public boolean hasCustomOverrides() {
|
||||
return !customEbcdicToUnicode.isEmpty() || !customUnicodeToEbcdic.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an unmodifiable view of active EBCDIC-to-Unicode custom overrides.
|
||||
*/
|
||||
public Map<Integer, Character> getCustomEbcdicToUnicodeOverrides() {
|
||||
return Collections.unmodifiableMap(new HashMap<>(customEbcdicToUnicode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an unmodifiable view of active Unicode-to-EBCDIC custom overrides.
|
||||
*/
|
||||
public Map<Character, Integer> getCustomUnicodeToEbcdicOverrides() {
|
||||
return Collections.unmodifiableMap(new HashMap<>(customUnicodeToEbcdic));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Translation Operations
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Translate double-byte EBCDIC pair (b1, b2) to Unicode.
|
||||
*/
|
||||
@@ -100,10 +206,15 @@ public class EbcdicTranslator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate EBCDIC byte to Unicode character using active code page.
|
||||
* Translate EBCDIC byte to Unicode character using active code page and custom overrides.
|
||||
*/
|
||||
public char ebcdicToUnicode(int ebc) {
|
||||
return activeCodePage.ebcdicToUnicode(ebc);
|
||||
int b = ebc & 0xFF;
|
||||
Character custom = customEbcdicToUnicode.get(b);
|
||||
if (custom != null) {
|
||||
return custom;
|
||||
}
|
||||
return activeCodePage.ebcdicToUnicode(b);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,10 +232,14 @@ public class EbcdicTranslator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate Unicode character to EBCDIC byte using active code page.
|
||||
* Translate Unicode character to EBCDIC byte using active code page and custom overrides.
|
||||
* Returns -1 if the character cannot be mapped.
|
||||
*/
|
||||
public int unicodeToEbcdic(char unicode) {
|
||||
Integer custom = customUnicodeToEbcdic.get(unicode);
|
||||
if (custom != null) {
|
||||
return custom;
|
||||
}
|
||||
return activeCodePage.unicodeToEbcdic(unicode);
|
||||
}
|
||||
|
||||
@@ -132,20 +247,37 @@ public class EbcdicTranslator {
|
||||
* Translate Unicode character to EBCDIC, returning EBCDIC space (0x40) if unmappable.
|
||||
*/
|
||||
public byte unicodeToEbcdicSafe(char unicode) {
|
||||
return activeCodePage.unicodeToEbcdicSafe(unicode);
|
||||
int ebc = unicodeToEbcdic(unicode);
|
||||
return (byte) (ebc >= 0 ? ebc : 0x40);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a byte array from EBCDIC to a Unicode string using active code page.
|
||||
* Translate a byte array from EBCDIC to a Unicode string using active code page and overrides.
|
||||
*/
|
||||
public String ebcdicToString(byte[] ebcdic, int offset, int length) {
|
||||
if (ebcdic == null || length <= 0) return "";
|
||||
if (hasCustomOverrides() || !(activeCodePage instanceof AbstractDBCSCodePage)) {
|
||||
char[] chars = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
chars[i] = ebcdicToUnicode(ebcdic[offset + i]);
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
return activeCodePage.ebcdicToString(ebcdic, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a Unicode string to EBCDIC byte array using active code page.
|
||||
* Translate a Unicode string to EBCDIC byte array using active code page and overrides.
|
||||
*/
|
||||
public byte[] stringToEbcdic(String s) {
|
||||
if (s == null || s.isEmpty()) return new byte[0];
|
||||
if (hasCustomOverrides() || !(activeCodePage instanceof AbstractDBCSCodePage)) {
|
||||
byte[] bytes = new byte[s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
bytes[i] = unicodeToEbcdicSafe(s.charAt(i));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
return activeCodePage.stringToEbcdic(s);
|
||||
}
|
||||
|
||||
@@ -169,7 +301,7 @@ public class EbcdicTranslator {
|
||||
*/
|
||||
public char mapAPL(int ebcdicCodePoint) {
|
||||
switch (ebcdicCodePoint & 0xFF) {
|
||||
// Box-drawing line and corner characters (standard IBM 3270 GE / APL)
|
||||
// Standard Box-Drawing Lines, Corners, T-Junctions, and Crosses
|
||||
case 0xA2: return '\u2500'; // Horizontal Line 's' -> '─'
|
||||
case 0x85: return '\u2502'; // Vertical Line 'e' -> '│'
|
||||
case 0xC5: return '\u250C'; // Top Left 'E' -> '┌'
|
||||
@@ -182,7 +314,7 @@ public class EbcdicTranslator {
|
||||
case 0xD7: return '\u2534'; // T-Junction Bottom 'P' -> '┴'
|
||||
case 0xCB: return '\u253C'; // Cross -> '┼'
|
||||
|
||||
// Special math and APL symbols (matching x3270 cg.c / apl.c)
|
||||
// Mathematical Relations and Punctuation
|
||||
case 0x8C: return '\u2264'; // Less-than or equal '≤'
|
||||
case 0xAE: return '\u2265'; // Greater-than or equal '≥'
|
||||
case 0xBE: return '\u2260'; // Not equal '≠'
|
||||
@@ -194,11 +326,58 @@ public class EbcdicTranslator {
|
||||
case 0xB1: return '\u00B1'; // Plus-minus '±'
|
||||
case 0xB2: return '\u00B2'; // Superscript 2 '²'
|
||||
case 0xB3: return '\u00B3'; // Superscript 3 '³'
|
||||
case 0xAF: return '\u00AF'; // Overbar '¯'
|
||||
case 0xAF: return '\u00AF'; // Overbar / High Minus '¯'
|
||||
case 0xBA: return '\u03A9'; // Omega 'Ω'
|
||||
case 0xBF: return '\u00B5'; // Micro 'µ'
|
||||
case 0x5F: return '\u00AC'; // Not sign '¬'
|
||||
|
||||
// IBM 3270 APL Operational & Structural Glyphs
|
||||
case 0x80: return '\u22C4'; // Diamond '⋄'
|
||||
case 0x81: return '\u237A'; // APL Alpha '⍺'
|
||||
case 0x82: return '\u22A5'; // Up Tack / Decode '⊥'
|
||||
case 0x83: return '\u2229'; // Intersection '∩'
|
||||
case 0x84: return '\u230A'; // Floor '⌊'
|
||||
case 0x86: return '\u2286'; // Subset or equal '⊆'
|
||||
case 0x87: return '\u2207'; // Del / Grad '∇'
|
||||
case 0x88: return '\u2206'; // Delta '∆'
|
||||
case 0x89: return '\u2373'; // Iota '⍳'
|
||||
case 0x8A: return '\u2192'; // Right Arrow '→'
|
||||
case 0x8B: return '\u235E'; // Quote Quad '⍞'
|
||||
case 0x8E: return '\u00D7'; // Multiply '×'
|
||||
case 0x8F: return '\u00F7'; // Divide '÷'
|
||||
case 0x90: return '\u235F'; // Circle Star / Log '⍟'
|
||||
case 0x91: return '\u2339'; // Quad Divide / Domino '⌹'
|
||||
case 0x92: return '\u22A4'; // Down Tack / Encode '⊤'
|
||||
case 0x93: return '\u222A'; // Union '∪'
|
||||
case 0x94: return '\u2308'; // Ceiling '⌈'
|
||||
case 0x95: return '\u2374'; // Rho / Shape '⍴'
|
||||
case 0x96: return '\u2375'; // APL Omega '⍵'
|
||||
case 0x97: return '\u2260'; // Not equal '≠'
|
||||
case 0x98: return '\u2377'; // Epsilon Underbar '⍷'
|
||||
case 0x99: return '\u25CB'; // Circle '○'
|
||||
case 0x9A: return '\u2190'; // Left Arrow '←'
|
||||
case 0x9B: return '\u2359'; // Delta Underbar '⍙'
|
||||
case 0x9C: return '\u234B'; // Grade Up '⍋'
|
||||
case 0x9E: return '\u2352'; // Grade Down '⍒'
|
||||
case 0x9F: return '\u235D'; // Lamp / Comment '⍝'
|
||||
case 0xA1: return '\u00A8'; // Diaeresis '¨'
|
||||
case 0xA4: return '\u2336'; // I-Beam '⌶'
|
||||
case 0xA5: return '\u2355'; // Thorn / Format '⍕'
|
||||
case 0xA6: return '\u2282'; // Left Shoe / Enclose '⊂'
|
||||
case 0xA7: return '\u2283'; // Right Shoe / Disclose '⊃'
|
||||
case 0xA8: return '\u2191'; // Up Arrow / Take '↑'
|
||||
case 0xA9: return '\u2193'; // Down Arrow / Drop '↓'
|
||||
case 0xAA: return '\u2395'; // Quad '⎕'
|
||||
case 0xAB: return '\u234E'; // Execute / Hydra '⍎'
|
||||
case 0xAC: return '\u2349'; // Transpose / Circle Slope '⍉'
|
||||
case 0xB4: return '\u2296'; // Circle Bar / Reverse '⊖'
|
||||
case 0xB5: return '\u236A'; // Comma Bar / Table '⍪'
|
||||
case 0xB6: return '\u236B'; // Del Tilde '⍫'
|
||||
case 0xB7: return '\u236C'; // Zilde '⍬'
|
||||
case 0xB9: return '\u233F'; // Slash Bar '⌿'
|
||||
case 0xBB: return '\u2340'; // Backslash Bar '⍀'
|
||||
case 0xBC: return '\u2338'; // Quad Equal '⌸'
|
||||
|
||||
default: return ebcdicToUnicode(ebcdicCodePoint & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
/**
|
||||
* Concrete converter implementing mixed SBCS/DBCS byte-to-char conversion with transparent
|
||||
* Shift-Out (0x0E) and Shift-In (0x0F) state management.
|
||||
* Conforms to com.ibm.eNetwork.HOD.converters.ByteToCharDBCS_EBCDIC.
|
||||
*/
|
||||
public class ByteToCharDBCS_EBCDIC extends HODByteToCharConverter {
|
||||
|
||||
public ByteToCharDBCS_EBCDIC() {
|
||||
this(CodePageRegistry.getCodePage("930"));
|
||||
}
|
||||
|
||||
public ByteToCharDBCS_EBCDIC(CodePage codePage) {
|
||||
super(codePage != null ? codePage : CodePageRegistry.getCodePage("930"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convert(byte[] in, int inOff, int inEnd, char[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException {
|
||||
if (in == null || inEnd <= inOff) {
|
||||
return 0;
|
||||
}
|
||||
if (out == null) {
|
||||
throw new HODCharConversionException("Output buffer cannot be null");
|
||||
}
|
||||
|
||||
this.byteOff = inOff;
|
||||
this.charOff = outOff;
|
||||
|
||||
while (this.byteOff < inEnd || this.savedBytePresent) {
|
||||
int b;
|
||||
boolean isSaved = false;
|
||||
if (this.savedBytePresent) {
|
||||
b = this.savedByte & 0xFF;
|
||||
this.savedBytePresent = false;
|
||||
isSaved = true;
|
||||
} else {
|
||||
b = in[this.byteOff] & 0xFF;
|
||||
}
|
||||
|
||||
// Handle Shift-Out (0x0E) -> DBCS mode
|
||||
if (b == SO) {
|
||||
this.currentState = 1;
|
||||
if (this.preserveSOSI) {
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing SO at " + this.charOff);
|
||||
}
|
||||
out[this.charOff++] = (char) SO;
|
||||
}
|
||||
if (!isSaved) this.byteOff++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle Shift-In (0x0F) -> SBCS mode
|
||||
if (b == SI) {
|
||||
this.currentState = 0;
|
||||
if (this.preserveSOSI) {
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing SI at " + this.charOff);
|
||||
}
|
||||
out[this.charOff++] = (char) SI;
|
||||
}
|
||||
if (!isSaved) this.byteOff++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SBCS mode conversion
|
||||
if (this.currentState == 0) {
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow at position " + this.charOff);
|
||||
}
|
||||
char c = this.codePage.ebcdicToUnicode(b);
|
||||
if (c == '\uFFFD') {
|
||||
if (this.subMode) {
|
||||
c = this.subChars[0];
|
||||
} else {
|
||||
this.badInputLength = 1;
|
||||
throw new HODCharConversionException("Unmappable byte 0x" + Integer.toHexString(b) + " at index " + this.byteOff);
|
||||
}
|
||||
}
|
||||
out[this.charOff++] = c;
|
||||
if (!isSaved) this.byteOff++;
|
||||
} else {
|
||||
// DBCS mode conversion (requires 2 bytes)
|
||||
int b2;
|
||||
if (isSaved) {
|
||||
if (this.byteOff >= inEnd) {
|
||||
// Incomplete DBCS pair at end of buffer
|
||||
this.savedByte = (byte) b;
|
||||
this.savedBytePresent = true;
|
||||
break;
|
||||
}
|
||||
b2 = in[this.byteOff++] & 0xFF;
|
||||
} else {
|
||||
if (this.byteOff + 1 >= inEnd) {
|
||||
// Trailing single byte inside DBCS shift
|
||||
this.savedByte = (byte) b;
|
||||
this.savedBytePresent = true;
|
||||
this.byteOff++;
|
||||
break;
|
||||
}
|
||||
b2 = in[this.byteOff + 1] & 0xFF;
|
||||
this.byteOff += 2;
|
||||
}
|
||||
|
||||
// Check for premature Shift-In
|
||||
if (b2 == SI) {
|
||||
this.currentState = 0;
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow at position " + this.charOff);
|
||||
}
|
||||
out[this.charOff++] = this.codePage.ebcdicToUnicode(b);
|
||||
if (this.preserveSOSI) {
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow at position " + this.charOff);
|
||||
}
|
||||
out[this.charOff++] = (char) SI;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
char c = this.codePage.dbcsToUnicode(b, b2);
|
||||
if (c == '?' || c == '\uFFFD') {
|
||||
if (this.subMode) {
|
||||
c = this.subChars[0];
|
||||
} else {
|
||||
this.badInputLength = 2;
|
||||
throw new HODCharConversionException("Unmappable DBCS pair 0x" + Integer.toHexString(b) + ", 0x" + Integer.toHexString(b2));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow at position " + this.charOff);
|
||||
}
|
||||
out[this.charOff++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
return this.charOff - outOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flush(char[] out, int outOff, int outEnd) throws HODCharConversionException {
|
||||
int count = 0;
|
||||
if (this.savedBytePresent) {
|
||||
if (!this.subMode) {
|
||||
reset();
|
||||
this.badInputLength = 1;
|
||||
throw new HODCharConversionException("Unclosed trailing DBCS byte at end of input");
|
||||
}
|
||||
if (outOff < outEnd) {
|
||||
out[outOff] = this.subChars[0];
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.byteOff = 0;
|
||||
this.charOff = 0;
|
||||
this.currentState = 0;
|
||||
this.savedBytePresent = false;
|
||||
this.savedByte = 0;
|
||||
this.badInputLength = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return this.codePage != null ? "Cp" + this.codePage.getCodePageId() : "DBCS_EBCDIC";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
/**
|
||||
* Concrete converter implementing single-byte character set (SBCS) byte-to-char conversion.
|
||||
* Conforms to com.ibm.eNetwork.HOD.converters.ByteToCharSingleByte.
|
||||
*/
|
||||
public class ByteToCharSingleByte extends HODByteToCharConverter {
|
||||
|
||||
public ByteToCharSingleByte() {
|
||||
this(CodePageRegistry.getDefault());
|
||||
}
|
||||
|
||||
public ByteToCharSingleByte(CodePage codePage) {
|
||||
super(codePage != null ? codePage : CodePageRegistry.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convert(byte[] in, int inOff, int inEnd, char[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException {
|
||||
if (in == null || inEnd <= inOff) {
|
||||
return 0;
|
||||
}
|
||||
if (out == null) {
|
||||
throw new HODCharConversionException("Output buffer cannot be null");
|
||||
}
|
||||
|
||||
this.byteOff = inOff;
|
||||
this.charOff = outOff;
|
||||
|
||||
while (this.byteOff < inEnd) {
|
||||
if (this.charOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output char buffer overflow at position " + this.charOff);
|
||||
}
|
||||
|
||||
int b = in[this.byteOff] & 0xFF;
|
||||
char c = this.codePage.ebcdicToUnicode(b);
|
||||
|
||||
if (c == '\uFFFD') {
|
||||
if (this.subMode) {
|
||||
c = this.subChars[0];
|
||||
} else {
|
||||
this.badInputLength = 1;
|
||||
throw new HODCharConversionException("Unmappable byte 0x" + Integer.toHexString(b) + " at input index " + this.byteOff);
|
||||
}
|
||||
}
|
||||
|
||||
out[this.charOff++] = c;
|
||||
this.byteOff++;
|
||||
}
|
||||
|
||||
return this.charOff - outOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flush(char[] out, int outOff, int outEnd) {
|
||||
reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.byteOff = 0;
|
||||
this.charOff = 0;
|
||||
this.badInputLength = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return this.codePage != null ? "Cp" + this.codePage.getCodePageId() : "SingleByte";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
/**
|
||||
* Concrete converter implementing mixed SBCS/DBCS char-to-byte conversion with transparent
|
||||
* Shift-Out (0x0E) and Shift-In (0x0F) state generation.
|
||||
* Conforms to com.ibm.eNetwork.HOD.converters.CharToByteDBCS_EBCDIC.
|
||||
*/
|
||||
public class CharToByteDBCS_EBCDIC extends HODCharToByteConverter {
|
||||
|
||||
public CharToByteDBCS_EBCDIC() {
|
||||
this(CodePageRegistry.getCodePage("930"));
|
||||
}
|
||||
|
||||
public CharToByteDBCS_EBCDIC(CodePage codePage) {
|
||||
super(codePage != null ? codePage : CodePageRegistry.getCodePage("930"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convert(char[] in, int inOff, int inEnd, byte[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException {
|
||||
if (in == null || inEnd <= inOff) {
|
||||
return 0;
|
||||
}
|
||||
if (out == null) {
|
||||
throw new HODCharConversionException("Output buffer cannot be null");
|
||||
}
|
||||
|
||||
this.charOff = inOff;
|
||||
this.byteOff = outOff;
|
||||
|
||||
while (this.charOff < inEnd) {
|
||||
char c = in[this.charOff];
|
||||
|
||||
// Explicit Shift-Out control character handling
|
||||
if (c == (char) SO) {
|
||||
if (this.currentState == 0) {
|
||||
if (this.byteOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing SO at " + this.byteOff);
|
||||
}
|
||||
out[this.byteOff++] = SO;
|
||||
this.currentState = 1;
|
||||
}
|
||||
this.charOff++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Explicit Shift-In control character handling
|
||||
if (c == (char) SI) {
|
||||
if (this.currentState == 1) {
|
||||
if (this.byteOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing SI at " + this.byteOff);
|
||||
}
|
||||
out[this.byteOff++] = SI;
|
||||
this.currentState = 0;
|
||||
}
|
||||
this.charOff++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int dbcs = this.codePage.unicodeToDbcs(c);
|
||||
|
||||
if (dbcs >= 0) {
|
||||
// Character is DBCS: ensure in DBCS mode
|
||||
int needed = (this.currentState == 0) ? 3 : 2;
|
||||
if (this.byteOff + needed > outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing DBCS character at " + this.byteOff);
|
||||
}
|
||||
|
||||
if (this.currentState == 0) {
|
||||
out[this.byteOff++] = SO;
|
||||
this.currentState = 1;
|
||||
}
|
||||
|
||||
out[this.byteOff++] = (byte) ((dbcs >> 8) & 0xFF);
|
||||
out[this.byteOff++] = (byte) (dbcs & 0xFF);
|
||||
} else {
|
||||
// Character is SBCS: ensure in SBCS mode
|
||||
int needed = (this.currentState == 1) ? 2 : 1;
|
||||
if (this.byteOff + needed > outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow writing SBCS character at " + this.byteOff);
|
||||
}
|
||||
|
||||
if (this.currentState == 1) {
|
||||
out[this.byteOff++] = SI;
|
||||
this.currentState = 0;
|
||||
}
|
||||
|
||||
int ebc = this.codePage.unicodeToEbcdic(c);
|
||||
if (ebc < 0) {
|
||||
if (this.subMode) {
|
||||
out[this.byteOff++] = this.subBytes[0];
|
||||
} else {
|
||||
this.badInputLength = 1;
|
||||
throw new HODCharConversionException("Unmappable character '\\u" + Integer.toHexString(c) + "' at input index " + this.charOff);
|
||||
}
|
||||
} else {
|
||||
out[this.byteOff++] = (byte) (ebc & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
this.charOff++;
|
||||
}
|
||||
|
||||
return this.byteOff - outOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flush(byte[] out, int outOff, int outEnd) throws HODCharConversionException {
|
||||
int flushed = 0;
|
||||
if (this.currentState == 1) {
|
||||
if (outOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output buffer overflow during flush at " + outOff);
|
||||
}
|
||||
out[outOff] = SI;
|
||||
flushed = 1;
|
||||
this.currentState = 0;
|
||||
}
|
||||
reset();
|
||||
return flushed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.charOff = 0;
|
||||
this.byteOff = 0;
|
||||
this.currentState = 0;
|
||||
this.badInputLength = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return this.codePage != null ? "Cp" + this.codePage.getCodePageId() : "DBCS_EBCDIC";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
/**
|
||||
* Concrete converter implementing single-byte character set (SBCS) char-to-byte conversion.
|
||||
* Conforms to com.ibm.eNetwork.HOD.converters.CharToByteSingleByte.
|
||||
*/
|
||||
public class CharToByteSingleByte extends HODCharToByteConverter {
|
||||
|
||||
public CharToByteSingleByte() {
|
||||
this(CodePageRegistry.getDefault());
|
||||
}
|
||||
|
||||
public CharToByteSingleByte(CodePage codePage) {
|
||||
super(codePage != null ? codePage : CodePageRegistry.getDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convert(char[] in, int inOff, int inEnd, byte[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException {
|
||||
if (in == null || inEnd <= inOff) {
|
||||
return 0;
|
||||
}
|
||||
if (out == null) {
|
||||
throw new HODCharConversionException("Output buffer cannot be null");
|
||||
}
|
||||
|
||||
this.charOff = inOff;
|
||||
this.byteOff = outOff;
|
||||
|
||||
while (this.charOff < inEnd) {
|
||||
if (this.byteOff >= outEnd) {
|
||||
throw new HODCharConversionException("Output byte buffer overflow at position " + this.byteOff);
|
||||
}
|
||||
|
||||
char c = in[this.charOff];
|
||||
int ebc = this.codePage.unicodeToEbcdic(c);
|
||||
|
||||
if (ebc < 0) {
|
||||
if (this.subMode) {
|
||||
out[this.byteOff++] = this.subBytes[0];
|
||||
} else {
|
||||
this.badInputLength = 1;
|
||||
throw new HODCharConversionException("Unmappable character '\\u" + Integer.toHexString(c) + "' at input index " + this.charOff);
|
||||
}
|
||||
} else {
|
||||
out[this.byteOff++] = (byte) (ebc & 0xFF);
|
||||
}
|
||||
|
||||
this.charOff++;
|
||||
}
|
||||
|
||||
return this.byteOff - outOff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flush(byte[] out, int outOff, int outEnd) {
|
||||
reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
this.charOff = 0;
|
||||
this.byteOff = 0;
|
||||
this.badInputLength = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding() {
|
||||
return this.codePage != null ? "Cp" + this.codePage.getCodePageId() : "SingleByte";
|
||||
}
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* High-performance adapter and bridge converting byte streams (EBCDIC, ASCII, ISO, UTF)
|
||||
* to Unicode characters conforming to IBM Host On-Demand (HoD) converter specifications.
|
||||
* <p>
|
||||
* Supports dynamic factory resolution for all 275 HoD converter class names and transparent
|
||||
* Shift-In (0x0F) / Shift-Out (0x0E) DBCS transitions.
|
||||
*/
|
||||
public abstract class HODByteToCharConverter {
|
||||
|
||||
public static final int SO = 0x0E;
|
||||
public static final int SI = 0x0F;
|
||||
|
||||
protected int byteOff = 0;
|
||||
protected int charOff = 0;
|
||||
protected int badInputLength = 0;
|
||||
protected boolean subMode = true;
|
||||
protected char[] subChars = new char[]{'\uFFFD'};
|
||||
protected CodePage codePage;
|
||||
|
||||
// DBCS State
|
||||
protected int currentState = 0; // 0 = SBCS, 1 = DBCS
|
||||
protected boolean savedBytePresent = false;
|
||||
protected byte savedByte = 0;
|
||||
protected boolean preserveSOSI = false;
|
||||
|
||||
public HODByteToCharConverter() {
|
||||
}
|
||||
|
||||
public HODByteToCharConverter(CodePage codePage) {
|
||||
this.codePage = Objects.requireNonNull(codePage, "codePage cannot be null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up and instantiate a ByteToChar converter matching the given encoding,
|
||||
* codepage ID, alias, or HoD converter class name (e.g. "Cp037", "037", "ByteToCharCp1047", "ConverterFT1047").
|
||||
*
|
||||
* @param encoding encoding identifier or class name
|
||||
* @return initialized HODByteToCharConverter instance
|
||||
* @throws HODUnsupportedCodepageException if the codepage cannot be resolved
|
||||
*/
|
||||
public static HODByteToCharConverter getHODConverter(String encoding) throws HODUnsupportedCodepageException {
|
||||
if (encoding == null || encoding.trim().isEmpty()) {
|
||||
throw new HODUnsupportedCodepageException("Encoding name cannot be null or empty");
|
||||
}
|
||||
|
||||
CodePage cp = CodePageRegistry.resolveCodePage(encoding);
|
||||
if (cp == null) {
|
||||
throw new HODUnsupportedCodepageException("Unsupported codepage / converter: " + encoding);
|
||||
}
|
||||
|
||||
if (cp.isDBCS()) {
|
||||
return new ByteToCharDBCS_EBCDIC(cp);
|
||||
} else {
|
||||
return new ByteToCharSingleByte(cp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard converter lookup alias conforming to Java/HoD converter factory patterns.
|
||||
*/
|
||||
public static HODByteToCharConverter getConverter(String encoding) throws HODUnsupportedCodepageException {
|
||||
return getHODConverter(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of bytes into an array of characters.
|
||||
*
|
||||
* @param in source byte buffer
|
||||
* @param inOff start offset in input buffer
|
||||
* @param inEnd end offset in input buffer (exclusive)
|
||||
* @param out destination char buffer
|
||||
* @param outOff start offset in output buffer
|
||||
* @param outEnd end offset in output buffer (exclusive)
|
||||
* @return number of characters converted and written into out
|
||||
* @throws HODCharConversionException if an unmappable byte is encountered with substitution disabled,
|
||||
* or if the output buffer overflows
|
||||
*/
|
||||
public abstract int convert(byte[] in, int inOff, int inEnd, char[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException;
|
||||
|
||||
/**
|
||||
* Overload supporting an extra boolean flag matching HoD CFR decompiled signature.
|
||||
*/
|
||||
public int convert(byte[] in, int inOff, int inEnd, char[] out, int outOff, int outEnd, boolean bl)
|
||||
throws HODCharConversionException {
|
||||
return convert(in, inOff, inEnd, out, outOff, outEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any buffered / trailing state into the output char buffer.
|
||||
*
|
||||
* @param out destination char buffer
|
||||
* @param outOff start offset
|
||||
* @param outEnd end offset
|
||||
* @return number of characters flushed
|
||||
* @throws HODCharConversionException if flush fails or trailing incomplete sequence cannot be converted
|
||||
*/
|
||||
public abstract int flush(char[] out, int outOff, int outEnd) throws HODCharConversionException;
|
||||
|
||||
/**
|
||||
* Reset converter state and offsets to defaults.
|
||||
*/
|
||||
public abstract void reset();
|
||||
|
||||
/**
|
||||
* Get the canonical character encoding name (e.g. "Cp037", "Cp930").
|
||||
*/
|
||||
public abstract String getCharacterEncoding();
|
||||
|
||||
/**
|
||||
* Convert an entire byte array to a char array matching IBM HoD's hodConvertAll API.
|
||||
*/
|
||||
public char[] hodConvertAll(byte[] in) throws HODCharConversionException {
|
||||
if (in == null) return new char[0];
|
||||
reset();
|
||||
char[] buf = new char[Math.max(16, in.length * 2 + 16)];
|
||||
int converted = convert(in, 0, in.length, buf, 0, buf.length);
|
||||
int flushed = flush(buf, converted, buf.length);
|
||||
int total = converted + flushed;
|
||||
char[] result = new char[total];
|
||||
System.arraycopy(buf, 0, result, 0, total);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience alias for hodConvertAll.
|
||||
*/
|
||||
public char[] convertAll(byte[] in) throws HODCharConversionException {
|
||||
return hodConvertAll(in);
|
||||
}
|
||||
|
||||
public void setSubstitutionMode(boolean mode) {
|
||||
this.subMode = mode;
|
||||
}
|
||||
|
||||
public boolean getSubstitutionMode() {
|
||||
return this.subMode;
|
||||
}
|
||||
|
||||
public void setSubstitutionChars(char[] subChars) {
|
||||
if (subChars != null && subChars.length > 0) {
|
||||
this.subChars = subChars;
|
||||
}
|
||||
}
|
||||
|
||||
public char[] getSubstitutionChars() {
|
||||
return this.subChars;
|
||||
}
|
||||
|
||||
public int getBadInputLength() {
|
||||
return this.badInputLength;
|
||||
}
|
||||
|
||||
public int nextByteIndex() {
|
||||
return this.byteOff;
|
||||
}
|
||||
|
||||
public int nextCharIndex() {
|
||||
return this.charOff;
|
||||
}
|
||||
|
||||
public CodePage getCodePage() {
|
||||
return this.codePage;
|
||||
}
|
||||
|
||||
public void setPreserveSOSI(boolean preserve) {
|
||||
this.preserveSOSI = preserve;
|
||||
}
|
||||
|
||||
public boolean isPreserveSOSI() {
|
||||
return this.preserveSOSI;
|
||||
}
|
||||
|
||||
public int getCurrentState() {
|
||||
return this.currentState;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import java.io.CharConversionException;
|
||||
|
||||
/**
|
||||
* Exception thrown when character conversion fails during Host On-Demand converter processing.
|
||||
* Conforms to com.ibm.eNetwork.HOD.common.HODCharConversionException.
|
||||
*/
|
||||
public class HODCharConversionException extends CharConversionException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public HODCharConversionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODCharConversionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.CodePage;
|
||||
import haus.nightmare.lib3270j.charset.CodePageRegistry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* High-performance adapter and bridge converting Unicode characters to byte streams
|
||||
* (EBCDIC, ASCII, ISO, UTF) conforming to IBM Host On-Demand (HoD) converter specifications.
|
||||
* <p>
|
||||
* Supports dynamic factory resolution for all 275 HoD converter class names and transparent
|
||||
* Shift-In (0x0F) / Shift-Out (0x0E) DBCS transitions.
|
||||
*/
|
||||
public abstract class HODCharToByteConverter {
|
||||
|
||||
public static final byte SO = 0x0E;
|
||||
public static final byte SI = 0x0F;
|
||||
|
||||
protected int byteOff = 0;
|
||||
protected int charOff = 0;
|
||||
protected int badInputLength = 0;
|
||||
protected boolean subMode = true;
|
||||
protected byte[] subBytes = new byte[]{(byte) 0x6F}; // 0x6F '?' in EBCDIC (or safe fallback)
|
||||
protected CodePage codePage;
|
||||
|
||||
// DBCS State
|
||||
protected int currentState = 0; // 0 = SBCS, 1 = DBCS
|
||||
|
||||
public HODCharToByteConverter() {
|
||||
}
|
||||
|
||||
public HODCharToByteConverter(CodePage codePage) {
|
||||
this.codePage = Objects.requireNonNull(codePage, "codePage cannot be null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up and instantiate a CharToByte converter matching the given encoding,
|
||||
* codepage ID, alias, or HoD converter class name (e.g. "Cp037", "037", "CharToByteCp1047", "ConverterFT1047").
|
||||
*
|
||||
* @param encoding encoding identifier or class name
|
||||
* @return initialized HODCharToByteConverter instance
|
||||
* @throws HODUnsupportedCodepageException if the codepage cannot be resolved
|
||||
*/
|
||||
public static HODCharToByteConverter getHODConverter(String encoding) throws HODUnsupportedCodepageException {
|
||||
if (encoding == null || encoding.trim().isEmpty()) {
|
||||
throw new HODUnsupportedCodepageException("Encoding name cannot be null or empty");
|
||||
}
|
||||
|
||||
CodePage cp = CodePageRegistry.resolveCodePage(encoding);
|
||||
if (cp == null) {
|
||||
throw new HODUnsupportedCodepageException("Unsupported codepage / converter: " + encoding);
|
||||
}
|
||||
|
||||
if (cp.isDBCS()) {
|
||||
return new CharToByteDBCS_EBCDIC(cp);
|
||||
} else {
|
||||
return new CharToByteSingleByte(cp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard converter lookup alias conforming to Java/HoD converter factory patterns.
|
||||
*/
|
||||
public static HODCharToByteConverter getConverter(String encoding) throws HODUnsupportedCodepageException {
|
||||
return getHODConverter(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of characters into an array of bytes.
|
||||
*
|
||||
* @param in source char buffer
|
||||
* @param inOff start offset in input buffer
|
||||
* @param inEnd end offset in input buffer (exclusive)
|
||||
* @param out destination byte buffer
|
||||
* @param outOff start offset in output buffer
|
||||
* @param outEnd end offset in output buffer (exclusive)
|
||||
* @return number of bytes converted and written into out
|
||||
* @throws HODCharConversionException if an unmappable char is encountered with substitution disabled,
|
||||
* or if the output buffer overflows
|
||||
*/
|
||||
public abstract int convert(char[] in, int inOff, int inEnd, byte[] out, int outOff, int outEnd)
|
||||
throws HODCharConversionException;
|
||||
|
||||
/**
|
||||
* Flush any buffered / trailing shift state into the output byte buffer.
|
||||
*
|
||||
* @param out destination byte buffer
|
||||
* @param outOff start offset
|
||||
* @param outEnd end offset
|
||||
* @return number of bytes flushed
|
||||
* @throws HODCharConversionException if output buffer overflows
|
||||
*/
|
||||
public abstract int flush(byte[] out, int outOff, int outEnd) throws HODCharConversionException;
|
||||
|
||||
/**
|
||||
* Reset converter state and offsets to defaults.
|
||||
*/
|
||||
public abstract void reset();
|
||||
|
||||
/**
|
||||
* Get the canonical character encoding name (e.g. "Cp037", "Cp930").
|
||||
*/
|
||||
public abstract String getCharacterEncoding();
|
||||
|
||||
/**
|
||||
* Convert an entire char array to a byte array matching IBM HoD's hodConvertAll API.
|
||||
*/
|
||||
public byte[] hodConvertAll(char[] in) throws HODCharConversionException {
|
||||
if (in == null) return new byte[0];
|
||||
reset();
|
||||
byte[] buf = new byte[Math.max(16, in.length * 3 + 16)];
|
||||
int converted = convert(in, 0, in.length, buf, 0, buf.length);
|
||||
int flushed = flush(buf, converted, buf.length);
|
||||
int total = converted + flushed;
|
||||
byte[] result = new byte[total];
|
||||
System.arraycopy(buf, 0, result, 0, total);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience alias for hodConvertAll.
|
||||
*/
|
||||
public byte[] convertAll(char[] in) throws HODCharConversionException {
|
||||
return hodConvertAll(in);
|
||||
}
|
||||
|
||||
public void setSubstitutionMode(boolean mode) {
|
||||
this.subMode = mode;
|
||||
}
|
||||
|
||||
public boolean getSubstitutionMode() {
|
||||
return this.subMode;
|
||||
}
|
||||
|
||||
public void setSubstitutionBytes(byte[] subBytes) {
|
||||
if (subBytes != null && subBytes.length > 0) {
|
||||
this.subBytes = subBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getSubstitutionBytes() {
|
||||
return this.subBytes;
|
||||
}
|
||||
|
||||
public int getBadInputLength() {
|
||||
return this.badInputLength;
|
||||
}
|
||||
|
||||
public int nextByteIndex() {
|
||||
return this.byteOff;
|
||||
}
|
||||
|
||||
public int nextCharIndex() {
|
||||
return this.charOff;
|
||||
}
|
||||
|
||||
public int getMaxBytesPerChar() {
|
||||
return (codePage != null && codePage.isDBCS()) ? 3 : 1; // At most 3 bytes (SO + 2-byte DBCS)
|
||||
}
|
||||
|
||||
public CodePage getCodePage() {
|
||||
return this.codePage;
|
||||
}
|
||||
|
||||
public int getCurrentState() {
|
||||
return this.currentState;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package haus.nightmare.lib3270j.converters;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a requested character encoding or codepage identifier cannot be resolved.
|
||||
* Conforms to com.ibm.eNetwork.HOD.common.HODUnsupportedCodepageException.
|
||||
*/
|
||||
public class HODUnsupportedCodepageException extends UnsupportedEncodingException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public HODUnsupportedCodepageException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODUnsupportedCodepageException(String encoding) {
|
||||
super(encoding);
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,14 @@ public class DataStreamProcessor {
|
||||
this.graphicsPlane.setProgramSymbolManager(programSymbolManager);
|
||||
}
|
||||
|
||||
public ScreenBuffer getScreen() {
|
||||
return screen;
|
||||
}
|
||||
|
||||
public ScreenBuffer getScreenBuffer() {
|
||||
return screen;
|
||||
}
|
||||
|
||||
public QueryReplyBuilder getQueryReplyBuilder() {
|
||||
return qrBuilder;
|
||||
}
|
||||
@@ -81,6 +89,13 @@ public class DataStreamProcessor {
|
||||
|
||||
public void setOutputSender(OutputSender sender) {
|
||||
this.outputSender = sender;
|
||||
if (inputProcessor != null) {
|
||||
inputProcessor.setOutputSender(sender);
|
||||
}
|
||||
}
|
||||
|
||||
public OutputSender getOutputSender() {
|
||||
return outputSender;
|
||||
}
|
||||
|
||||
public void setFTDft(haus.nightmare.lib3270j.ft.FTDft ftDft) {
|
||||
@@ -99,6 +114,9 @@ public class DataStreamProcessor {
|
||||
|
||||
public void setInputProcessor(haus.nightmare.lib3270j.input.InputProcessor inputProcessor) {
|
||||
this.inputProcessor = inputProcessor;
|
||||
if (inputProcessor != null && outputSender != null) {
|
||||
inputProcessor.setOutputSender(outputSender);
|
||||
}
|
||||
}
|
||||
|
||||
public haus.nightmare.lib3270j.input.InputProcessor getInputProcessor() {
|
||||
@@ -109,6 +127,10 @@ public class DataStreamProcessor {
|
||||
screenListeners.add(l);
|
||||
}
|
||||
|
||||
public void removeScreenUpdateListener(ScreenUpdateListener l) {
|
||||
screenListeners.remove(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a 3270 data stream record.
|
||||
*
|
||||
@@ -1512,4 +1534,233 @@ public class DataStreamProcessor {
|
||||
public void processNullStructuredField() {
|
||||
log.fine("Processed null structured field");
|
||||
}
|
||||
|
||||
// ========== Phase 3: HoD DS3270 Order & Data Stream Functions ==========
|
||||
|
||||
/** Process Write Control Character (WCC). */
|
||||
public void processWCC(int wcc) {
|
||||
boolean alarm = wccSoundAlarm(wcc);
|
||||
boolean kbdRestore = wccKeyboardRestore(wcc);
|
||||
boolean resetMdt = wccResetMDT(wcc);
|
||||
|
||||
log.fine("processWCC: " + String.format("0x%02x", wcc) +
|
||||
" reset=" + wccReset(wcc) + " alarm=" + alarm + " kbdRestore=" + kbdRestore + " resetMdt=" + resetMdt);
|
||||
|
||||
if (kbdRestore && inputProcessor != null) {
|
||||
inputProcessor.setKeyboardLocked(false);
|
||||
}
|
||||
if (resetMdt) {
|
||||
resetAllMDT();
|
||||
}
|
||||
if (wccReset(wcc)) {
|
||||
log.fine("WCC reset: clearing default attributes");
|
||||
}
|
||||
}
|
||||
|
||||
public void processWCC(short wcc) {
|
||||
processWCC(wcc & 0xFFFF);
|
||||
}
|
||||
|
||||
/** Process Set Buffer Address (SBA) order. */
|
||||
public void processSBA(int baddr) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size > 0) {
|
||||
screen.setBufferAddress(baddr % size);
|
||||
}
|
||||
}
|
||||
|
||||
public void processSBA(int b1, int b2) {
|
||||
processSBA(decodeAddress(b1, b2));
|
||||
}
|
||||
|
||||
public void processSBA() {
|
||||
// No-op or maintains current buffer address
|
||||
}
|
||||
|
||||
/** Process Start Field (SF) order. */
|
||||
public void processSF(byte fa) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
int baddr = screen.getBufferAddress();
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.clear();
|
||||
ea.fa = (byte) (fa & FA_MASK);
|
||||
ea.ec = 0;
|
||||
ea.ucs4 = ' ';
|
||||
screen.setFormatted(true);
|
||||
screen.setBufferAddress((baddr + 1) % size);
|
||||
}
|
||||
|
||||
public void processSF() {
|
||||
processSF((byte) FA_PRINTABLE);
|
||||
}
|
||||
|
||||
/** Process Start Field Extended (SFE) order. */
|
||||
public void processSFE(byte[] pairs) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
int baddr = screen.getBufferAddress();
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.clear();
|
||||
ea.ec = 0;
|
||||
ea.ucs4 = ' ';
|
||||
if (pairs != null) {
|
||||
for (int i = 0; i + 1 < pairs.length; i += 2) {
|
||||
int attrType = pairs[i] & 0xFF;
|
||||
int attrValue = pairs[i + 1] & 0xFF;
|
||||
applyExtendedAttribute(ea, attrType, attrValue);
|
||||
}
|
||||
}
|
||||
if (ea.fa == 0) {
|
||||
ea.fa = (byte) FA_PRINTABLE;
|
||||
}
|
||||
screen.setFormatted(true);
|
||||
screen.setBufferAddress((baddr + 1) % size);
|
||||
}
|
||||
|
||||
public void processSFE() {
|
||||
processSFE(new byte[0]);
|
||||
}
|
||||
|
||||
/** Process Set Attribute (SA) order. */
|
||||
public void processSA(int attrType, int attrValue) {
|
||||
int baddr = screen.getBufferAddress();
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
applyExtendedAttribute(ea, attrType, attrValue);
|
||||
}
|
||||
|
||||
public void processSA() {
|
||||
// Default attributes
|
||||
}
|
||||
|
||||
/** Process Modify Field (MF) order. */
|
||||
public void processMF(byte[] pairs) {
|
||||
int baddr = screen.getBufferAddress();
|
||||
int faAddr = screen.findFieldAttribute(baddr);
|
||||
if (faAddr >= 0 && pairs != null) {
|
||||
ExtendedAttribute ea = screen.getCell(faAddr);
|
||||
for (int i = 0; i + 1 < pairs.length; i += 2) {
|
||||
int attrType = pairs[i] & 0xFF;
|
||||
int attrValue = pairs[i + 1] & 0xFF;
|
||||
applyExtendedAttribute(ea, attrType, attrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processMF() {
|
||||
processMF(new byte[0]);
|
||||
}
|
||||
|
||||
/** Process Insert Cursor (IC) order. */
|
||||
public void processIC() {
|
||||
screen.setCursorAddress(screen.getBufferAddress());
|
||||
}
|
||||
|
||||
/** Process Program Tab (PT) order. */
|
||||
public void processPT() {
|
||||
int baddr = screen.findNextUnprotected(screen.getBufferAddress());
|
||||
screen.setBufferAddress(baddr);
|
||||
}
|
||||
|
||||
/** Process Repeat to Address (RA) order. */
|
||||
public void processRA(int toAddr, int fillChar) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
toAddr = ((toAddr % size) + size) % size;
|
||||
int baddr = screen.getBufferAddress();
|
||||
char ucs4 = (translator != null) ? translator.ebcdicToUnicode(fillChar & 0xFF) : (char) fillChar;
|
||||
do {
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0;
|
||||
ea.ec = (byte) fillChar;
|
||||
ea.ucs4 = ucs4;
|
||||
baddr = (baddr + 1) % size;
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
}
|
||||
|
||||
public void processRA() {
|
||||
processRA(0, 0);
|
||||
}
|
||||
|
||||
/** Process Erase Unprotected to Address (EUA) order. */
|
||||
public void processEUA(int toAddr) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
toAddr = ((toAddr % size) + size) % size;
|
||||
int baddr = screen.getBufferAddress();
|
||||
do {
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
if (!ea.isFieldAttribute()) {
|
||||
int faAddr = screen.findFieldAttribute(baddr);
|
||||
byte faVal = faAddr >= 0 ? screen.getCell(faAddr).fa : 0;
|
||||
if (!faIsProtected(faVal & 0xFF)) {
|
||||
ea.ec = 0;
|
||||
ea.ucs4 = 0;
|
||||
ea.fg = 0;
|
||||
ea.bg = 0;
|
||||
ea.gr = 0;
|
||||
ea.cs = 0;
|
||||
}
|
||||
}
|
||||
baddr = (baddr + 1) % size;
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
}
|
||||
|
||||
public void processEUA() {
|
||||
processEUA(0);
|
||||
}
|
||||
|
||||
/** Process Graphic Escape (GE) order. */
|
||||
public void processGE(int geChar) {
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
int baddr = screen.getBufferAddress();
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0;
|
||||
ea.ec = (byte) geChar;
|
||||
ea.cs = CS_GE;
|
||||
ea.ucs4 = (translator != null) ? translator.mapAPL(geChar) : (char) geChar;
|
||||
screen.setBufferAddress((baddr + 1) % size);
|
||||
}
|
||||
|
||||
public void processGE() {
|
||||
processGE(0);
|
||||
}
|
||||
|
||||
/** Process Write Structured Field (WSF) from short buffer. */
|
||||
public void processWSF(short[] data, int off, int len) {
|
||||
if (data == null || len <= 0) return;
|
||||
byte[] bdata = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
bdata[i] = (byte) (data[off + i] & 0xFF);
|
||||
}
|
||||
processWriteStructuredField(bdata, 0, len);
|
||||
}
|
||||
|
||||
public void processWSF(byte[] data, int off, int len) {
|
||||
processWriteStructuredField(data, off, len);
|
||||
}
|
||||
|
||||
/** Process raw inbound data stream chunk (short[] representation). */
|
||||
public void processData(short[] data, int off, int len) {
|
||||
if (data == null || len <= 0) return;
|
||||
byte[] bdata = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
bdata[i] = (byte) (data[off + i] & 0xFF);
|
||||
}
|
||||
processRecord(bdata, 0, len, true);
|
||||
}
|
||||
|
||||
public void processData(byte[] data, int off, int len) {
|
||||
processRecord(data, off, len, true);
|
||||
}
|
||||
|
||||
/** Send AID key with explicit cursor address. */
|
||||
public void sendAid(short aid, int cursorAddress) {
|
||||
if (inputProcessor != null) {
|
||||
inputProcessor.sendAid(aid & 0xFFFF, cursorAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.Telnet3270Client;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLConnection drop-in compatibility class.
|
||||
*/
|
||||
public class ECLConnection extends haus.nightmare.lib3270j.ecl.ECLConnection {
|
||||
|
||||
public ECLConnection() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLConnection(haus.nightmare.lib3270j.ecl.ECLSession session) {
|
||||
super((haus.nightmare.lib3270j.ecl.ECLSession) session, session != null ? session.getClient() : null);
|
||||
}
|
||||
|
||||
public ECLConnection(String host, int port) {
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
public ECLConnection(java.util.Properties props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public ECLConnection(haus.nightmare.lib3270j.ecl.ECLSession session, Telnet3270Client client) {
|
||||
super(session, client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLConstants compatibility interface.
|
||||
*/
|
||||
public interface ECLConstants extends haus.nightmare.lib3270j.ecl.ECLConstants {
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLErr.
|
||||
*/
|
||||
public class ECLErr extends haus.nightmare.lib3270j.ecl.ECLErr {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLErr() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLErr(String text) {
|
||||
super(text);
|
||||
}
|
||||
|
||||
public ECLErr(String tag, String id, String text) {
|
||||
super(tag, id, text);
|
||||
}
|
||||
|
||||
public ECLErr(String tag, String id, String text, String extra) {
|
||||
super(tag, id, text, extra);
|
||||
}
|
||||
|
||||
public ECLErr(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ECLErr(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLErrors compatibility interface.
|
||||
*/
|
||||
public interface ECLErrors extends haus.nightmare.lib3270j.ecl.ECLErrors {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLException compatibility class.
|
||||
*/
|
||||
public class ECLException extends haus.nightmare.lib3270j.ecl.ECLException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLException(int errorCode, String message) {
|
||||
super(errorCode, message);
|
||||
}
|
||||
|
||||
public ECLException(int errorCode, String message, Throwable cause) {
|
||||
super(errorCode, message, cause);
|
||||
}
|
||||
|
||||
public ECLException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLField drop-in compatibility class.
|
||||
*/
|
||||
public class ECLField extends haus.nightmare.lib3270j.ecl.ECLField {
|
||||
|
||||
public ECLField(haus.nightmare.lib3270j.ecl.ECLPS ps, int startPos, int dataStart, int endPos, int length, byte attribute) {
|
||||
super(ps, startPos, dataStart, endPos, length, attribute);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLFieldList drop-in compatibility class.
|
||||
*/
|
||||
public class ECLFieldList extends haus.nightmare.lib3270j.ecl.ECLFieldList {
|
||||
|
||||
public ECLFieldList(haus.nightmare.lib3270j.ecl.ECLPS ps, ScreenBuffer screen) {
|
||||
super(ps, screen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetFSM;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLOIA drop-in compatibility class.
|
||||
*/
|
||||
public class ECLOIA extends haus.nightmare.lib3270j.ecl.ECLOIA {
|
||||
|
||||
public ECLOIA(ScreenBuffer screen, InputProcessor inputProcessor, TelnetFSM fsm) {
|
||||
super(screen, inputProcessor, fsm);
|
||||
}
|
||||
|
||||
public ECLOIA(haus.nightmare.lib3270j.eNetwork.ECL.ECLSession session) {
|
||||
super(session);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLOIANotify.
|
||||
*/
|
||||
public interface ECLOIANotify extends haus.nightmare.lib3270j.ecl.ECLOIANotify {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLPS drop-in compatibility class.
|
||||
*/
|
||||
public class ECLPS extends haus.nightmare.lib3270j.ecl.ECLPS {
|
||||
|
||||
public ECLPS(ScreenBuffer screen, InputProcessor inputProcessor, EbcdicTranslator translator) {
|
||||
super(screen, inputProcessor, translator);
|
||||
}
|
||||
|
||||
public ECLPS(haus.nightmare.lib3270j.eNetwork.ECL.ECLSession session) {
|
||||
super(session);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSBIDIServices.
|
||||
*/
|
||||
public interface ECLPSBIDIServices extends haus.nightmare.lib3270j.ecl.ECLPSBIDIServices {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSGraphicsServices.
|
||||
*/
|
||||
public interface ECLPSGraphicsServices extends haus.nightmare.lib3270j.ecl.ECLPSGraphicsServices {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSHindiServices.
|
||||
*/
|
||||
public interface ECLPSHindiServices extends haus.nightmare.lib3270j.ecl.ECLPSHindiServices {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSTHAIServices.
|
||||
*/
|
||||
public interface ECLPSTHAIServices extends haus.nightmare.lib3270j.ecl.ECLPSTHAIServices {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSUpdate.
|
||||
*/
|
||||
public class ECLPSUpdate extends haus.nightmare.lib3270j.ecl.ECLPSUpdate {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLPSUpdate(haus.nightmare.lib3270j.ecl.ECLPS ps, int startRow, int startCol,
|
||||
int endRow, int endCol, int start, int end, boolean fullUpdate, String text) {
|
||||
super(ps, startRow, startCol, endRow, endCol, start, end, fullUpdate, text);
|
||||
}
|
||||
|
||||
public ECLPSUpdate(int startRow, int startCol, int endRow, int endCol, boolean fullUpdate) {
|
||||
super(startRow, startCol, endRow, endCol, fullUpdate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLScreenDesc drop-in compatibility class.
|
||||
*/
|
||||
public class ECLScreenDesc extends haus.nightmare.lib3270j.ecl.ECLScreenDesc {
|
||||
|
||||
public ECLScreenDesc() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLScreenNotify.
|
||||
*/
|
||||
public interface ECLScreenNotify extends haus.nightmare.lib3270j.ecl.ECLScreenNotify {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLScreenReco.
|
||||
*/
|
||||
public class ECLScreenReco extends haus.nightmare.lib3270j.ecl.ECLScreenReco {
|
||||
|
||||
public ECLScreenReco() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLScreenReco(haus.nightmare.lib3270j.ecl.ECLSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public ECLScreenReco(haus.nightmare.lib3270j.ecl.ECLPS ps) {
|
||||
super(ps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLScreenRecoEvent.
|
||||
*/
|
||||
public class ECLScreenRecoEvent extends haus.nightmare.lib3270j.ecl.ECLScreenRecoEvent {
|
||||
|
||||
public ECLScreenRecoEvent(haus.nightmare.lib3270j.ecl.ECLScreenReco source,
|
||||
haus.nightmare.lib3270j.ecl.ECLScreenDesc screenDesc,
|
||||
haus.nightmare.lib3270j.ecl.ECLPS ps) {
|
||||
super(source, screenDesc, ps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.ConnectionConfig;
|
||||
import haus.nightmare.lib3270j.Telnet3270Client;
|
||||
import haus.nightmare.lib3270j.TerminalModel;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLSession drop-in compatibility class.
|
||||
*/
|
||||
public class ECLSession extends haus.nightmare.lib3270j.ecl.ECLSession {
|
||||
|
||||
public ECLSession() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ECLSession(ConnectionConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
public ECLSession(String host, int port, TerminalModel model) {
|
||||
super(host, port, model);
|
||||
}
|
||||
|
||||
public ECLSession(String host, int port, TerminalModel model, boolean useTls) {
|
||||
super(host, port, model, useTls);
|
||||
}
|
||||
|
||||
public ECLSession(Properties props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public ECLSession(Telnet3270Client client) {
|
||||
super(client);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.datastream.DataStreamProcessor;
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLXfer drop-in compatibility class.
|
||||
*/
|
||||
public class ECLXfer extends haus.nightmare.lib3270j.ecl.ECLXfer {
|
||||
|
||||
public ECLXfer(ScreenBuffer screen, InputProcessor input, DataStreamProcessor dsProcessor, EbcdicTranslator translator) {
|
||||
super(screen, input, dsProcessor, translator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.bidi;
|
||||
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetFSM;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLOIABIDI.
|
||||
*/
|
||||
public class ECLOIABIDI extends haus.nightmare.lib3270j.ecl.ECLOIABIDI {
|
||||
|
||||
public ECLOIABIDI(ScreenBuffer screen, InputProcessor inputProcessor, TelnetFSM fsm) {
|
||||
super(screen, inputProcessor, fsm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
import haus.nightmare.lib3270j.ConnectionState;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLCommEvent compatibility class.
|
||||
*/
|
||||
public class ECLCommEvent extends haus.nightmare.lib3270j.ecl.ECLCommEvent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLCommEvent(Object source, int eventType, ConnectionState oldState, ConnectionState newState,
|
||||
String message, String deviceType, String deviceName) {
|
||||
super(source, eventType, oldState, newState, message, deviceType, deviceName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLCommListener compatibility interface.
|
||||
*/
|
||||
public interface ECLCommListener extends haus.nightmare.lib3270j.ecl.ECLCommListener {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLCommNotify compatibility interface.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ECLCommNotify extends haus.nightmare.lib3270j.ecl.ECLCommNotify {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLOIAEvent compatibility class.
|
||||
*/
|
||||
public class ECLOIAEvent extends haus.nightmare.lib3270j.ecl.ECLOIAEvent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLOIAEvent(Object source, int eventType, int inputInhibited, int alphanumericType,
|
||||
boolean insertMode, String statusString) {
|
||||
super(source, eventType, inputInhibited, alphanumericType, insertMode, statusString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLOIAListener compatibility interface.
|
||||
*/
|
||||
public interface ECLOIAListener extends haus.nightmare.lib3270j.ecl.ECLOIAListener {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLOIANotify in event package.
|
||||
*/
|
||||
public interface ECLOIANotify extends haus.nightmare.lib3270j.ecl.ECLOIANotify {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLPSUpdate;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLPSEvent compatibility class.
|
||||
*/
|
||||
public class ECLPSEvent extends haus.nightmare.lib3270j.ecl.ECLPSEvent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ECLPSEvent(Object source, int eventType, int type, int startRow, int startCol,
|
||||
int endRow, int endCol, int oldCursorAddress, int newCursorAddress,
|
||||
int rows, int cols, boolean fullUpdate, boolean cursorVisible,
|
||||
int ringCounter, boolean startPrinterBit, ECLPSUpdate psUpdate) {
|
||||
super(source, eventType, type, startRow, startCol, endRow, endCol,
|
||||
oldCursorAddress, newCursorAddress, rows, cols, fullUpdate,
|
||||
cursorVisible, ringCounter, startPrinterBit, psUpdate);
|
||||
}
|
||||
|
||||
public ECLPSEvent(Object source, int eventType, int startRow, int startCol, int endRow, int endCol,
|
||||
int oldCursorAddress, int newCursorAddress, int rows, int cols, boolean fullUpdate) {
|
||||
super(source, eventType, startRow, startCol, endRow, endCol, oldCursorAddress, newCursorAddress, rows, cols, fullUpdate);
|
||||
}
|
||||
|
||||
public ECLPSEvent(Object source, int eventType) {
|
||||
super(source, eventType);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSGraphicsEvent.
|
||||
*/
|
||||
public class ECLPSGraphicsEvent extends haus.nightmare.lib3270j.ecl.ECLPSGraphicsEvent {
|
||||
|
||||
public ECLPSGraphicsEvent(haus.nightmare.lib3270j.ecl.ECLPS source, int id) {
|
||||
super(source, id);
|
||||
}
|
||||
|
||||
public ECLPSGraphicsEvent(haus.nightmare.lib3270j.ecl.ECLPS source, int id, Image image) {
|
||||
super(source, id, image);
|
||||
}
|
||||
|
||||
public ECLPSGraphicsEvent(haus.nightmare.lib3270j.ecl.ECLPS source, int id, Image image, Rectangle rectangle) {
|
||||
super(source, id, image, rectangle);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLPSGraphicsListener.
|
||||
*/
|
||||
public interface ECLPSGraphicsListener extends haus.nightmare.lib3270j.ecl.ECLPSGraphicsListener {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.event;
|
||||
|
||||
/**
|
||||
* IBM Host On-Demand ECLPSListener compatibility interface.
|
||||
*/
|
||||
public interface ECLPSListener extends haus.nightmare.lib3270j.ecl.ECLPSListener {
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hindi;
|
||||
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetFSM;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLOIAHindi.
|
||||
*/
|
||||
public class ECLOIAHindi extends haus.nightmare.lib3270j.ecl.ECLOIAHindi {
|
||||
|
||||
public ECLOIAHindi(ScreenBuffer screen, InputProcessor inputProcessor, TelnetFSM fsm) {
|
||||
super(screen, inputProcessor, fsm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for Edge.
|
||||
*/
|
||||
public class Edge extends haus.nightmare.lib3270j.graphics.Edge {
|
||||
public Edge(int x1, int y1, int x2, int y2) {
|
||||
super(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for FillArea.
|
||||
*/
|
||||
public class FillArea extends haus.nightmare.lib3270j.graphics.FillArea {
|
||||
public FillArea() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FillArea(int fillRule) {
|
||||
super(fillRule);
|
||||
}
|
||||
|
||||
public FillArea(int[] px, int[] py, int[] polyCounts, int numPolys, Color color) {
|
||||
super(px, py, polyCounts, numPolys, color);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for FilletPts.
|
||||
*/
|
||||
public class FilletPts extends haus.nightmare.lib3270j.graphics.FilletPts {
|
||||
public FilletPts() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODBitImage.
|
||||
*/
|
||||
public class HODBitImage extends haus.nightmare.lib3270j.graphics.HODBitImage {
|
||||
public HODBitImage(Component comp, int width, int height, byte[] data, int baseColor, int depth, boolean useGraphicColors) {
|
||||
super(comp, width, height, data, baseColor, depth, useGraphicColors);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODBounds.
|
||||
*/
|
||||
public class HODBounds extends haus.nightmare.lib3270j.graphics.HODBounds {
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODColorChangeFilter.
|
||||
*/
|
||||
public class HODColorChangeFilter extends haus.nightmare.lib3270j.graphics.HODColorChangeFilter {
|
||||
public HODColorChangeFilter(int color) {
|
||||
super(color);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import haus.nightmare.lib3270j.graphics.GraphicsPlane;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODGraphicsPlane.
|
||||
*/
|
||||
public class HODGraphicsPlane extends haus.nightmare.lib3270j.graphics.HODGraphicsPlane {
|
||||
public HODGraphicsPlane() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODGraphicsPlane(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
public HODGraphicsPlane(GraphicsPlane delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODPart.
|
||||
*/
|
||||
public class HODPart extends haus.nightmare.lib3270j.graphics.HODPart {
|
||||
public HODPart() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODPart(Component component) {
|
||||
super(component);
|
||||
}
|
||||
|
||||
public HODPart(Component component, Dimension dimension) {
|
||||
super(component, dimension);
|
||||
}
|
||||
|
||||
public HODPart(Component component, Rectangle rectangle) {
|
||||
super(component, rectangle);
|
||||
}
|
||||
|
||||
public HODPart(HODPart hODPart) {
|
||||
super(hODPart);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import haus.nightmare.lib3270j.graphics.ProgramSymbolManager;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODProgramSymbolManager.
|
||||
*/
|
||||
public class HODProgramSymbolManager extends haus.nightmare.lib3270j.graphics.HODProgramSymbolManager {
|
||||
public HODProgramSymbolManager() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODProgramSymbolManager(ProgramSymbolManager delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODTransform.
|
||||
*/
|
||||
public class HODTransform extends haus.nightmare.lib3270j.graphics.HODTransform {
|
||||
public HODTransform(int charW, int charH, int defaultCharW, int defaultCharH) {
|
||||
super(charW, charH, defaultCharW, defaultCharH);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODTransparentColorFilter.
|
||||
*/
|
||||
public class HODTransparentColorFilter extends haus.nightmare.lib3270j.graphics.HODTransparentColorFilter {
|
||||
public HODTransparentColorFilter(int transparentColor) {
|
||||
super(transparentColor);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.hostgraphics;
|
||||
|
||||
import java.awt.Image;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for HODWallpaper.
|
||||
*/
|
||||
public class HODWallpaper extends haus.nightmare.lib3270j.graphics.HODWallpaper {
|
||||
public HODWallpaper() {
|
||||
super();
|
||||
}
|
||||
|
||||
public HODWallpaper(int displayMode) {
|
||||
super(displayMode);
|
||||
}
|
||||
|
||||
public HODWallpaper(Image image, int displayMode) {
|
||||
super(image, displayMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.thai;
|
||||
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetFSM;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for ECLOIATHAI.
|
||||
*/
|
||||
public class ECLOIATHAI extends haus.nightmare.lib3270j.ecl.ECLOIATHAI {
|
||||
|
||||
public ECLOIATHAI(ScreenBuffer screen, InputProcessor inputProcessor, TelnetFSM fsm) {
|
||||
super(screen, inputProcessor, fsm);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.datastream.DataStreamProcessor;
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
import haus.nightmare.lib3270j.ecl.ECLSession;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270.DS3270.
|
||||
*/
|
||||
public class DS3270 extends haus.nightmare.lib3270j.tn3270.DS3270 {
|
||||
|
||||
public DS3270() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DS3270(ScreenBuffer screen, EbcdicTranslator translator) {
|
||||
super(screen, translator);
|
||||
}
|
||||
|
||||
public DS3270(DataStreamProcessor delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public DS3270(ECLSession session, ECLPS ps) {
|
||||
super(session, ps);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
import haus.nightmare.lib3270j.ecl.ECLSession;
|
||||
import haus.nightmare.lib3270j.nvt.NvtProcessor;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270.NVT3270.
|
||||
*/
|
||||
public class NVT3270 extends haus.nightmare.lib3270j.tn3270.NVT3270 {
|
||||
|
||||
public NVT3270() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NVT3270(NvtProcessor nvtProcessor) {
|
||||
super(nvtProcessor);
|
||||
}
|
||||
|
||||
public NVT3270(String host, ECLSession session, ECLPS ps, haus.nightmare.lib3270j.tn3270.DS3270 ds) {
|
||||
super(host, session, ps, ds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.ecl.ECLSession;
|
||||
import haus.nightmare.lib3270j.input.InputProcessor;
|
||||
import haus.nightmare.lib3270j.screen.ScreenBuffer;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270.PS3270.
|
||||
*/
|
||||
public class PS3270 extends haus.nightmare.lib3270j.tn3270.PS3270 {
|
||||
|
||||
public PS3270() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PS3270(ECLSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public PS3270(ScreenBuffer screen, InputProcessor inputProcessor, EbcdicTranslator translator) {
|
||||
super(screen, inputProcessor, translator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270;
|
||||
|
||||
import haus.nightmare.lib3270j.ecl.ECLPS;
|
||||
import haus.nightmare.lib3270j.ecl.ECLSession;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetConnection;
|
||||
import haus.nightmare.lib3270j.telnet.TelnetFSM;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270.Telnet3270E.
|
||||
*/
|
||||
public class Telnet3270E extends haus.nightmare.lib3270j.tn3270.Telnet3270E {
|
||||
|
||||
public Telnet3270E() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Telnet3270E(TelnetFSM fsm, TelnetConnection connection) {
|
||||
super(fsm, connection);
|
||||
}
|
||||
|
||||
public Telnet3270E(String host, ECLSession session, ECLPS ps, haus.nightmare.lib3270j.tn3270.DS3270 ds) {
|
||||
super(host, session, ps, ds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270.qr_elem.
|
||||
*/
|
||||
public class qr_elem extends haus.nightmare.lib3270j.tn3270.qr_elem {
|
||||
|
||||
public qr_elem() {
|
||||
super();
|
||||
}
|
||||
|
||||
public qr_elem(int type, int sendFlag) {
|
||||
super(type, sendFlag);
|
||||
}
|
||||
|
||||
public qr_elem(byte type, byte sendFlag) {
|
||||
super(type, sendFlag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270p;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.printer.PD3270;
|
||||
import haus.nightmare.lib3270j.printer.PrintPS3270;
|
||||
import haus.nightmare.lib3270j.printer.PrintSCS3270;
|
||||
import haus.nightmare.lib3270j.printer.PrinterConfig;
|
||||
import haus.nightmare.lib3270j.printer.Telnet3270EP;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270p.DS3270P.
|
||||
*/
|
||||
public class DS3270P extends haus.nightmare.lib3270j.printer.DS3270P {
|
||||
|
||||
public DS3270P() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DS3270P(PrinterConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
public DS3270P(PrinterConfig config, PD3270 pd, EbcdicTranslator translator) {
|
||||
super(config, pd, translator);
|
||||
}
|
||||
|
||||
public DS3270P(Telnet3270EP telnet, PrinterConfig config, PD3270 pd,
|
||||
PrintSCS3270 scs, PrintPS3270 printPs, EbcdicTranslator translator) {
|
||||
super(telnet, config, pd, scs, printPs, translator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270p;
|
||||
|
||||
import haus.nightmare.lib3270j.printer.PrinterConfig;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270p.PD3270.
|
||||
*/
|
||||
public class PD3270 extends haus.nightmare.lib3270j.printer.PD3270 {
|
||||
|
||||
public PD3270() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PD3270(PrinterConfig config) {
|
||||
super(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270p;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270p.PDT.
|
||||
*/
|
||||
public class PDT extends PrinterDefinitionTable {
|
||||
|
||||
public PDT(String name, String description) {
|
||||
super(name, description);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270p;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.printer.PD3270;
|
||||
import haus.nightmare.lib3270j.printer.PrinterConfig;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270p.PrintPS3270.
|
||||
*/
|
||||
public class PrintPS3270 extends haus.nightmare.lib3270j.printer.PrintPS3270 {
|
||||
|
||||
public PrintPS3270(PrinterConfig config, PD3270 pd, EbcdicTranslator translator) {
|
||||
super(config, pd, translator);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package haus.nightmare.lib3270j.eNetwork.ECL.tn3270p;
|
||||
|
||||
import haus.nightmare.lib3270j.charset.EbcdicTranslator;
|
||||
import haus.nightmare.lib3270j.printer.PD3270;
|
||||
import haus.nightmare.lib3270j.printer.PrinterConfig;
|
||||
|
||||
/**
|
||||
* Drop-in IBM Host On-Demand compatible facade for com.ibm.eNetwork.ECL.tn3270p.PrintPS3270DB.
|
||||
*/
|
||||
public class PrintPS3270DB extends haus.nightmare.lib3270j.printer.PrintPS3270DB {
|
||||
|
||||
public PrintPS3270DB(PrinterConfig config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
public PrintPS3270DB(PrinterConfig config, PD3270 pd, EbcdicTranslator translator) {
|
||||
super(config, pd, translator);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user