com.ibm.as400.access.ConvTableMixedMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400 Show documentation
Show all versions of jt400 Show documentation
The Open Source version of the IBM Toolbox for Java
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: ConvTableMixedMap.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2004 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.UnsupportedEncodingException;
/** This is the parent class for all ConvTableXXX classes that represent mixed-byte ccsids.
*
*/
public abstract class ConvTableMixedMap extends ConvTable
{
private static final String copyright = "Copyright (C) 1997-2004 International Business Machines Corporation and others.";
public ConvTableSingleMap sbTable_ = null; // The single-byte portion of this mixed-byte table.
public ConvTableDoubleMap dbTable_ = null; // The double-byte portion of this mixed-byte table.
static final byte shiftOut_ = 0x0E; // Byte used to shift-out of single byte mode.
static final byte shiftIn_ = 0x0F; // Byte used to shift-in to single byte mode.
static final byte ebcdicSpace_ = 0x40;
// Constructor.
ConvTableMixedMap(int ccsid, int sbCcsid, int dbCcsid) throws UnsupportedEncodingException
{
super(ccsid);
sbTable_ = (ConvTableSingleMap)ConvTable.getTable(sbCcsid, null);
dbTable_ = (ConvTableDoubleMap)ConvTable.getTable(dbCcsid, null);
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Successfully loaded mixed-byte map for ccsid: " + ccsid_);
}
// Perform an OS/400 CCSID to Unicode conversion.
final String byteArrayToString(byte[] buf, int offset, int length, BidiConversionProperties properties)
{
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Converting byte array to string for ccsid: " + ccsid_, buf, offset, length);
char[] dest = new char[length];
boolean inSBMode = true;
int destPos = 0;
for (int srcPos = offset; srcPos < offset + length; ++srcPos)
{
byte curByte = buf[srcPos];
if (inSBMode)
{
// In single byte mode.
if (curByte == shiftOut_)
{
// Shift out character. Switch to double byte mode.
inSBMode = false;
}
else
{
// Normal character. Perform single-byte lookup.
dest[destPos++] = sbTable_.toUnicode_[(0x00FF & curByte)];
}
}
else
{
// In double byte mode.
if (curByte == shiftIn_)
{
// Shift in character. Switch to single byte mode.
inSBMode = true;
}
else
{
try
{
if ((srcPos+1) < offset + length) {
// Normal character. Perform double-byte lookup.
int unicodeLength = dbTable_.toUnicode(dest, destPos, ((0x00FF & curByte) << 8) + (0x00FF & buf[++srcPos])); /*@KDC*/
destPos += unicodeLength;
// dest[destPos++] = dbTable_.toUnicode_[((0x00FF & curByte) << 8) + (0x00FF & buf[++srcPos])];
} else {
if (CharConverter.isFaultTolerantConversion()) {
// Do not add the replacement character to behave as before (when ArrayIndexOutOfBoundsException used to be caught).
} else {
// Only half a character at the end -- add substitution character
dest[destPos++] = '\ufffd';
}
}
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
// Swallow this if we are doing fault-tolerant conversion.
if(!CharConverter.isFaultTolerantConversion())
{
throw aioobe;
}
// No need to decrement because increment in dest[destPost++] not longer occurs
// --destPos;
}
}
}
}
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Destination string for ccsid: " + ccsid_ + ": 0," + destPos, ConvTable.dumpCharArray(dest));
return String.copyValueOf(dest, 0, destPos);
}
// Perform a Unicode to OS/400 CCSID conversion.
final byte[] stringToByteArray(String source, BidiConversionProperties properties)
{
return charArrayToByteArray(source.toCharArray(),properties); //@AI5C
/*char[] src = source.toCharArray();
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Converting string to byte array for ccsid: " + ccsid_, ConvTable.dumpCharArray(src));
// Max possible length for mixed-byte byte array.
byte[] dest = new byte[(src.length * 5 + 3) / 2];
boolean inSBMode = true;
byte sbLookup = 0x00;
char dbLookup = '\u0000';
int[] increment = new int[1];
int destPos = 0;
for (int srcPos = 0; srcPos < src.length; ++srcPos)
{
char curChar = src[srcPos];
// There is no concept of mode context when converting a String to a byte array.
// The table we look at first is only based on the current character in the String.
if (((curChar & 0xFF00) == 0x0000) || ( curChar == euro_ ) || ( curChar == 0x203e && (ccsid_ == 935 || ccsid_ == 1388)))
{
// Use single-byte table first.
sbLookup = sbTable_.fromUnicode_[curChar];
if (sbLookup == sbSubChar_ && curChar != sbSubUnic_)
{
// Character wasn't in single-byte table. Check double-byte table next.
dbLookup = dbTable_.fromUnicode(src,srcPos,increment);
if (increment[0] == 2) {
// move an extra byte in the source @KDA
srcPos++;
}
// dbLookup = dbTable_.fromUnicode_[curChar]; @KDC
if (dbLookup == dbSubChar_)
{
// Character wasn't in the double-byte table either, so use single-byte substitution character.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbSubChar_;
}
else
{
// Character found in double-byte table.
if (inSBMode)
{
inSBMode = false;
dest[destPos++] = shiftOut_;
}
dest[destPos++] = (byte)((0xFFFF & dbLookup) >>> 8);
dest[destPos++] = (byte)(0x00FF & dbLookup);
}
}
else
{
// Character found in single-byte table.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbLookup;
}
}
else
{
// Use double-byte table first.
// dbLookup = dbTable_.fromUnicode_[curChar];
dbLookup = dbTable_.fromUnicode(src,srcPos,increment);
if (increment[0] >= 2) {
// move an extra byte in the source @KDA
srcPos = srcPos + increment[0] -1;
}
if (dbLookup == dbSubChar_ && curChar != dbSubUnic_)
{
// Character wasn't in double-byte table. Check single-byte table next.
sbLookup = sbTable_.fromUnicode_[curChar];
if (sbLookup == sbSubChar_)
{
// Use the subsitition character value for the current mode @V5A
if (inSBMode) {
dest[destPos++] = sbSubChar_;
} else {
dest[destPos++] = (byte) ((0xFFFF & dbSubChar_) >>> 8);
dest[destPos++] = (byte) (0x00FF & dbSubChar_);
}
}
else
{
// Character found in single-byte table.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbLookup;
}
}
else
{
// Character found in double-byte table.
if (inSBMode)
{
inSBMode = false;
dest[destPos++] = shiftOut_;
}
dest[destPos++] = (byte)((0xFFFF & dbLookup) >>> 8);
dest[destPos++] = (byte)(0x00FF & dbLookup);
}
}
}
// Write final shift in, just in case.
if (!inSBMode)
{
dest[destPos++] = shiftIn_;
}
byte[] ret = new byte[destPos];
System.arraycopy(dest, 0, ret, 0, destPos);
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Destination byte array for ccsid: " + ccsid_, ret);
return ret;*/
}
//@AI5A
// Perform an OS/400 CCSID to Unicode conversion.
final char[] byteArrayToCharArray(byte[] buf, int offset, int length, BidiConversionProperties properties)
{
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Converting byte array to string for ccsid: " + ccsid_, buf, offset, length);
char[] dest = new char[length];
boolean inSBMode = true;
int destPos = 0;
for (int srcPos = offset; srcPos < offset + length; ++srcPos)
{
byte curByte = buf[srcPos];
if (inSBMode)
{
// In single byte mode.
if (curByte == shiftOut_)
{
// Shift out character. Switch to double byte mode.
inSBMode = false;
}
else
{
// Normal character. Perform single-byte lookup.
dest[destPos++] = sbTable_.toUnicode_[(0x00FF & curByte)];
}
}
else
{
// In double byte mode.
if (curByte == shiftIn_)
{
// Shift in character. Switch to single byte mode.
inSBMode = true;
}
else
{
try
{
if ((srcPos+1) < offset + length) {
// Normal character. Perform double-byte lookup.
int unicodeLength = dbTable_.toUnicode(dest, destPos, ((0x00FF & curByte) << 8) + (0x00FF & buf[++srcPos])); /*@KDC*/
destPos += unicodeLength;
// dest[destPos++] = dbTable_.toUnicode_[((0x00FF & curByte) << 8) + (0x00FF & buf[++srcPos])];
} else {
if (CharConverter.isFaultTolerantConversion()) {
// Do not add the replacement character to behave as before (when ArrayIndexOutOfBoundsException used to be caught).
} else {
// Only half a character at the end -- add substitution character
dest[destPos++] = '\ufffd';
}
}
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
// Swallow this if we are doing fault-tolerant conversion.
if(!CharConverter.isFaultTolerantConversion())
{
throw aioobe;
}
// No need to decrement because increment in dest[destPost++] not longer occurs
// --destPos;
}
}
}
}
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Destination string for ccsid: " + ccsid_ + ": 0," + destPos, ConvTable.dumpCharArray(dest));
char[] destChar = new char[destPos];
System.arraycopy(dest, 0, destChar,0,destPos);
return destChar;
}
// Perform a Unicode to OS/400 CCSID conversion.
final byte[] charArrayToByteArray(char[] src, BidiConversionProperties properties)
{
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Converting string to byte array for ccsid: " + ccsid_, ConvTable.dumpCharArray(src));
// Max possible length for mixed-byte byte array.
byte[] dest = new byte[(src.length * 5 + 3) / 2];
boolean inSBMode = true;
byte sbLookup = 0x00;
char dbLookup = '\u0000';
int[] increment = new int[1]; /*@KDA*/
int destPos = 0; /*@KDA*/
for (int srcPos = 0; srcPos < src.length; ++srcPos)
{
char curChar = src[srcPos];
// There is no concept of mode context when converting a String to a byte array.
// The table we look at first is only based on the current character in the String.
if (((curChar & 0xFF00) == 0x0000) || ( curChar == euro_ ) || ( curChar == 0x203e && (ccsid_ == 935 || ccsid_ == 1388)))
{
// Use single-byte table first.
sbLookup = sbTable_.fromUnicode_[curChar];
if (sbLookup == sbSubChar_ && curChar != sbSubUnic_)
{
// Character wasn't in single-byte table. Check double-byte table next.
dbLookup = dbTable_.fromUnicode(src,srcPos,increment);
if (increment[0] == 2) {
// move an extra byte in the source @KDA
srcPos++;
}
// dbLookup = dbTable_.fromUnicode_[curChar]; @KDC
if (dbLookup == dbSubChar_)
{
// Character wasn't in the double-byte table either, so use single-byte substitution character.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbSubChar_;
}
else
{
// Character found in double-byte table.
if (inSBMode)
{
inSBMode = false;
dest[destPos++] = shiftOut_;
}
dest[destPos++] = (byte)((0xFFFF & dbLookup) >>> 8);
dest[destPos++] = (byte)(0x00FF & dbLookup);
}
}
else
{
// Character found in single-byte table.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbLookup;
}
}
else
{
// Use double-byte table first.
// dbLookup = dbTable_.fromUnicode_[curChar];
dbLookup = dbTable_.fromUnicode(src,srcPos,increment);
if (increment[0] >= 2) {
// move an extra byte in the source @KDA
srcPos = srcPos + increment[0] -1;
}
if (dbLookup == dbSubChar_ && curChar != dbSubUnic_)
{
// Character wasn't in double-byte table. Check single-byte table next.
sbLookup = sbTable_.fromUnicode_[curChar];
if (sbLookup == sbSubChar_)
{
// Use the subsitition character value for the current mode @V5A
if (inSBMode) {
dest[destPos++] = sbSubChar_;
} else {
dest[destPos++] = (byte) ((0xFFFF & dbSubChar_) >>> 8);
dest[destPos++] = (byte) (0x00FF & dbSubChar_);
}
}
else
{
// Character found in single-byte table.
if (!inSBMode)
{
inSBMode = true;
dest[destPos++] = shiftIn_;
}
dest[destPos++] = sbLookup;
}
}
else
{
// Character found in double-byte table.
if (inSBMode)
{
inSBMode = false;
dest[destPos++] = shiftOut_;
}
dest[destPos++] = (byte)((0xFFFF & dbLookup) >>> 8);
dest[destPos++] = (byte)(0x00FF & dbLookup);
}
}
}
// Write final shift in, just in case.
if (!inSBMode)
{
dest[destPos++] = shiftIn_;
}
byte[] ret = new byte[destPos];
System.arraycopy(dest, 0, ret, 0, destPos);
if (Trace.traceConversion_) Trace.log(Trace.CONVERSION, "Destination byte array for ccsid: " + ccsid_, ret);
return ret;
}
// Scan the data. If valid return length, otherwise fixup and return the changed length,
// padding with spaces as needed.
// @X4A
public int validateData( byte[] buf, int offset, int length) {
int endOffset = offset+length;
int doubleByteStart = -1;
boolean doubleByte = false;
for (int i = offset; i < endOffset; i++) {
// Not in double byte
if (doubleByteStart == -1 ) {
if (buf[i] == shiftOut_) {
doubleByteStart = i+1;
}
} else {
if (buf[i] == shiftIn_) {
doubleByteStart = -1;
} else {
i++; // Skip over an extra byte
}
}
}
// If there are double bytes then we need to fix up.
if (doubleByteStart >= 0) {
// Easy case, there is just a half left, replace it with shiftIn
if (((0xFFFFFFFFl &(endOffset - doubleByteStart)) % 2) == 1) {
// Check to see if we would put a ShiftIn by a shiftOut_
if (buf[endOffset-2 ] == shiftOut_) {
length = length - 2;
buf[endOffset-2] = ebcdicSpace_;
buf[endOffset-1] = ebcdicSpace_;
} else {
buf[endOffset -1 ] = shiftIn_;
}
} else {
// Check to see if ended with shiftOut
if (doubleByteStart == endOffset) {
// Just get rid of the shiftOut and reduce the size
buf[endOffset -1 ] = ebcdicSpace_;
length --;
} else {
// Check to see if we would put a ShiftIn by a shiftOut_
if (buf[endOffset-3] == shiftOut_) {
length = length - 3;
buf[endOffset-3] = ebcdicSpace_;
buf[endOffset-2] = ebcdicSpace_;
buf[endOffset-1] = ebcdicSpace_;
} else {
// This case there is a two byte character at the end.
// Add the shiftin.
buf[endOffset-2]= shiftIn_;
buf[endOffset-1]= ebcdicSpace_;
length --;
}
}
}
}
return length;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy