All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.as400.access.ConvTableMixedMap Maven / Gradle / Ivy

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