Codepage, ECL, and some UI updates
This commit is contained in:
@@ -131,7 +131,18 @@ public class ECLField extends haus.nightmare.lib3270j.ecl.ECLField implements EC
|
||||
return delegate != null ? (short) (delegate.getAttribute() & 0xFF) : 0;
|
||||
}
|
||||
|
||||
public short getAttribute() { return GetAttribute(); }
|
||||
public boolean IsDBCS() {
|
||||
return delegate != null && delegate.isDBCS();
|
||||
}
|
||||
|
||||
public boolean isDBCS() { return IsDBCS(); }
|
||||
|
||||
public boolean IsDBCSOnly() {
|
||||
return delegate != null && delegate.isDBCSOnly();
|
||||
}
|
||||
|
||||
public boolean isDBCSOnly() { return IsDBCSOnly(); }
|
||||
|
||||
public haus.nightmare.lib3270j.ecl.ECLField getDelegate() { return delegate; }
|
||||
}
|
||||
|
||||
|
||||
@@ -511,4 +511,61 @@ public class ECLPS implements ECLConstants, Serializable, Cloneable {
|
||||
public int GetScreen(char[] buffer, int len, int row, int col, int length, int plane) {
|
||||
return delegate.GetScreen(buffer, len, row, col, length, plane);
|
||||
}
|
||||
|
||||
// ========== DBCS Character Status ==========
|
||||
|
||||
public boolean IsDBCSChar(int pos) {
|
||||
return delegate != null && delegate.IsDBCSChar(pos);
|
||||
}
|
||||
|
||||
public boolean isDBCSChar(int pos) { return IsDBCSChar(pos); }
|
||||
|
||||
public boolean IsDBCSChar(int row, int col) {
|
||||
return delegate != null && delegate.IsDBCSChar(row, col);
|
||||
}
|
||||
|
||||
public boolean isDBCSChar(int row, int col) { return IsDBCSChar(row, col); }
|
||||
|
||||
public boolean IsDBCS1stChar(int pos) {
|
||||
return delegate != null && delegate.IsDBCS1stChar(pos);
|
||||
}
|
||||
|
||||
public boolean isDBCS1stChar(int pos) { return IsDBCS1stChar(pos); }
|
||||
|
||||
public boolean IsDBCS1stChar(int row, int col) {
|
||||
return delegate != null && delegate.IsDBCS1stChar(row, col);
|
||||
}
|
||||
|
||||
public boolean isDBCS1stChar(int row, int col) { return IsDBCS1stChar(row, col); }
|
||||
|
||||
public boolean IsDBCS2ndChar(int pos) {
|
||||
return delegate != null && delegate.IsDBCS2ndChar(pos);
|
||||
}
|
||||
|
||||
public boolean isDBCS2ndChar(int pos) { return IsDBCS2ndChar(pos); }
|
||||
|
||||
public boolean IsDBCS2ndChar(int row, int col) {
|
||||
return delegate != null && delegate.IsDBCS2ndChar(row, col);
|
||||
}
|
||||
|
||||
public boolean isDBCS2ndChar(int row, int col) { return IsDBCS2ndChar(row, col); }
|
||||
|
||||
public boolean IsSOChar(int pos) {
|
||||
return delegate != null && delegate.IsSOChar(pos);
|
||||
}
|
||||
|
||||
public boolean isSOChar(int pos) { return IsSOChar(pos); }
|
||||
|
||||
public boolean IsSIChar(int pos) {
|
||||
return delegate != null && delegate.IsSIChar(pos);
|
||||
}
|
||||
|
||||
public boolean isSIChar(int pos) { return IsSIChar(pos); }
|
||||
|
||||
public boolean IsSOSIChar(int pos) {
|
||||
return delegate != null && delegate.IsSOSIChar(pos);
|
||||
}
|
||||
|
||||
public boolean isSOSIChar(int pos) { return IsSOSIChar(pos); }
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,15 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
int[] sbcsMapping, String nioCharsetName) {
|
||||
super(id, description, cpgid, cgcsgid, sbcsMapping);
|
||||
if (nioCharsetName != null) {
|
||||
try {
|
||||
if (Charset.isSupported(nioCharsetName)) {
|
||||
this.nioCharset = Charset.forName(nioCharsetName);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
for (String candidate : nioCharsetName.split(",")) {
|
||||
candidate = candidate.trim();
|
||||
try {
|
||||
if (Charset.isSupported(candidate)) {
|
||||
this.nioCharset = Charset.forName(candidate);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
// Initialize ideographic space (0x4040 <-> \u3000)
|
||||
registerDbcsPair(0x4040, '\u3000');
|
||||
@@ -250,4 +254,78 @@ public abstract class AbstractDBCSCodePage extends AbstractCodePage {
|
||||
public byte[] utf8WithSOSIToEbcdic(String s) {
|
||||
return stringToEbcdic(s, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Double-byte character set Graphic Character Set Global ID (DBGID/CGCSGID) matching HoD DBGIDTable.
|
||||
*/
|
||||
public int getDbCgcsgid() {
|
||||
switch (getCpgid()) {
|
||||
case 930:
|
||||
case 939:
|
||||
case 290:
|
||||
return 370; // 0x0172
|
||||
case 933:
|
||||
return 934; // 0x03A6
|
||||
case 935:
|
||||
return 937; // 0x03A9
|
||||
case 937:
|
||||
return 935; // 0x03A7
|
||||
case 1390:
|
||||
case 1399:
|
||||
case 1364:
|
||||
case 1371:
|
||||
case 1388:
|
||||
return 65535; // 0xFFFF
|
||||
default:
|
||||
return 370;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Double-byte character set Code Page Global ID (DBCS CPGID) matching HoD DBGIDTable.
|
||||
*/
|
||||
public int getDbCpgid() {
|
||||
switch (getCpgid()) {
|
||||
case 930:
|
||||
case 939:
|
||||
case 290:
|
||||
case 1390:
|
||||
case 1399:
|
||||
return 300; // 0x012C
|
||||
case 933:
|
||||
case 1364:
|
||||
return 834; // 0x0342
|
||||
case 935:
|
||||
case 1388:
|
||||
return 837; // 0x0345
|
||||
case 937:
|
||||
case 1371:
|
||||
return 835; // 0x0343
|
||||
default:
|
||||
return 300;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Double-byte character set section start byte matching HoD DBCSSectTable.
|
||||
*/
|
||||
public byte getDbcsSectionStart() {
|
||||
return 0x41;
|
||||
}
|
||||
|
||||
/**
|
||||
* Double-byte character set section end byte matching HoD DBCSSectTable.
|
||||
*/
|
||||
public byte getDbcsSectionEnd() {
|
||||
switch (getCpgid()) {
|
||||
case 290:
|
||||
case 930:
|
||||
case 935:
|
||||
case 939:
|
||||
return 0x7F;
|
||||
default:
|
||||
return (byte) 0xFE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -311,6 +311,12 @@ public class CodePageRegistry {
|
||||
register(new Cp1388());
|
||||
register(new Cp1371());
|
||||
|
||||
// Japanese Katakana & Latin SBCS / DBCS Euro
|
||||
register(new Cp290());
|
||||
register(new Cp1027());
|
||||
register(new Cp1390());
|
||||
register(new Cp1399());
|
||||
|
||||
// Setup Extended Aliases
|
||||
addAlias("ar", "420");
|
||||
addAlias("arabic", "420");
|
||||
@@ -360,10 +366,12 @@ public class CodePageRegistry {
|
||||
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("1390", "1390");
|
||||
addAlias("1390jis2004", "1390");
|
||||
addAlias("1399", "1399");
|
||||
addAlias("1399jis2004", "1399");
|
||||
addAlias("290", "290");
|
||||
addAlias("1027", "1027");
|
||||
addAlias("937macau", "937");
|
||||
addAlias("1364", "933");
|
||||
addAlias("1379", "937");
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1027 (Japanese Latin Extended SBCS).
|
||||
* Conforms 1:1 to IBM Host On-Demand com.ibm.eNetwork.HOD.converters.ja.ByteToCharCp939.singleByteToChar.
|
||||
* CCSID / CPGID: 1027, GCSGID: 1172.
|
||||
*/
|
||||
public class Cp1027 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "1027";
|
||||
public static final String DESCRIPTION = "Japanese Latin Extended - EBCDIC";
|
||||
public static final int CPGID = 1027;
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
private static final String SBCS_STR =
|
||||
"\u0000\u0001\u0002\u0003\u009c\t\u0086\u007f\u0097\u008d\u008e\u000b\f\r\u000e\u000f" +
|
||||
"\u0010\u0011\u0012\u0013\u009d\u0085\b\u0087\u0018\u0019\u0092\u008f\u001c\u001d\u001e\u001f" +
|
||||
"\u0080\u0081\u0082\u0083\u0084\n\u0017\u001b\u0088\u0089\u008a\u008b\u008c\u0005\u0006\u0007" +
|
||||
"\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009a\u009b\u0014\u0015\u009e\u001a" +
|
||||
" \ufffd\uff61\uff62\uff63\uff64\uff65\uff66\uff67\uff68\u00a2.<(+|" +
|
||||
"&\uff69\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\uff70\uff71!$*);\u00ac" +
|
||||
"-/\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\ufffd,%_>?" +
|
||||
"\uff7a\uff7b\uff7c\uff7d\uff7e\uff7f\uff80\uff81\uff82`:#@'=\"" +
|
||||
"\ufffdabcdefghi\uff83\uff84\uff85\uff86\uff87\uff88" +
|
||||
"\ufffdjklmnopqr\uff89\uff8a\uff8b\uff8c\uff8d\uff8e" +
|
||||
"\u203e~stuvwxyz\uff8f\uff90\uff91[\uff92\uff93^" +
|
||||
"\u00a3\u00a5\uff94\uff95\uff96\uff97\uff98\uff99\uff9a\uff9b\uff9c\uff9d]\uff9e\uff9f" +
|
||||
"{ABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"}JKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"\\\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f";
|
||||
|
||||
public static final int[] MAPPING = new int[256];
|
||||
static {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
MAPPING[i] = (i < SBCS_STR.length()) ? SBCS_STR.charAt(i) : i;
|
||||
}
|
||||
}
|
||||
|
||||
public Cp1027() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1390 (Japanese Katakana Extended Mixed DBCS with Euro support: host SBCS CP290+Euro / DBCS CP16684).
|
||||
* CCSID / CPGID: 1390, GCSGID: 1172.
|
||||
*/
|
||||
public class Cp1390 extends AbstractDBCSCodePage {
|
||||
|
||||
public static final String ID = "1390";
|
||||
public static final String DESCRIPTION = "Japanese Katakana Extended Mixed DBCS (with Euro)";
|
||||
public static final int CPGID = 1390;
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
public static final int[] MAPPING = Cp290.MAPPING.clone();
|
||||
static {
|
||||
// Euro symbol at 0xE1
|
||||
MAPPING[0xE1] = 0x20AC;
|
||||
}
|
||||
|
||||
public Cp1390() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, MAPPING, "x-IBM1390,IBM1390,Cp1390,x-IBM930,IBM930,Cp930");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 1399 (Japanese Latin Extended Mixed DBCS with Euro support: host SBCS CP1027+Euro / DBCS CP16684).
|
||||
* CCSID / CPGID: 1399, GCSGID: 1172.
|
||||
*/
|
||||
public class Cp1399 extends AbstractDBCSCodePage {
|
||||
|
||||
public static final String ID = "1399";
|
||||
public static final String DESCRIPTION = "Japanese Latin Extended Mixed DBCS (with Euro)";
|
||||
public static final int CPGID = 1399;
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
public static final int[] MAPPING = Cp1027.MAPPING.clone();
|
||||
static {
|
||||
// Euro symbol at 0xE1
|
||||
MAPPING[0xE1] = 0x20AC;
|
||||
}
|
||||
|
||||
public Cp1399() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, MAPPING, "x-IBM1399,IBM1399,Cp1399,x-IBM939,IBM939,Cp939");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package haus.nightmare.lib3270j.charset;
|
||||
|
||||
/**
|
||||
* IBM Code Page 290 (Japanese Katakana Extended SBCS).
|
||||
* Conforms 1:1 to IBM Host On-Demand com.ibm.eNetwork.HOD.converters.ja.ByteToCharCp290.
|
||||
* CCSID / CPGID: 290, GCSGID: 1172.
|
||||
*/
|
||||
public class Cp290 extends AbstractCodePage {
|
||||
|
||||
public static final String ID = "290";
|
||||
public static final String DESCRIPTION = "Japanese Katakana Extended - EBCDIC";
|
||||
public static final int CPGID = 290;
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
private static final String SBCS_STR =
|
||||
"\u0000\u0001\u0002\u0003\u009c\t\u0086\u007f\u0097\u008d\u008e\u000b\f\r\u000e\u000f" +
|
||||
"\u0010\u0011\u0012\u0013\u009d\u0085\b\u0087\u0018\u0019\u0092\u008f\u001c\u001d\u001e\u001f" +
|
||||
"\u0080\u0081\u0082\u0083\u0084\n\u0017\u001b\u0088\u0089\u008a\u008b\u008c\u0005\u0006\u0007" +
|
||||
"\u0090\u0091\u0016\u0093\u0094\u0095\u0096\u0004\u0098\u0099\u009a\u009b\u0014\u0015\u009e\u001a" +
|
||||
" \uff61\uff62\uff63\uff64\uff65\uff66\uff67\uff68\uff69\u00a3.<(+|" +
|
||||
"&\uff6a\uff6b\uff6c\uff6d\uff6e\uff6f\ufffd\uff70\ufffd!\u00a5*);\u00ac" +
|
||||
"-/\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ufffd,%_>?" +
|
||||
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000:#@'=\"" +
|
||||
"\u0000\uff71\uff72\uff73\uff74\uff75\uff76\uff77\uff78\uff79\uff7a\u0000\uff7b\uff7c\uff7d\uff7e" +
|
||||
"\uff7f\uff80\uff81\uff82\uff83\uff84\uff85\uff86\uff87\uff88\uff89\u0000\ufffd\uff8a\uff8b\uff8c" +
|
||||
"\u0000\u203e\uff8d\uff8e\uff8f\uff90\uff91\uff92\uff93\uff94\uff95\u0000\uff96\uff97\uff98\uff99" +
|
||||
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\uff9a\uff9b\uff9c\uff9d\uff9e\uff9f" +
|
||||
"\u0000ABCDEFGHI\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"\u0000JKLMNOPQR\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"$\ufffdSTUVWXYZ\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd" +
|
||||
"0123456789\ufffd\ufffd\ufffd\ufffd\ufffd\u009f";
|
||||
|
||||
public static final int[] MAPPING = new int[256];
|
||||
static {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
MAPPING[i] = (i < SBCS_STR.length()) ? SBCS_STR.charAt(i) : i;
|
||||
}
|
||||
}
|
||||
|
||||
public Cp290() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, MAPPING);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,6 @@ public class Cp930 extends AbstractDBCSCodePage {
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
public Cp930() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp037.MAPPING, "x-IBM930");
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp290.MAPPING, "x-IBM930,IBM930,Cp930");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ public class Cp939 extends AbstractDBCSCodePage {
|
||||
public static final int GCSGID = 1172;
|
||||
|
||||
public Cp939() {
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp037.MAPPING, "x-IBM939");
|
||||
super(ID, DESCRIPTION, CPGID, GCSGID, Cp1027.MAPPING, "x-IBM939,IBM939,Cp939");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,35 @@ public class EbcdicTranslator {
|
||||
return isDBCSCodePage();
|
||||
}
|
||||
|
||||
public synchronized int getDbCgcsgid() {
|
||||
if (activeCodePage instanceof AbstractDBCSCodePage) {
|
||||
return ((AbstractDBCSCodePage) activeCodePage).getDbCgcsgid();
|
||||
}
|
||||
return 370;
|
||||
}
|
||||
|
||||
public synchronized int getDbCpgid() {
|
||||
if (activeCodePage instanceof AbstractDBCSCodePage) {
|
||||
return ((AbstractDBCSCodePage) activeCodePage).getDbCpgid();
|
||||
}
|
||||
return 300;
|
||||
}
|
||||
|
||||
public synchronized byte getDbcsSectionStart() {
|
||||
if (activeCodePage instanceof AbstractDBCSCodePage) {
|
||||
return ((AbstractDBCSCodePage) activeCodePage).getDbcsSectionStart();
|
||||
}
|
||||
return 0x41;
|
||||
}
|
||||
|
||||
public synchronized byte getDbcsSectionEnd() {
|
||||
if (activeCodePage instanceof AbstractDBCSCodePage) {
|
||||
return ((AbstractDBCSCodePage) activeCodePage).getDbcsSectionEnd();
|
||||
}
|
||||
return 0x7F;
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Custom Character Translation Overrides
|
||||
// =========================================================================
|
||||
|
||||
+158
-1
@@ -60,6 +60,8 @@ public class DataStreamProcessor {
|
||||
private byte currentGr = 0;
|
||||
private byte currentCs = 0;
|
||||
private byte currentOl = 0;
|
||||
private byte currentTr = 0;
|
||||
private boolean inDBCS = false;
|
||||
|
||||
/** Functional interface for sending output back through the telnet stack. */
|
||||
@FunctionalInterface
|
||||
@@ -252,6 +254,7 @@ public class DataStreamProcessor {
|
||||
currentGr = 0;
|
||||
currentCs = 0;
|
||||
currentOl = 0;
|
||||
currentTr = 0;
|
||||
break;
|
||||
case CMD_WSF:
|
||||
case SNA_CMD_WSF:
|
||||
@@ -395,6 +398,8 @@ public class DataStreamProcessor {
|
||||
currentGr = 0;
|
||||
currentCs = 0;
|
||||
currentOl = 0;
|
||||
currentTr = 0;
|
||||
inDBCS = false;
|
||||
}
|
||||
|
||||
if (eraseFirst) {
|
||||
@@ -405,6 +410,8 @@ public class DataStreamProcessor {
|
||||
currentGr = 0;
|
||||
currentCs = 0;
|
||||
currentOl = 0;
|
||||
currentTr = 0;
|
||||
inDBCS = false;
|
||||
}
|
||||
|
||||
// Process orders and data starting at byte 2
|
||||
@@ -435,6 +442,7 @@ public class DataStreamProcessor {
|
||||
}
|
||||
|
||||
case ORDER_SF: { // Start Field
|
||||
inDBCS = false;
|
||||
if (pos + 1 >= end) {
|
||||
pos = end;
|
||||
break;
|
||||
@@ -456,6 +464,7 @@ public class DataStreamProcessor {
|
||||
}
|
||||
|
||||
case ORDER_SFE: { // Start Field Extended
|
||||
inDBCS = false;
|
||||
if (pos + 1 >= end) {
|
||||
pos = end;
|
||||
break;
|
||||
@@ -502,6 +511,7 @@ public class DataStreamProcessor {
|
||||
currentGr = 0;
|
||||
currentCs = 0;
|
||||
currentOl = 0;
|
||||
currentTr = 0;
|
||||
break;
|
||||
case XA_FOREGROUND:
|
||||
currentFg = (byte) attrValue;
|
||||
@@ -530,6 +540,9 @@ public class DataStreamProcessor {
|
||||
case 0x84:
|
||||
currentOl = (byte) attrValue;
|
||||
break;
|
||||
case XA_TRANSPARENCY:
|
||||
currentTr = (byte) attrValue;
|
||||
break;
|
||||
}
|
||||
pos += 3;
|
||||
lastWasOrder = true;
|
||||
@@ -591,6 +604,44 @@ public class DataStreamProcessor {
|
||||
if (toAddr >= size)
|
||||
toAddr = toAddr % size;
|
||||
|
||||
boolean isDbcsSession = (translator != null && translator.isDBCS());
|
||||
if (isDbcsSession && (inDBCS || currentCs == ExtendedAttribute.CS_DBCS) && pos + 4 < end) {
|
||||
int fillChar2 = data[pos + 4] & 0xFF;
|
||||
char uni = (translator.getCodePage() != null) ? translator.getCodePage().dbcsToUnicode(fillChar, fillChar2) : '?';
|
||||
do {
|
||||
ExtendedAttribute ea1 = screen.getCell(baddr);
|
||||
ea1.fa = 0;
|
||||
ea1.ec = (byte) fillChar;
|
||||
ea1.ucs4 = uni;
|
||||
ea1.fg = currentFg;
|
||||
ea1.bg = currentBg;
|
||||
ea1.gr = (byte) currentGr;
|
||||
ea1.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea1.db = ExtendedAttribute.DB_LEFT;
|
||||
ea1.ol = currentOl;
|
||||
ea1.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
if (baddr == toAddr) break;
|
||||
|
||||
ExtendedAttribute ea2 = screen.getCell(baddr);
|
||||
ea2.fa = 0;
|
||||
ea2.ec = (byte) fillChar2;
|
||||
ea2.ucs4 = uni;
|
||||
ea2.fg = currentFg;
|
||||
ea2.bg = currentBg;
|
||||
ea2.gr = (byte) currentGr;
|
||||
ea2.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea2.db = ExtendedAttribute.DB_RIGHT;
|
||||
ea2.ol = currentOl;
|
||||
ea2.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 5;
|
||||
lastWasOrder = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle GE (graphic escape) prefix
|
||||
byte fillCs = currentCs;
|
||||
char fillUcs4 = 0;
|
||||
@@ -614,7 +665,9 @@ public class DataStreamProcessor {
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.cs = fillCs;
|
||||
ea.db = ExtendedAttribute.DB_NONE;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
} while (baddr != toAddr);
|
||||
screen.setBufferAddress(baddr);
|
||||
@@ -644,6 +697,7 @@ public class DataStreamProcessor {
|
||||
ea.gr = 0;
|
||||
ea.cs = 0;
|
||||
ea.ol = 0;
|
||||
ea.tr = 0;
|
||||
}
|
||||
}
|
||||
baddr = (baddr + 1) % size;
|
||||
@@ -669,6 +723,7 @@ public class DataStreamProcessor {
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 2;
|
||||
@@ -677,6 +732,98 @@ public class DataStreamProcessor {
|
||||
}
|
||||
|
||||
default: {
|
||||
boolean isDbcsSession = (translator != null && translator.isDBCS());
|
||||
if (isDbcsSession && b == 0x0E) { // Shift-Out (enter DBCS mode)
|
||||
inDBCS = true;
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0;
|
||||
ea.ec = (byte) 0x0E;
|
||||
ea.ucs4 = ' ';
|
||||
ea.cs = ExtendedAttribute.CS_BASE;
|
||||
ea.db = ExtendedAttribute.DB_SO;
|
||||
ea.fg = currentFg;
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 1;
|
||||
lastWasOrder = false;
|
||||
break;
|
||||
} else if (isDbcsSession && b == 0x0F) { // Shift-In (exit DBCS mode)
|
||||
inDBCS = false;
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0;
|
||||
ea.ec = (byte) 0x0F;
|
||||
ea.ucs4 = ' ';
|
||||
ea.cs = ExtendedAttribute.CS_BASE;
|
||||
ea.db = ExtendedAttribute.DB_SI;
|
||||
ea.fg = currentFg;
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
baddr = (baddr + 1) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 1;
|
||||
lastWasOrder = false;
|
||||
break;
|
||||
} else if (isDbcsSession && (inDBCS || currentCs == ExtendedAttribute.CS_DBCS)) {
|
||||
if (pos + 1 < end) {
|
||||
int b2 = data[pos + 1] & 0xFF;
|
||||
if (b2 == 0x0F) { // Orphaned single byte before SI
|
||||
ExtendedAttribute ea = screen.getCell(baddr);
|
||||
ea.fa = 0;
|
||||
ea.ec = (byte) b;
|
||||
ea.ucs4 = translator.ebcdicToUnicode(b);
|
||||
ea.fg = currentFg;
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.cs = currentCs;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
ea.db = ExtendedAttribute.DB_NONE;
|
||||
baddr = (baddr + 1) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 1;
|
||||
lastWasOrder = false;
|
||||
break;
|
||||
}
|
||||
char uni = (translator.getCodePage() != null) ? translator.getCodePage().dbcsToUnicode(b, b2) : '?';
|
||||
ExtendedAttribute ea1 = screen.getCell(baddr);
|
||||
ea1.fa = 0;
|
||||
ea1.ec = (byte) b;
|
||||
ea1.ucs4 = uni;
|
||||
ea1.fg = currentFg;
|
||||
ea1.bg = currentBg;
|
||||
ea1.gr = (byte) currentGr;
|
||||
ea1.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea1.db = ExtendedAttribute.DB_LEFT;
|
||||
ea1.ol = currentOl;
|
||||
ea1.tr = currentTr;
|
||||
|
||||
int nextAddr = (baddr + 1) % size;
|
||||
ExtendedAttribute ea2 = screen.getCell(nextAddr);
|
||||
ea2.fa = 0;
|
||||
ea2.ec = (byte) b2;
|
||||
ea2.ucs4 = uni;
|
||||
ea2.fg = currentFg;
|
||||
ea2.bg = currentBg;
|
||||
ea2.gr = (byte) currentGr;
|
||||
ea2.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea2.db = ExtendedAttribute.DB_RIGHT;
|
||||
ea2.ol = currentOl;
|
||||
ea2.tr = currentTr;
|
||||
|
||||
baddr = (baddr + 2) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
pos += 2;
|
||||
lastWasOrder = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Regular data byte (EBCDIC character)
|
||||
// Format control codes display as nulls/blanks per 3270 spec
|
||||
boolean isFCOrder = (b == FCORDER_NULL || b == FCORDER_FF ||
|
||||
@@ -688,14 +835,18 @@ public class DataStreamProcessor {
|
||||
|
||||
if (isFCOrder) {
|
||||
ea.ec = 0; // Display as null/blank
|
||||
ea.ucs4 = 0;
|
||||
} else {
|
||||
ea.ec = (byte) b;
|
||||
ea.ucs4 = (translator != null) ? translator.ebcdicToUnicode(b) : (char) b;
|
||||
}
|
||||
ea.fg = currentFg;
|
||||
ea.bg = currentBg;
|
||||
ea.gr = (byte) currentGr;
|
||||
ea.cs = currentCs;
|
||||
ea.db = ExtendedAttribute.DB_NONE;
|
||||
ea.ol = currentOl;
|
||||
ea.tr = currentTr;
|
||||
|
||||
baddr = (baddr + 1) % size;
|
||||
screen.setBufferAddress(baddr);
|
||||
@@ -796,7 +947,7 @@ public class DataStreamProcessor {
|
||||
// Buffer contents depending on Reply Mode
|
||||
if (mode == SF_SRM_XFIELD || mode == SF_SRM_CHAR) {
|
||||
// Extended Field or Character Mode
|
||||
byte curFg = 0, curBg = 0, curGr = 0, curCs = 0;
|
||||
byte curFg = 0, curBg = 0, curGr = 0, curCs = 0, curTr = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
ExtendedAttribute ea = screen.getCell(i);
|
||||
if (ea.isFieldAttribute()) {
|
||||
@@ -807,6 +958,7 @@ public class DataStreamProcessor {
|
||||
if (ea.gr != 0) count++;
|
||||
if (ea.cs != 0) count++;
|
||||
if (ea.ol != 0) count++;
|
||||
if (ea.tr != 0) count++;
|
||||
|
||||
outputWrite(ORDER_SFE);
|
||||
outputWrite(count);
|
||||
@@ -825,6 +977,7 @@ public class DataStreamProcessor {
|
||||
}
|
||||
if (ea.cs != 0) { outputWrite(XA_CHARSET); outputWrite(ea.cs & 0xFF); }
|
||||
if (ea.ol != 0) { outputWrite(XA_OUTLINING); outputWrite(ea.ol & 0xFF); }
|
||||
if (ea.tr != 0) { outputWrite(XA_TRANSPARENCY); outputWrite(ea.tr & 0xFF); }
|
||||
} else {
|
||||
if (mode == SF_SRM_CHAR) {
|
||||
// In character mode, output SA if character attributes differ
|
||||
@@ -850,6 +1003,10 @@ public class DataStreamProcessor {
|
||||
outputWrite(ORDER_SA); outputWrite(XA_CHARSET); outputWrite(ea.cs & 0xFF);
|
||||
curCs = ea.cs;
|
||||
}
|
||||
if (ea.tr != curTr) {
|
||||
outputWrite(ORDER_SA); outputWrite(XA_TRANSPARENCY); outputWrite(ea.tr & 0xFF);
|
||||
curTr = ea.tr;
|
||||
}
|
||||
}
|
||||
outputWrite(ea.ec & 0xFF);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ public class QueryReplyBuilder {
|
||||
QR_DDM, // 0x95 - Distributed Data Management (file transfer)
|
||||
QR_AUXDA, // 0x99 - Auxiliary Devices
|
||||
QR_IMP_PART, // 0xa6 - Implicit Partition Sizes
|
||||
QR_TRANSPARENCY, // 0xa8 - Background Transparency
|
||||
};
|
||||
|
||||
// Vector graphics query reply codes matching HOD QueryReply3270Constants.java QR_3270_WITHOUT_DCBS_SUMMARY_STRING
|
||||
@@ -218,6 +219,9 @@ public class QueryReplyBuilder {
|
||||
// Implicit Partition (0xA6)
|
||||
appendQueryReply(out, QR_IMP_PART, buildImplicitPartition(maxCols, maxRows));
|
||||
|
||||
// Background Transparency (0xA8)
|
||||
appendQueryReply(out, QR_TRANSPARENCY, STATIC_QR_TRANSPARENCY);
|
||||
|
||||
log.info("Built " + out.size() + " bytes of base query replies (graphicsMode=" + graphicsMode + ")");
|
||||
return out.toByteArray();
|
||||
}
|
||||
@@ -245,9 +249,9 @@ public class QueryReplyBuilder {
|
||||
appendQueryReply(out, QR_DDM, buildDdm(4096));
|
||||
appendQueryReply(out, QR_AUXDA, STATIC_QR_AUXDA);
|
||||
appendQueryReply(out, QR_IMP_PART, buildImplicitPartition(maxCols, maxRows));
|
||||
appendQueryReply(out, QR_TRANSPARENCY, STATIC_QR_TRANSPARENCY); // 0xA8
|
||||
|
||||
if (graphicsMode.isVectorGraphicsEnabled()) {
|
||||
appendQueryReply(out, QR_TRANSPARENCY, STATIC_QR_TRANSPARENCY); // 0xA8
|
||||
appendQueryReply(out, QR_SEGMENT, STATIC_QR_SEGMENT); // 0xB0
|
||||
appendQueryReply(out, QR_PROCEDURE, STATIC_QR_PROCEDURE); // 0xB1
|
||||
appendQueryReply(out, QR_LINETYPE, STATIC_QR_LINETYPE); // 0xB2
|
||||
@@ -317,11 +321,7 @@ public class QueryReplyBuilder {
|
||||
appendQueryReply(out, QR_IMP_PART, buildImplicitPartition(maxCols, maxRows));
|
||||
break;
|
||||
case QR_TRANSPARENCY: // 0xA8
|
||||
if (graphicsMode.isVectorGraphicsEnabled()) {
|
||||
appendQueryReply(out, QR_TRANSPARENCY, STATIC_QR_TRANSPARENCY);
|
||||
} else {
|
||||
appendQueryReply(out, QR_NULL, new byte[0]);
|
||||
}
|
||||
appendQueryReply(out, QR_TRANSPARENCY, STATIC_QR_TRANSPARENCY);
|
||||
break;
|
||||
case QR_SEGMENT: // 0xB0
|
||||
if (graphicsMode.isVectorGraphicsEnabled()) {
|
||||
@@ -390,10 +390,17 @@ public class QueryReplyBuilder {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
int[] codes = graphicsMode.isVectorGraphicsEnabled() ? SUPPORTED_QR_VECTOR : SUPPORTED_QR_BASE;
|
||||
boolean isDbcs = (screen != null && screen.getTranslator() != null && screen.getTranslator().isDBCS());
|
||||
boolean wroteDbcs = false;
|
||||
for (int code : codes) {
|
||||
if (isDbcs && !wroteDbcs && code == QR_DDM) {
|
||||
out.write(QR_OUTLINING);
|
||||
out.write(QR_DBCS_ASIA);
|
||||
wroteDbcs = true;
|
||||
}
|
||||
out.write(code);
|
||||
if (isDbcs && code == QR_OUTLINING) {
|
||||
if (isDbcs && code == QR_OUTLINING && !wroteDbcs) {
|
||||
out.write(QR_DBCS_ASIA); // 0x91
|
||||
wroteDbcs = true;
|
||||
}
|
||||
}
|
||||
return out.toByteArray();
|
||||
@@ -441,7 +448,7 @@ public class QueryReplyBuilder {
|
||||
|
||||
public int getCharWidth(int rows) {
|
||||
if (screen != null && screen.getTranslator() != null && screen.getTranslator().isDBCS()) {
|
||||
return 12;
|
||||
return 12; // 0x0C
|
||||
}
|
||||
return SW_3279_2; // 9
|
||||
}
|
||||
@@ -452,6 +459,9 @@ public class QueryReplyBuilder {
|
||||
}
|
||||
|
||||
public int getCharHeight(int rows) {
|
||||
if (screen != null && screen.getTranslator() != null && screen.getTranslator().isDBCS()) {
|
||||
return 24; // 0x18
|
||||
}
|
||||
return graphicsMode.isVectorGraphicsEnabled() ? 0x10 : SH_3279_2;
|
||||
}
|
||||
|
||||
@@ -477,9 +487,54 @@ public class QueryReplyBuilder {
|
||||
|
||||
int cgcsgid = 0x02B9;
|
||||
int cpgid = 0x0025;
|
||||
boolean isDbcs = false;
|
||||
if (screen != null && screen.getTranslator() != null) {
|
||||
cgcsgid = screen.getTranslator().getCgcsgid();
|
||||
cpgid = screen.getTranslator().getCpgid();
|
||||
isDbcs = screen.getTranslator().isDBCS();
|
||||
}
|
||||
|
||||
if (isDbcs) {
|
||||
int dbCgcsgid = screen.getTranslator().getDbCgcsgid();
|
||||
int dbCpgid = screen.getTranslator().getDbCpgid();
|
||||
byte secStart = screen.getTranslator().getDbcsSectionStart();
|
||||
byte secEnd = screen.getTranslator().getDbcsSectionEnd();
|
||||
|
||||
// 42-byte DBCS Character Sets QR payload (total 46 bytes structured field, matching HoD DS3270.java xxxqrcs)
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(42);
|
||||
out.write(0x8E); // flags: GE | DBCS / 2-byte charsets (0x8E)
|
||||
out.write(0x00); // flags 2
|
||||
out.write(charW); // SDW (12)
|
||||
out.write(charH); // SDH (24)
|
||||
out.write(0x00); out.write(0x00); out.write(0x00); out.write(0x00); // 4 reserved bytes
|
||||
out.write(0x0B); // DL = 11 bytes per descriptor
|
||||
|
||||
// Descriptor 1: Base SBCS (11 bytes)
|
||||
out.write(0x00); out.write(0x00); out.write(0x00);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write((cgcsgid >> 8) & 0xFF); out.write(cgcsgid & 0xFF);
|
||||
out.write((cpgid >> 8) & 0xFF); out.write(cpgid & 0xFF);
|
||||
|
||||
// Descriptor 2: DBCS Set 1 (11 bytes)
|
||||
out.write(0x01); // Set ID = 1
|
||||
out.write(0x00); // Flags
|
||||
out.write(0x80); // Local ID = 0x80 (DBCS)
|
||||
out.write((charW * 2) & 0xFF); // Double cell width (24)
|
||||
out.write(charH & 0xFF); // Cell height (24)
|
||||
out.write(secStart); // Section start (e.g. 0x41)
|
||||
out.write(secEnd); // Section end (e.g. 0xFE or 0x7F)
|
||||
out.write((dbCgcsgid >> 8) & 0xFF); out.write(dbCgcsgid & 0xFF);
|
||||
out.write((dbCpgid >> 8) & 0xFF); out.write(dbCpgid & 0xFF);
|
||||
|
||||
// Descriptor 3: APL / Text (11 bytes)
|
||||
out.write(0x01); out.write(0x00); out.write(0xF1);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write(0x00); out.write(0x00);
|
||||
out.write(0x03); out.write(0xC3); // CGCSGID 963
|
||||
out.write(0x01); out.write(0x36); // CPGID 310
|
||||
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
if (graphicsMode.isProgrammedSymbolsEnabled()) {
|
||||
@@ -531,6 +586,7 @@ public class QueryReplyBuilder {
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
public byte[] buildColor() {
|
||||
return STATIC_QR_COLOR.clone();
|
||||
}
|
||||
|
||||
@@ -5,13 +5,27 @@ package haus.nightmare.lib3270j.ecl;
|
||||
*/
|
||||
public interface ECLConstants {
|
||||
|
||||
// Presentation space logical planes
|
||||
int PLANE_TEXT = 1; // Unicode/EBCDIC characters
|
||||
int PLANE_COLOR = 2; // Color attributes
|
||||
int PLANE_HILITE = 3; // Extended highlighting
|
||||
int PLANE_EXTENDED = 4; // Extended character sets / outlining
|
||||
int PLANE_FIELD = 5; // Field attribute definition bytes
|
||||
int PLANE_DBCS = 6; // Double-byte character plane
|
||||
// Presentation space logical planes (Bitmask & ordinal definitions matching IBM Host On-Demand)
|
||||
int PLANE_TEXT = 1; // Unicode/EBCDIC characters
|
||||
int PLANE_COLOR = 2; // Color attributes
|
||||
int PLANE_HILITE = 3; // Extended highlighting
|
||||
int PLANE_EXTENDED = 4; // Extended character sets / outlining
|
||||
int PLANE_FIELD = 5; // Field attribute definition bytes
|
||||
int PLANE_DBCS = 6; // Double-byte character plane (lib3270j convention)
|
||||
int PLANE_GRID = 8; // Grid lines / outlining plane
|
||||
|
||||
// Canonical IBM Host On-Demand ECLConstants plane bitmasks
|
||||
int TEXT_PLANE = 1;
|
||||
int COLOR_PLANE = 2;
|
||||
int DBCS_PLANE = 4;
|
||||
int GRID_PLANE = 8;
|
||||
int FIELD_PLANE = 16;
|
||||
int EXFIELD_PLANE = 32;
|
||||
int NLS_PLANE = 64;
|
||||
int HOST_PLANE = 128;
|
||||
int RAWTEXT_PLANE = 256;
|
||||
int COLOR_ATTRIBUTES_PLANE = 512;
|
||||
int ALL_PLANES = 319;
|
||||
|
||||
// Color definitions (IBM 3279 standard 16-color palette)
|
||||
char COLOR_NEUTRAL_BLACK = 0;
|
||||
|
||||
@@ -295,6 +295,54 @@ public class ECLField {
|
||||
}
|
||||
public void Erase() { erase(); }
|
||||
|
||||
/**
|
||||
* Check whether this field contains any DBCS characters or SO/SI delimiters.
|
||||
*/
|
||||
public boolean isDBCS() {
|
||||
if (ps == null || length <= 0) return false;
|
||||
ScreenBuffer sb = ps.getScreenBuffer();
|
||||
if (sb == null) return false;
|
||||
int size = sb.getRows() * sb.getCols();
|
||||
if (size <= 0) return false;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int addr = (dataStart + i) % size;
|
||||
ExtendedAttribute ea = sb.getCell(addr);
|
||||
if (ea != null && (ea.db == ExtendedAttribute.DB_LEFT || ea.db == ExtendedAttribute.DB_RIGHT
|
||||
|| ea.db == ExtendedAttribute.DB_SO || ea.db == ExtendedAttribute.DB_SI)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean IsDBCS() { return isDBCS(); }
|
||||
|
||||
/**
|
||||
* Check whether this field contains only DBCS characters (excluding nulls / spaces).
|
||||
*/
|
||||
public boolean isDBCSOnly() {
|
||||
if (ps == null || length <= 0) return false;
|
||||
ScreenBuffer sb = ps.getScreenBuffer();
|
||||
if (sb == null) return false;
|
||||
int size = sb.getRows() * sb.getCols();
|
||||
if (size <= 0) return false;
|
||||
boolean hasDBCS = false;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int addr = (dataStart + i) % size;
|
||||
ExtendedAttribute ea = sb.getCell(addr);
|
||||
if (ea != null) {
|
||||
if (ea.db == ExtendedAttribute.DB_LEFT || ea.db == ExtendedAttribute.DB_RIGHT
|
||||
|| ea.db == ExtendedAttribute.DB_SO || ea.db == ExtendedAttribute.DB_SI) {
|
||||
hasDBCS = true;
|
||||
} else if (ea.ec != 0 && ea.ec != 0x40 && ea.ucs4 != 0 && ea.ucs4 != ' ') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasDBCS;
|
||||
}
|
||||
public boolean IsDBCSOnly() { return isDBCSOnly(); }
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -25,9 +25,22 @@ public class ECLFieldList extends Vector<ECLField> {
|
||||
refresh();
|
||||
}
|
||||
|
||||
public ECLFieldList(ECLPS ps) {
|
||||
this(ps, ps != null ? ps.getScreenBuffer() : null);
|
||||
}
|
||||
|
||||
public ECLField getField(int index) {
|
||||
return (index >= 0 && index < size()) ? get(index) : null;
|
||||
}
|
||||
|
||||
public ECLField GetField(int index) {
|
||||
return getField(index);
|
||||
}
|
||||
|
||||
public ECLPS getPS() { return ps; }
|
||||
public ScreenBuffer getScreenBuffer() { return screen; }
|
||||
|
||||
|
||||
/**
|
||||
* Refresh the field list by scanning the presentation space buffer.
|
||||
*/
|
||||
|
||||
@@ -264,10 +264,12 @@ public class ECLPS implements ECLConstants {
|
||||
case PLANE_TEXT:
|
||||
if (ea.isFieldAttribute()) {
|
||||
destBuffer[i] = ' ';
|
||||
} else if (ea.db == ExtendedAttribute.DB_SO || ea.db == ExtendedAttribute.DB_SI) {
|
||||
destBuffer[i] = ' ';
|
||||
} else if (ea.ucs4 != 0) {
|
||||
destBuffer[i] = (char) ea.ucs4;
|
||||
} else if (ea.ec != 0) {
|
||||
destBuffer[i] = translator.ebcdicToUnicode(ea.ec & 0xFF);
|
||||
destBuffer[i] = (translator != null) ? translator.ebcdicToUnicode(ea.ec & 0xFF) : (char) (ea.ec & 0xFF);
|
||||
} else {
|
||||
destBuffer[i] = ' ';
|
||||
}
|
||||
@@ -278,12 +280,43 @@ public class ECLPS implements ECLConstants {
|
||||
case PLANE_HILITE:
|
||||
destBuffer[i] = (char) (ea.gr & 0xFF);
|
||||
break;
|
||||
case PLANE_EXTENDED:
|
||||
destBuffer[i] = (char) (ea.cs & 0xFF);
|
||||
case DBCS_PLANE: // 4 (HoD DBCS_PLANE) or PLANE_EXTENDED for SBCS
|
||||
if (translator != null && translator.isDBCS()) {
|
||||
if (ea.db == ExtendedAttribute.DB_LEFT) {
|
||||
destBuffer[i] = (char) 0xC0; // DB_DBHIGH (first half of DBCS)
|
||||
} else if (ea.db == ExtendedAttribute.DB_RIGHT) {
|
||||
destBuffer[i] = (char) 0x80; // DB_DBCS (second half of DBCS)
|
||||
} else if (ea.db == ExtendedAttribute.DB_SO) {
|
||||
destBuffer[i] = (char) 0x20; // DB_SO
|
||||
} else if (ea.db == ExtendedAttribute.DB_SI) {
|
||||
destBuffer[i] = (char) 0x10; // DB_SI
|
||||
} else {
|
||||
destBuffer[i] = 0;
|
||||
}
|
||||
} else {
|
||||
destBuffer[i] = (char) (ea.cs & 0xFF);
|
||||
}
|
||||
break;
|
||||
case PLANE_FIELD:
|
||||
case FIELD_PLANE: // 16
|
||||
destBuffer[i] = ea.isFieldAttribute() ? (char) (ea.fa & 0xFF) : 0;
|
||||
break;
|
||||
case PLANE_DBCS: // 6
|
||||
if (ea.db == ExtendedAttribute.DB_LEFT) {
|
||||
destBuffer[i] = (char) 0xC0;
|
||||
} else if (ea.db == ExtendedAttribute.DB_RIGHT) {
|
||||
destBuffer[i] = (char) 0x80;
|
||||
} else if (ea.db == ExtendedAttribute.DB_SO) {
|
||||
destBuffer[i] = (char) 0x20;
|
||||
} else if (ea.db == ExtendedAttribute.DB_SI) {
|
||||
destBuffer[i] = (char) 0x10;
|
||||
} else {
|
||||
destBuffer[i] = 0;
|
||||
}
|
||||
break;
|
||||
case GRID_PLANE: // 8 (HoD GRID_PLANE / Outlining)
|
||||
destBuffer[i] = (char) (ea.ol & 0xFF);
|
||||
break;
|
||||
default:
|
||||
destBuffer[i] = ' ';
|
||||
break;
|
||||
@@ -292,6 +325,107 @@ public class ECLPS implements ECLConstants {
|
||||
return copyLen;
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCSChar(int pos) {
|
||||
if (screen == null) return false;
|
||||
int size = getSize();
|
||||
if (size <= 0) return false;
|
||||
pos = ((pos % size) + size) % size;
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
return ea != null && (ea.db == ExtendedAttribute.DB_LEFT || ea.db == ExtendedAttribute.DB_RIGHT);
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCSChar(int pos) {
|
||||
return IsDBCSChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCSChar(int row, int col) {
|
||||
if (screen == null) return false;
|
||||
return IsDBCSChar(screen.rowColToAddress(row, col));
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCSChar(int row, int col) {
|
||||
return IsDBCSChar(row, col);
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCS1stChar(int pos) {
|
||||
if (screen == null) return false;
|
||||
int size = getSize();
|
||||
if (size <= 0) return false;
|
||||
pos = ((pos % size) + size) % size;
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
return ea != null && ea.db == ExtendedAttribute.DB_LEFT;
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCS1stChar(int pos) {
|
||||
return IsDBCS1stChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCS1stChar(int row, int col) {
|
||||
if (screen == null) return false;
|
||||
return IsDBCS1stChar(screen.rowColToAddress(row, col));
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCS1stChar(int row, int col) {
|
||||
return IsDBCS1stChar(row, col);
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCS2ndChar(int pos) {
|
||||
if (screen == null) return false;
|
||||
int size = getSize();
|
||||
if (size <= 0) return false;
|
||||
pos = ((pos % size) + size) % size;
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
return ea != null && ea.db == ExtendedAttribute.DB_RIGHT;
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCS2ndChar(int pos) {
|
||||
return IsDBCS2ndChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean IsDBCS2ndChar(int row, int col) {
|
||||
if (screen == null) return false;
|
||||
return IsDBCS2ndChar(screen.rowColToAddress(row, col));
|
||||
}
|
||||
|
||||
public synchronized boolean isDBCS2ndChar(int row, int col) {
|
||||
return IsDBCS2ndChar(row, col);
|
||||
}
|
||||
|
||||
public synchronized boolean IsSOChar(int pos) {
|
||||
if (screen == null) return false;
|
||||
int size = getSize();
|
||||
if (size <= 0) return false;
|
||||
pos = ((pos % size) + size) % size;
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
return ea != null && (ea.db == ExtendedAttribute.DB_SO || (ea.ec & 0xFF) == 0x0E);
|
||||
}
|
||||
|
||||
public synchronized boolean isSOChar(int pos) {
|
||||
return IsSOChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean IsSIChar(int pos) {
|
||||
if (screen == null) return false;
|
||||
int size = getSize();
|
||||
if (size <= 0) return false;
|
||||
pos = ((pos % size) + size) % size;
|
||||
ExtendedAttribute ea = screen.getCell(pos);
|
||||
return ea != null && (ea.db == ExtendedAttribute.DB_SI || (ea.ec & 0xFF) == 0x0F);
|
||||
}
|
||||
|
||||
public synchronized boolean isSIChar(int pos) {
|
||||
return IsSIChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean IsSOSIChar(int pos) {
|
||||
return IsSOChar(pos) || IsSIChar(pos);
|
||||
}
|
||||
|
||||
public synchronized boolean isSOSIChar(int pos) {
|
||||
return IsSOSIChar(pos);
|
||||
}
|
||||
|
||||
|
||||
public synchronized int GetScreenRect(char[] cArray, int len, int sRow, int sCol, int eRow, int eCol, int plane) {
|
||||
if (cArray == null || len <= 0 || screen == null) return 0;
|
||||
int minR = Math.max(1, Math.min(sRow, eRow));
|
||||
|
||||
@@ -816,15 +816,14 @@ public class FTDft {
|
||||
|
||||
for (int i = 0; i < lineStr.length(); i++) {
|
||||
char ch = lineStr.charAt(i);
|
||||
int ebc = translator != null ? translator.unicodeToEbcdic(ch) : -1;
|
||||
boolean charIsDbcs = isDbcs && (ch > 0xFF || ebc > 0xFF);
|
||||
if (charIsDbcs) {
|
||||
int dbcsVal = (isDbcs && translator != null) ? translator.unicodeToDbcs(ch) : -1;
|
||||
if (dbcsVal != -1) {
|
||||
if (!inDbcsState && !noSo) {
|
||||
converted.write(0x0E); // Shift-Out
|
||||
inDbcsState = true;
|
||||
}
|
||||
converted.write((ebc >> 8) & 0xFF);
|
||||
converted.write(ebc & 0xFF);
|
||||
converted.write((dbcsVal >> 8) & 0xFF);
|
||||
converted.write(dbcsVal & 0xFF);
|
||||
} else {
|
||||
if (inDbcsState && !noSo) {
|
||||
converted.write(0x0F); // Shift-In
|
||||
|
||||
@@ -292,9 +292,10 @@ public class InputProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
// Translate character to EBCDIC (or APL Graphic Escape if in APL Keyboard Mode)
|
||||
// Translate character to EBCDIC (or APL Graphic Escape if in APL Keyboard Mode, or DBCS)
|
||||
boolean isAplChar = false;
|
||||
int ebc = -1;
|
||||
int dbcs = -1;
|
||||
if (aplKeyboardMode) {
|
||||
int aplCode = getAplCodeForChar(ch);
|
||||
if (aplCode >= 0) {
|
||||
@@ -303,10 +304,62 @@ public class InputProcessor {
|
||||
isAplChar = true;
|
||||
}
|
||||
}
|
||||
if (ebc < 0) {
|
||||
ebc = translator.unicodeToEbcdic(ch);
|
||||
if (ebc < 0 && translator != null && translator.isDBCS()) {
|
||||
dbcs = translator.unicodeToDbcs(ch);
|
||||
}
|
||||
if (ebc < 0 && dbcs < 0) {
|
||||
ebc = (translator != null) ? translator.unicodeToEbcdic(ch) : (int) ch;
|
||||
}
|
||||
if (ebc < 0 && dbcs < 0) return;
|
||||
|
||||
if (dbcs >= 0) {
|
||||
// DBCS character typing
|
||||
if (insertMode) {
|
||||
if (!screen.insertChar(baddr, ch)) {
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_OVERFLOW);
|
||||
}
|
||||
setKeyboardLocked(true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int nextPos = screen.incrementAddress(baddr);
|
||||
if (screen.isFormatted() && screen.getCell(nextPos).isFieldAttribute()) {
|
||||
// Cannot fit 2-cell DBCS at the last position of the field
|
||||
if (oia != null) {
|
||||
oia.setInputInhibited(ECLConstants.INHIBIT_OVERFLOW);
|
||||
}
|
||||
setKeyboardLocked(true);
|
||||
return;
|
||||
}
|
||||
int b1 = (dbcs >> 8) & 0xFF;
|
||||
int b2 = dbcs & 0xFF;
|
||||
ExtendedAttribute ea1 = screen.getCell(baddr);
|
||||
ea1.fa = 0;
|
||||
ea1.ec = (byte) b1;
|
||||
ea1.ucs4 = ch;
|
||||
ea1.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea1.db = ExtendedAttribute.DB_LEFT;
|
||||
|
||||
ExtendedAttribute ea2 = screen.getCell(nextPos);
|
||||
ea2.fa = 0;
|
||||
ea2.ec = (byte) b2;
|
||||
ea2.ucs4 = ch;
|
||||
ea2.cs = ExtendedAttribute.CS_DBCS;
|
||||
ea2.db = ExtendedAttribute.DB_RIGHT;
|
||||
|
||||
if (screen.isFormatted()) {
|
||||
int faAddr = screen.findFieldAttribute(baddr);
|
||||
if (faAddr >= 0) {
|
||||
screen.getCell(faAddr).fa = (byte) (screen.getCell(faAddr).fa | FA_MODIFY);
|
||||
}
|
||||
}
|
||||
screen.setCursorAddress(screen.incrementAddress(nextPos));
|
||||
}
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
return;
|
||||
}
|
||||
if (ebc < 0) return;
|
||||
|
||||
if (insertMode) {
|
||||
// Insert mode: shift characters right from cursor to end of field
|
||||
@@ -1476,38 +1529,12 @@ public class InputProcessor {
|
||||
}
|
||||
|
||||
public void deleteChar() {
|
||||
if (!screen.isFormatted()) return;
|
||||
int addr = screen.getCursorAddress();
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
if (size <= 0) return;
|
||||
addr = ((addr % size) + size) % size;
|
||||
|
||||
// Cannot delete a field attribute
|
||||
if (screen.getCell(addr).isFieldAttribute()) return;
|
||||
|
||||
byte faVal = screen.getFieldAttributeAt(addr);
|
||||
if (faIsProtected(faVal & 0xFF)) return;
|
||||
|
||||
// Shift characters left within the field
|
||||
int shiftAddr = addr;
|
||||
int count = 0;
|
||||
while (count < size) {
|
||||
int next = screen.incrementAddress(shiftAddr);
|
||||
if (screen.getCell(next).isFieldAttribute()) {
|
||||
screen.getCell(shiftAddr).ec = 0;
|
||||
screen.getCell(shiftAddr).ucs4 = 0;
|
||||
break;
|
||||
}
|
||||
screen.getCell(shiftAddr).ec = screen.getCell(next).ec;
|
||||
screen.getCell(shiftAddr).ucs4 = screen.getCell(next).ucs4;
|
||||
shiftAddr = next;
|
||||
count++;
|
||||
}
|
||||
|
||||
int faAddr = screen.findFieldAttribute(addr);
|
||||
if (faAddr >= 0) {
|
||||
screen.getCell(faAddr).fa = (byte) (screen.getCell(faAddr).fa | FA_MODIFY);
|
||||
if (screen.isFormatted()) {
|
||||
byte faVal = screen.getFieldAttributeAt(addr);
|
||||
if (faIsProtected(faVal & 0xFF)) return;
|
||||
}
|
||||
screen.deleteChar(addr);
|
||||
screen.markAllChanged();
|
||||
screen.updateDisplaySnapshot();
|
||||
}
|
||||
@@ -1525,6 +1552,9 @@ public class InputProcessor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (screen.getCell(prev).db == ExtendedAttribute.DB_RIGHT) {
|
||||
prev = screen.decrementAddress(prev);
|
||||
}
|
||||
screen.setCursorAddress(prev);
|
||||
deleteChar();
|
||||
}
|
||||
|
||||
@@ -97,6 +97,11 @@ public class ExtendedAttribute {
|
||||
/** Validation attribute. */
|
||||
public byte vl;
|
||||
|
||||
// Transparency attribute values (0x46 / XA_TRANSPARENCY)
|
||||
public static final byte TR_DEFAULT = 0x00;
|
||||
public static final byte TR_OR = (byte) 0xF0;
|
||||
public static final byte TR_OPAQUE = (byte) 0xFF;
|
||||
|
||||
/** Transparency attribute. */
|
||||
public byte tr;
|
||||
|
||||
|
||||
@@ -727,6 +727,14 @@ public class ScreenBuffer {
|
||||
for (int i = 0; i < size; i++) {
|
||||
ExtendedAttribute ea = buffer[i];
|
||||
if (!ea.isFieldAttribute()) {
|
||||
if (ea.db == ExtendedAttribute.DB_LEFT || ea.db == ExtendedAttribute.DB_RIGHT) {
|
||||
// Preserve decoded DBCS character
|
||||
continue;
|
||||
}
|
||||
if (ea.db == ExtendedAttribute.DB_SO || ea.db == ExtendedAttribute.DB_SI) {
|
||||
ea.ucs4 = ' ';
|
||||
continue;
|
||||
}
|
||||
if (ea.ec == 0) {
|
||||
ea.ucs4 = 0;
|
||||
} else if (ea.cs == 1 || ea.cs == 0x04) { // CS_APL or CS_GE
|
||||
@@ -736,6 +744,9 @@ public class ScreenBuffer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (translator != null && translator.isDBCS()) {
|
||||
processSOSI();
|
||||
}
|
||||
}
|
||||
|
||||
private char getAplGraphic(int ec) {
|
||||
@@ -1124,7 +1135,7 @@ public class ScreenBuffer {
|
||||
int count = 0;
|
||||
while (count < size) {
|
||||
int next = incrementAddress(shiftAddr);
|
||||
if (getCell(next).isFieldAttribute()) {
|
||||
if (getCell(next).isFieldAttribute() || count == size - 1) {
|
||||
getCell(shiftAddr).clear();
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user