jtopenlite.com.ibm.jtopenlite.Conv Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400-jdk9 Show documentation
Show all versions of jt400-jdk9 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpenLite
//
// Filename: Conv.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) 2011-2012 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.jtopenlite;
import java.io.*;
import java.util.*;
import java.math.*;
import com.ibm.jtopenlite.ccsidConversion.CcsidConversion;
/**
* Utility class for converting data from one format to another.
**/
public final class Conv
{
private static Hashtable localeNlvMap_;
private static final char[] NUM = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
private static final byte[] CHAR_HIGH = new byte[10];
private static final byte[] CHAR_LOW = new byte[10];
static
{
for (int i=0; i<=9; ++i)
{
int val = i;
CHAR_HIGH[i] = (byte)(val << 4);
CHAR_LOW[i] = (byte)val;
}
}
// The array offset is the Unicode character value, the array value is the EBCDIC 37 value.
// e.g. CONV_TO_37['0'] == 0xF0 and CONV_TO_37[' '] == 0x40
private static final byte[] CONV_TO_37 = new byte[65536];
private static final byte[] INIT_TO_37 = new byte[]
{
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
(byte)0xF0, (byte)0xF1, (byte)0xF2, (byte)0xF3, (byte)0xF4, (byte)0xF5, (byte)0xF6, (byte)0xF7, (byte)0xF8, (byte)0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, (byte)0xC1, (byte)0xC2, (byte)0xC3, (byte)0xC4, (byte)0xC5, (byte)0xC6, (byte)0xC7, (byte)0xC8, (byte)0xC9, (byte)0xD1, (byte)0xD2, (byte)0xD3, (byte)0xD4, (byte)0xD5, (byte)0xD6,
(byte)0xD7, (byte)0xD8, (byte)0xD9, (byte)0xE2, (byte)0xE3, (byte)0xE4, (byte)0xE5, (byte)0xE6, (byte)0xE7, (byte)0xE8, (byte)0xE9, (byte)0xBA, (byte)0xE0, (byte)0xBB, (byte)0xB0, 0x6D,
0x79, (byte)0x81, (byte)0x82, (byte)0x83, (byte)0x84, (byte)0x85, (byte)0x86, (byte)0x87, (byte)0x88, (byte)0x89, (byte)0x91, (byte)0x92, (byte)0x93, (byte)0x94, (byte)0x95, (byte)0x96,
(byte)0x97, (byte)0x98, (byte)0x99, (byte)0xA2, (byte)0xA3, (byte)0xA4, (byte)0xA5, (byte)0xA6, (byte)0xA7, (byte)0xA8, (byte)0xA9, (byte)0xC0, 0x4F, (byte)0xD0, (byte)0xA1, 0x07,
0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B,
0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, (byte)0xFF,
0x41, (byte)0xAA, 0x4A, (byte)0xB1, (byte)0x9F, (byte)0xB2, 0x6A, (byte)0xB5, (byte)0xBD, (byte)0xB4, (byte)0x9A, (byte)0x8A, 0x5F, (byte)0xCA, (byte)0xAF, (byte)0xBC,
(byte)0x90, (byte)0x8F, (byte)0xEA, (byte)0xFA, (byte)0xBE, (byte)0xA0, (byte)0xB6, (byte)0xB3, (byte)0x9D, (byte)0xDA, (byte)0x9B, (byte)0x8B, (byte)0xB7, (byte)0xB8, (byte)0xB9, (byte)0xAB,
0x64, 0x65, 0x62, 0x66, 0x63, 0x67, (byte)0x9E, 0x68, 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77,
(byte)0xAC, 0x69, (byte)0xED, (byte)0xEE, (byte)0xEB, (byte)0xEF, (byte)0xEC, (byte)0xBF, (byte)0x80, (byte)0xFD, (byte)0xFE, (byte)0xFB, (byte)0xFC, (byte)0xAD, (byte)0xAE, 0x59,
0x44, 0x45, 0x42, 0x46, 0x43, 0x47, (byte)0x9C, 0x48, 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57,
(byte)0x8C, 0x49, (byte)0xCD, (byte)0xCE, (byte)0xCB, (byte)0xCF, (byte)0xCC, (byte)0xE1, 0x70, (byte)0xDD, (byte)0xDE, (byte)0xDB, (byte)0xDC, (byte)0x8D, (byte)0x8E, (byte)0xDF
};
// The array offset is the EBCDIC 37 character value, the array value is the Unicode value.
// e.g. CONV_FROM_37[0xF0] == '0' and CONV_FROM_37[0x40] == ' '
private static final char[] CONV_FROM_37 = new char[]
{
0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087, 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F,
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A,
0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C,
0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC,
0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F,
0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022,
0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4,
0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE,
0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5,
0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF,
0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F
};
private static final String[] CACHE_FROM_37 = new String[256];
private static final boolean cacheFrom37Init_;
static
{
System.arraycopy(INIT_TO_37, 0, CONV_TO_37, 0, INIT_TO_37.length);
for (int i=INIT_TO_37.length; i=offset; --i)
{
int low = data[i] & 0x000F;
int high = (data[i] >> 4) & 0x000F;
buffer[--count] = NUM[low];
buffer[--count] = NUM[high];
}
return new String(buffer, 0, numChars);
}
/**
* Converts the specified hexadecimal String into its constituent byte values.
**/
public static final byte[] hexStringToBytes(final String value)
{
int len = value.length();
/* this comparison works with negative numbers */
if (len % 2 != 0) ++len;
final byte[] data = new byte[len>>1];
hexStringToBytes(value, data, 0);
return data;
}
/**
* Converts the specified hexadecimal String into its constituent byte values.
**/
public static final int hexStringToBytes(final String value, final byte[] data, final int offset)
{
final int len = value.length();
final int odd = len % 2;
if (odd == 1)
{
data[offset] = 0;
}
for (int i=0; i= '0' && c <= '9')
{
val = c - '0';
}
else if (c >= 'A' && c <= 'F')
{
val = c - 'A' + 10;
}
else if (c >= 'a' && c <= 'f')
{
val = c - 'a' + 10;
}
final int arrOff = offset + ((i+odd)>>1);
data[arrOff] = i % 2 == odd ? (byte)(val << 4) : (byte)(data[arrOff] | val);
}
final int num = len >> 1;
return odd == 0 ? num : num+1;
}
/**
* Converts the specified String into CCSID 37 bytes.
**/
public static final byte[] stringToEBCDICByteArray37(final String s)
{
final byte[] b = new byte[s.length()];
stringToEBCDICByteArray37(s, b, 0);
return b;
}
/**
* Converts the specified String into CCSID 37 bytes.
**/
public static final int stringToEBCDICByteArray37(final String s, final byte[] data, final int offset)
{
return stringToEBCDICByteArray37(s, s.length(), data, offset);
}
public static final int stringToEBCDICByteArray37(final String s, int length, final byte[] data, final int offset)
{
int sLength = s.length();
if (sLength < length) {
length = sLength;
}
final int stop = offset+length;
for (int i=offset; i sLength) length = sLength;
final int ccsidToUse = ccsid & 0x00FFFF; // So we don't overflow our encodings_ table.
if (ccsidToUse == 37) return stringToEBCDICByteArray37(s, length, data, offset);
String encoding = encodings_[ccsidToUse];
if (encoding != null)
{
try {
// BOOOO!
byte[] b = s.substring(0,length).getBytes(encoding);
System.arraycopy(b, 0, data, offset, b.length);
return b.length;
} catch (UnsupportedEncodingException ex) {
encodings_[ccsidToUse] = null;
}
}
return CcsidConversion.stringToEBCDICByteArray(s, length, data, offset, ccsidToUse);
}
/**
* Converts the specified String into Unicode bytes.
* returns the number of bytes.
**/
public static final byte[] stringToUnicodeByteArray(final String s)
{
final byte[] b = new byte[s.length()*2];
stringToUnicodeByteArray(s, b, 0);
return b;
}
/**
* Converts the specified String into Unicode bytes.
**/
public static final int stringToUnicodeByteArray(final String s, final byte[] data, final int offset)
{
return stringToUnicodeByteArray(s, s.length(), data, offset);
}
public static final int stringToUnicodeByteArray(final String s, int length, final byte[] data, final int offset)
{
for (int i=0; i> 8);
byte low = (byte)c;
data[offset+(i*2)] = high;
data[offset+(i*2)+1] = low;
}
return length*2;
}
/* Version that pads with spaces */
public static void stringToUnicodeByteArray(String s, byte[] data, int offset, int byteLength) {
int sLength = s.length();
for (int i=0; i> 8);
byte low = (byte)c;
data[offset+(i*2)] = high;
data[offset+(i*2)+1] = low;
}
}
public static final int stringToUtf8ByteArray(final String s, int length, final byte[] data, final int offset)
{
int sLength = s.length();
if (length > sLength) length = sLength;
// BOOOO!
byte[] b ;
try {
b = s.substring(0,length).getBytes("UTF-8");
System.arraycopy(b, 0, data, offset, b.length);
return b.length;
} catch (UnsupportedEncodingException uee) {
// should never happen
return 0;
}
}
/**
* Converts the specified String into Unicode bytes, padding the byte array with Unicode
* spaces (0x0020) up to length bytes.
**/
public static final void stringToBlankPadUnicodeByteArray(final String s,
final byte[] data, final int offset, final int length)
{
int counter = 0;
if (s != null)
{
for (int i=0; i> 8);
byte low = (byte)s.charAt(i);
data[offset+counter] = high;
++counter;
data[offset+counter] = low;
++counter;
}
}
while ((counter+2) <= length)
{
data[offset+counter] = 0x00;
++counter;
data[offset+counter] = 0x20;
++counter;
}
}
/**
* Converts the specified Unicode bytes into a String.
* The length is in bytes, and should be twice the length of the returned String.
**/
public static final String unicodeByteArrayToString(final byte[] data, final int offset, final int length)
{
char[] buf = new char[length];
return unicodeByteArrayToString(data, offset, length, buf);
}
/**
* Converts the specified Unicode bytes into a String.
* The length is in bytes, and should be twice the length of the returned String.
**/
public static final String unicodeByteArrayToString(final byte[] data, final int offset, final int length, final char[] buffer)
{
final int numChars = length/2;
int count = numChars;
for (int i=offset+length-1; i>=offset; i-=2)
{
int low = data[i] & 0x00FF;
int high = data[i-1] & 0x00FF;
char c = (char)((high << 8) | low);
buffer[--count] = c;
}
return new String(buffer, 0, numChars);
}
/**
* Converts the specified String into CCSID 37 bytes, padding the byte array with EBCDIC spaces (0x40) up to length bytes.
**/
public static final void stringToBlankPadEBCDICByteArray(final String s, final byte[] data, final int offset, final int length)
{
for (int i=0; ilength bytes.
* @exception UnsupportedEncodingException Thrown if conversion to or from the specified CCSID is not supported.
**/
public static final void stringToBlankPadEBCDICByteArray(final String s, final byte[] data, final int offset, final int length, final int ccsid) throws UnsupportedEncodingException
{
final int ccsidToUse = ccsid & 0x00FFFF; // So we don't overflow our encodings_ table.
if (ccsidToUse == 37)
{
stringToBlankPadEBCDICByteArray(s, data, offset, length);
}
else
{
String encoding = encodings_[ccsidToUse];
if (encoding != null)
{
// BOOOO!
byte[] b = s.getBytes(encoding);
int len = b.length;
int total = len < length ? len : length;
System.arraycopy(b, 0, data, offset, total);
int rem = length-len;
if (rem > 0)
{
final byte[] blank = " ".getBytes(encoding);
while (rem > 0)
{
System.arraycopy(blank, 0, data, offset+total, blank.length);
total += blank.length;
rem = rem - blank.length;
}
}
}
else
{
throw new UnsupportedEncodingException("CCSID "+ccsidToUse);
}
}
}
/**
* Converts the specified CCSID 37 byte into a Unicode char without creating any intermediate objects.
**/
public static final char ebcdicByteToChar(final byte b)
{
return CONV_FROM_37[b & 0x00FF];
}
/**
* Converts the specified CCSID 37 bytes into a String.
* Note: You might as well just use new String(data,"Cp037") to avoid the extra char array this method needs to create.
* Note: You cannot use new String(data,"Cp037" because this is not supported on all JVMS
**/
public static final String ebcdicByteArrayToString(final byte[] data, final int offset, final int length)
{
if (length == 1 && cacheFrom37Init_) return CACHE_FROM_37[data[offset] & 0x00FF];
return ebcdicByteArrayToString(data, offset, length, new char[length]);
}
public static final String ebcdicByteArrayToString(final byte[] data, final char[] buffer) {
int offset = 0;
int length = data.length;
return ebcdicByteArrayToString(data, offset, length, buffer);
}
// @csmith: Perf testing:
// This uses the same amount of memory as new String(data, "Cp037")
// but is about 2x faster on IBM 1.5 Windows 32-bit and about 3x faster on Sun 1.4 Windows 32-bit.
/**
* Converts the specified CCSID 37 bytes into a String.
**/
public static final String ebcdicByteArrayToString(final byte[] data, final int offset, final int length, final char[] buffer)
{
if (length == 1 && cacheFrom37Init_) return CACHE_FROM_37[data[offset] & 0x00FF];
int counter = length;
for (int i=offset+length-1; i>=offset; --i)
{
buffer[--counter] = CONV_FROM_37[data[i] & 0x00FF];
}
return new String(buffer, 0, length);
}
// Conversion maps copied from Toolbox/JTOpen.
private static final HashMap encodingCcsid_ = new HashMap();
private static final HashMap ccsidEncoding_ = new HashMap();
private static final String[] encodings_ = new String[65536];
static
{
// 137+ possible Java encodings. 13 have unknown CCSIDs.
// We have 128 known in this table.
encodingCcsid_.put("ASCII", "367"); // ANSI X.34 ASCI.
encodingCcsid_.put("Cp1252", "1252");
encodingCcsid_.put("ISO8859_1", "819");
encodingCcsid_.put("Unicode", "13488");
encodingCcsid_.put("UnicodeBig", "13488"); // BOM is 0xFEFF.
// encodingCcsid_.put("UnicodeBigUnmarked", 13488);
encodingCcsid_.put("UnicodeLittle", "1202"); // BOM is 0xFFFE.
// encodingCcsid_.put("UnicodeLittleUnmarked", 13488);
encodingCcsid_.put("UTF8", "1208");
encodingCcsid_.put("UTF-8", "1208");
encodingCcsid_.put("UTF-16BE", "1200");
encodingCcsid_.put("Big5", "950");
// encodingCcsid_.put("Big5 HKSCS", ???); // Big5 with Hong Kong extensions.
encodingCcsid_.put("CNS11643", "964");
encodingCcsid_.put("Cp037", "37");
encodingCcsid_.put("Cp256", "256");
encodingCcsid_.put("Cp273", "273");
encodingCcsid_.put("Cp277", "277");
encodingCcsid_.put("Cp278", "278");
encodingCcsid_.put("Cp280", "280");
encodingCcsid_.put("Cp284", "284");
encodingCcsid_.put("Cp285", "285");
encodingCcsid_.put("Cp290", "290");
encodingCcsid_.put("Cp297", "297");
encodingCcsid_.put("Cp420", "420");
encodingCcsid_.put("Cp423", "423");
encodingCcsid_.put("Cp424", "424");
encodingCcsid_.put("Cp437", "437");
encodingCcsid_.put("Cp500", "500");
encodingCcsid_.put("Cp737", "737");
encodingCcsid_.put("Cp775", "775");
encodingCcsid_.put("Cp833", "833");
encodingCcsid_.put("Cp838", "838");
encodingCcsid_.put("Cp850", "850");
encodingCcsid_.put("Cp852", "852");
encodingCcsid_.put("Cp855", "855");
encodingCcsid_.put("Cp856", "856");
encodingCcsid_.put("Cp857", "857");
encodingCcsid_.put("Cp858", "858");
encodingCcsid_.put("Cp860", "860");
encodingCcsid_.put("Cp861", "861");
encodingCcsid_.put("Cp862", "862");
encodingCcsid_.put("Cp863", "863");
encodingCcsid_.put("Cp864", "864");
encodingCcsid_.put("Cp865", "865");
encodingCcsid_.put("Cp866", "866");
encodingCcsid_.put("Cp868", "868");
encodingCcsid_.put("Cp869", "869");
encodingCcsid_.put("Cp870", "870");
encodingCcsid_.put("Cp871", "871");
encodingCcsid_.put("Cp874", "874");
encodingCcsid_.put("Cp875", "875");
encodingCcsid_.put("Cp880", "880");
encodingCcsid_.put("Cp905", "905");
encodingCcsid_.put("Cp918", "918");
encodingCcsid_.put("Cp921", "921");
encodingCcsid_.put("Cp922", "922");
encodingCcsid_.put("Cp923", "923"); // IBM Latin-9.
encodingCcsid_.put("Cp924", "924");
encodingCcsid_.put("Cp930", "930");
encodingCcsid_.put("Cp933", "933");
encodingCcsid_.put("Cp935", "935");
encodingCcsid_.put("Cp937", "937");
encodingCcsid_.put("Cp939", "939");
encodingCcsid_.put("Cp942", "942");
// encodingCcsid_.put("Cp942C", ???); // Don't know the CCSID - unclear what the 'C' means.
encodingCcsid_.put("Cp943", "943");
// encodingCcsid_.put("Cp943C", ???); // Don't know the CCSID - unclear what the 'C' means.
encodingCcsid_.put("Cp948", "948");
encodingCcsid_.put("Cp949", "949");
// encodingCcsid_.put("Cp949C", ???); // Don't know the CCSID - unclear what the 'C' means.
encodingCcsid_.put("Cp950", "950");
encodingCcsid_.put("Cp964", "964");
encodingCcsid_.put("Cp970", "970");
encodingCcsid_.put("Cp1006", "1006");
encodingCcsid_.put("Cp1025", "1025");
encodingCcsid_.put("Cp1026", "1026");
encodingCcsid_.put("Cp1027", "1027");
encodingCcsid_.put("Cp1046", "1046");
encodingCcsid_.put("Cp1097", "1097");
encodingCcsid_.put("Cp1098", "1098");
encodingCcsid_.put("Cp1112", "1112");
encodingCcsid_.put("Cp1122", "1122");
encodingCcsid_.put("Cp1123", "1123");
encodingCcsid_.put("Cp1124", "1124");
encodingCcsid_.put("Cp1130", "1130");
encodingCcsid_.put("Cp1132", "1132");
encodingCcsid_.put("Cp1137", "1137");
encodingCcsid_.put("Cp1140", "1140");
encodingCcsid_.put("Cp1141", "1141");
encodingCcsid_.put("Cp1142", "1142");
encodingCcsid_.put("Cp1143", "1143");
encodingCcsid_.put("Cp1144", "1144");
encodingCcsid_.put("Cp1145", "1145");
encodingCcsid_.put("Cp1146", "1146");
encodingCcsid_.put("Cp1147", "1147");
encodingCcsid_.put("Cp1148", "1148");
encodingCcsid_.put("Cp1149", "1149");
encodingCcsid_.put("Cp1153", "1153");
encodingCcsid_.put("Cp1154", "1154");
encodingCcsid_.put("Cp1155", "1155");
encodingCcsid_.put("Cp1156", "1156");
encodingCcsid_.put("Cp1157", "1157");
encodingCcsid_.put("Cp1158", "1158");
encodingCcsid_.put("Cp1160", "1160");
encodingCcsid_.put("Cp1164", "1164");
encodingCcsid_.put("Cp1250", "1250");
encodingCcsid_.put("Cp1251", "1251");
encodingCcsid_.put("Cp1253", "1253");
encodingCcsid_.put("Cp1254", "1254");
encodingCcsid_.put("Cp1255", "1255");
encodingCcsid_.put("Cp1256", "1256");
encodingCcsid_.put("Cp1257", "1257");
encodingCcsid_.put("Cp1258", "1258");
encodingCcsid_.put("Cp1364", "1364");
encodingCcsid_.put("Cp1381", "1381");
encodingCcsid_.put("Cp1383", "1383");
encodingCcsid_.put("Cp1388", "1388");
encodingCcsid_.put("Cp1399", "1399");
encodingCcsid_.put("Cp4971", "4971");
encodingCcsid_.put("Cp5123", "5123");
encodingCcsid_.put("Cp9030", "9030");
encodingCcsid_.put("Cp13121", "13121");
encodingCcsid_.put("Cp13124", "13124");
encodingCcsid_.put("Cp28709", "28709");
encodingCcsid_.put("Cp33722", "33722");
// The Toolbox does not directly support EUC at this time, Java will do the conversion.
encodingCcsid_.put("EUC_CN", "1383"); // Superset of 5479.
encodingCcsid_.put("EUC_JP", "33722");
encodingCcsid_.put("EUC_KR", "970"); // Superset of 5066.
encodingCcsid_.put("EUC_TW", "964"); // Superset of 5060.
encodingCcsid_.put("GB2312", "1381");
encodingCcsid_.put("GB18030", "1392"); //1392 is mixed 4-byte; the individual component CCSIDs are not supported.
encodingCcsid_.put("GBK", "1386");
// encodingCcsid_.put("ISCII91", ???); // Indic scripts.
// The Toolbox does not directly support ISO2022.
// encodingCcsid_.put("ISO2022CN", ???); // Not sure of the CCSID, possibly 9575?
// encodingCcsid_.put("ISO2022CN_CNS", "965"); // Java doesn't support this one?
// encodingCcsid_.put("ISO2022CN_GB", "9575"); // Java doesn't support this one?
encodingCcsid_.put("ISO2022JP", "5054"); // Could be 956 also, but the IBM i JVM uses 5054.
encodingCcsid_.put("ISO2022KR", "25546"); // Could be 17354 also, but the IBM i JVM uses 25546.
encodingCcsid_.put("ISO8859_2", "912");
encodingCcsid_.put("ISO8859_3", "913");
encodingCcsid_.put("ISO8859_4", "914");
encodingCcsid_.put("ISO8859_5", "915");
encodingCcsid_.put("ISO8859_6", "1089");
encodingCcsid_.put("ISO8859_7", "813");
encodingCcsid_.put("ISO8859_8", "916");
encodingCcsid_.put("ISO8859_9", "920");
// encodingCcsid_.put("ISO8859_13", ???); // Latin alphabet No. 7.
// encodingCcsid_.put("ISO8859_15_FDIS", ???); // Don't know the CCSID; FYI, this codepage is ISO 28605.
// The Toolbox does not directly support JIS.
encodingCcsid_.put("JIS0201", "897"); // Could be 895, but the IBM i JVM uses 897.
encodingCcsid_.put("JIS0208", "952");
encodingCcsid_.put("JIS0212", "953");
// encodingCcsid_.put("JISAutoDetect", ???); // Can't do this one. Would need to look at the bytes to determine the CCSID.
encodingCcsid_.put("Johab", "1363");
encodingCcsid_.put("KOI8_R", "878");
encodingCcsid_.put("KSC5601", "949");
encodingCcsid_.put("MS874", "874");
encodingCcsid_.put("MS932", "943");
encodingCcsid_.put("MS936", "1386");
encodingCcsid_.put("MS949", "949");
encodingCcsid_.put("MS950", "950");
// encodingCcsid_.put("MacArabic", ???); // Don't know.
encodingCcsid_.put("MacCentralEurope", "1282");
encodingCcsid_.put("MacCroatian", "1284");
encodingCcsid_.put("MacCyrillic", "1283");
// encodingCcsid_.put("MacDingbat", ???); // Don't know.
encodingCcsid_.put("MacGreek", "1280");
// encodingCcsid_.put("MacHebrew", ???); // Don't know.
encodingCcsid_.put("MacIceland", "1286");
encodingCcsid_.put("MacRoman", "1275");
encodingCcsid_.put("MacRomania", "1285");
// encodingCcsid_.put("MacSymbol", ???); // Don't know.
// encodingCcsid_.put("MacThai", ???); // Don't know.
encodingCcsid_.put("MacTurkish", "1281");
// encodingCcsid_.put("MacUkraine", ???); // Don't know.
encodingCcsid_.put("SJIS", "932"); // Could be 943, but the IBM i JVM uses 932.
encodingCcsid_.put("TIS620", "874"); // IBM i JVM uses 874.
}
static
{
// Build the CCSID to encoding map.
Iterator it = encodingCcsid_.keySet().iterator();
while (it.hasNext())
{
Object key = it.next();
ccsidEncoding_.put(encodingCcsid_.get(key), key);
}
ccsidEncoding_.put("13488", "UTF-16BE");
ccsidEncoding_.put("61952", "UTF-16BE");
ccsidEncoding_.put("17584", "UTF-16BE"); // IBM i doesn't support this, but other people use it.
it = ccsidEncoding_.keySet().iterator();
while (it.hasNext())
{
String ccsid = (String)it.next();
String encoding = (String)ccsidEncoding_.get(ccsid);
int i = new Integer(ccsid).intValue();
encodings_[i] = encoding;
}
}
/**
* Converts the specific CCSID bytes into a String.
* @exception UnsupportedEncodingException Thrown if conversion to or from the specified CCSID is not supported.
**/
public static final String ebcdicByteArrayToString(final byte[] data, final int offset, final int length, final int ccsid) throws UnsupportedEncodingException
{
final int ccsidToUse = ccsid & 0x00FFFF; // So we don't overflow our encodings_ table.
if (ccsidToUse == 37) return ebcdicByteArrayToString(data, offset, length);
String encoding = encodings_[ccsidToUse];
if (encoding != null)
{
return new String(data, offset, length, encoding);
}
throw new UnsupportedEncodingException("CCSID "+ccsidToUse);
}
/**
* Converts the specific CCSID bytes into a String.
* @exception UnsupportedEncodingException Thrown if conversion to or from the specified CCSID is not supported.
**/
public static final String ebcdicByteArrayToString(final byte[] data, final int offset, final int length, final char[] buffer, final int ccsid) throws UnsupportedEncodingException
{
final int ccsidToUse = ccsid & 0x00FFFF; // So we don't overflow our encodings_ table.
if (ccsidToUse == 37) return ebcdicByteArrayToString(data, offset, length, buffer);
String encoding = encodings_[ccsidToUse];
if (encoding != null)
{
try {
return new String(data, offset, length, encoding);
} catch (UnsupportedEncodingException ex) {
// Mark as unsupported
encodings_[ccsidToUse] = null;
// Fall through and convert
encoding = null;
}
}
return CcsidConversion.createString(data, offset, length, ccsidToUse);
}
/**
* Returns true if the conversion to or from the specific CCSID is supported by the methods on this class.
**/
public static boolean isSupported(final int ccsid)
{
if (ccsid < 0 || ccsid > 65535) return false;
return ccsid == 37 || encodings_[ccsid] != null;
}
/**
* Converts the specified bytes into a long value.
**/
public static final long byteArrayToLong(final byte[] data, final int offset)
{
int p0 = (0x00FF & data[offset]) << 24;
int p1 = (0x00FF & data[offset+1]) << 16;
int p2 = (0x00FF & data[offset+2]) << 8;
int p3 = 0x00FF & data[offset+3];
int p4 = (0x00FF & data[offset+4]) << 24;
int p5 = (0x00FF & data[offset+5]) << 16;
int p6 = (0x00FF & data[offset+6]) << 8;
int p7 = (0x00FF & data[offset+7]);
long l1 = (long)(p0 | p1 | p2 | p3);
long l2 = (long)(p4 | p5 | p6 | p7);
return(l1 << 32) | (l2 & 0x00FFFFFFFFL);
}
/**
* Converts the specified bytes into an int value.
**/
public static final int byteArrayToInt(final byte[] data, final int offset)
{
int p0 = (0x00FF & data[offset]) << 24;
int p1 = (0x00FF & data[offset+1]) << 16;
int p2 = (0x00FF & data[offset+2]) << 8;
int p3 = 0x00FF & data[offset+3];
return p0 | p1 | p2 | p3;
}
/**
* Converts the specified bytes into a short value.
**/
public static final short byteArrayToShort(final byte[] data, final int offset)
{
short p0 = (short) (( 0x00FF & data[offset]) << 8);
short p1 = (short) (0x00FF & data[offset+1]);
return (short) (p0 | p1);
}
/**
* Converts the specified short value into 2 bytes.
**/
public static final void shortToByteArray(final int value, final byte[] data, final int offset)
{
data[offset] = (byte)(value >> 8);
data[offset+1] = (byte)value;
}
/**
* Converts the specified int value into 4 bytes.
**/
public static final byte[] intToByteArray(final int value)
{
final byte[] val = new byte[4];
intToByteArray(value, val, 0);
return val;
}
/**
* Converts the specified int value into 4 bytes.
**/
public static final void intToByteArray(final int value, final byte[] data, final int offset)
{
data[offset] = (byte)(value >> 24);
data[offset+1] = (byte)(value >> 16);
data[offset+2] = (byte)(value >> 8);
data[offset+3] = (byte)value;
}
/**
* Converts the specified long value into 8 bytes.
**/
public static final byte[] longToByteArray(final long longValue)
{
final byte[] val = new byte[8];
longToByteArray(longValue, val, 0);
return val;
}
// @csmith: Perf testing:
// Confirmed breaking the long into two int's is much faster.
// Using sign extension >> rather than unsigned shift >>> is faster on IBM JRE but not on Sun (Windows 32-bit).
/**
* Converts the specified long value into 8 bytes.
**/
public static final void longToByteArray(final long longValue, final byte[] data, final int offset)
{
// Do in two parts to avoid long temps.
final int high = (int)(longValue >> 32);
final int low = (int)longValue;
data[offset] = (byte)(high >> 24);
data[offset+1] = (byte)(high >> 16);
data[offset+2] = (byte)(high >> 8);
data[offset+3] = (byte)high;
data[offset+4] = (byte)(low >> 24);
data[offset+5] = (byte)(low >> 16);
data[offset+6] = (byte)(low >> 8);
data[offset+7] = (byte)low;
}
static final void writeStringToUnicodeBytes(final String s, final HostServerConnection.HostOutputStream out) throws IOException
{
for (int i=0; i> 58;
//compute sign here so we can get -+Infinity values
int sign = ((decFloat16Bits & DEC_FLOAT_16_SIGN_MASK) == DEC_FLOAT_16_SIGN_MASK) ? -1 : 1;
// deal with special numbers. (not a number and infinity)
if ((combination == 0x1fL) && (sign == 1))
{
long nanSignal = (decFloat16Bits & DEC_FLOAT_16_SIGNAL_MASK) >> 57; //shift first 7 bits to get signal bit out //@snan
return nanSignal == 1 ? "SNaN" : "NaN";
}
else if ((combination == 0x1fL) && (sign == -1))
{
long nanSignal = (decFloat16Bits & DEC_FLOAT_16_SIGNAL_MASK) >> 57; //shift first 7 bits to get signal bit out //@snan
return nanSignal == 1 ? "-SNaN" : "-NaN";
}
else if ((combination == 0x1eL) && (sign == 1))
{
return "Infinity";
}
else if ((combination == 0x1eL) && (sign == -1))
{
return "-Infinity";
}
// compute the exponent MSD and the coefficient MSD.
int exponentMSD;
long coefficientMSD;
if ((combination & 0x18L) == 0x18L)
{
// format of 11xxx:
exponentMSD = (int) ((combination & 0x06L) >> 1);
coefficientMSD = 8 + (combination & 0x01L);
}
else
{
// format of xxxxx:
exponentMSD = (int) ((combination & 0x18L) >> 3);
coefficientMSD = (combination & 0x07L);
}
// compute the exponent.
int exponent = (int) ((decFloat16Bits & DEC_FLOAT_16_EXPONENT_CONTINUATION_MASK) >> 50);
exponent |= (exponentMSD << 8);
exponent -= DEC_FLOAT_16_BIAS;
// compute the coefficient.
long coefficientContinuation = decFloat16Bits & DEC_FLOAT_16_COEFFICIENT_CONTINUATION_MASK;
int coefficientLo = decFloatBitsToDigits((int) (coefficientContinuation & 0x3fffffff)); // low 30 bits (9 digits)
int coefficientHi = decFloatBitsToDigits((int) ((coefficientContinuation >> 30) & 0xfffff)); // high 20 bits (6 digits)
coefficientHi += coefficientMSD * 1000000L;
// compute the int array of coefficient.
int[] value = computeMagnitude(new int[] { coefficientHi, coefficientLo});
// convert value to a byte array of coefficient.
byte[] magnitude = new byte[8];
magnitude[0] = (byte) (value[0] >>> 24);
magnitude[1] = (byte) (value[0] >>> 16);
magnitude[2] = (byte) (value[0] >>> 8);
magnitude[3] = (byte) (value[0]);
magnitude[4] = (byte) (value[1] >>> 24);
magnitude[5] = (byte) (value[1] >>> 16);
magnitude[6] = (byte) (value[1] >>> 8);
magnitude[7] = (byte) (value[1]);
BigInteger bigInt = new BigInteger(sign, magnitude);
BigDecimal bigDec = new BigDecimal(bigInt, -exponent);
return bigDec.toString();
}
// Copied from JTOpen. TODO - Needs optimization.
/**
* Converts the specified 16 bytes in decfloat34 format into a String.
**/
public static final String decfloat34ByteArrayToString(final byte[] data, final int offset)
{
long decFloat34BitsHi = byteArrayToLong(data, offset);
long decFloat34BitsLo = byteArrayToLong(data, offset + 8);
long combination = (decFloat34BitsHi & DEC_FLOAT_34_COMBINATION_MASK) >> 58;
//compute sign.
int sign = ((decFloat34BitsHi & DEC_FLOAT_34_SIGN_MASK) == DEC_FLOAT_34_SIGN_MASK) ? -1 : 1;
// deal with special numbers.
if ((combination == 0x1fL) && (sign == 1))
{
long nanSignal = (decFloat34BitsHi & DEC_FLOAT_34_SIGNAL_MASK) >> 57; //shift first 7 bits to get signal bit out //@snan
return nanSignal == 1 ? "SNaN" : "NaN";
}
else if ((combination == 0x1fL) && (sign == -1))
{
long nanSignal = (decFloat34BitsHi & DEC_FLOAT_34_SIGNAL_MASK) >> 57; //shift first 7 bits to get signal bit out //@snan
return nanSignal == 1 ? "-SNaN" : "-NaN";
}
else if ((combination == 0x1eL) && (sign == 1))
{
return "Infinity";
}
else if ((combination == 0x1eL) && (sign == -1))
{
return "-Infinity";
}
// compute the exponent MSD and the coefficient MSD.
int exponentMSD;
long coefficientMSD;
if ((combination & 0x18L) == 0x18L)
{
// format of 11xxx:
exponentMSD = (int) ((combination & 0x06L) >> 1);
coefficientMSD = 8 + (combination & 0x01L);
}
else
{
// format of xxxxx:
exponentMSD = (int) ((combination & 0x18L) >> 3);
coefficientMSD = (combination & 0x07L);
}
// compute the exponent.
int exponent = (int) ((decFloat34BitsHi & DEC_FLOAT_34_EXPONENT_CONTINUATION_MASK) >> 46);
exponent |= (exponentMSD << 12);
exponent -= DEC_FLOAT_34_BIAS;
// compute the coefficient.
int coefficientLo = decFloatBitsToDigits((int) (decFloat34BitsLo & 0x3fffffff)); // last 30 bits (9 digits)
// another 30 bits (9 digits)
int coefficientMeLo = decFloatBitsToDigits((int) ((decFloat34BitsLo >> 30) & 0x3fffffff));
// another 30 bits (9 digits). 26 bits from hi and 4 bits from lo.
int coefficientMeHi = decFloatBitsToDigits((int) (((decFloat34BitsHi & 0x3ffffff) << 4) | ((decFloat34BitsLo >> 60) & 0xf)));
int coefficientHi = decFloatBitsToDigits((int) ((decFloat34BitsHi >> 26) & 0xfffff)); // high 20 bits (6 digits)
coefficientHi += coefficientMSD * 1000000L;
// compute the int array of coefficient.
int[] value = computeMagnitude(new int[] { coefficientHi, coefficientMeHi, coefficientMeLo, coefficientLo});
// convert value to a byte array of coefficient.
byte[] magnitude = new byte[16];
magnitude[0] = (byte) (value[0] >>> 24);
magnitude[1] = (byte) (value[0] >>> 16);
magnitude[2] = (byte) (value[0] >>> 8);
magnitude[3] = (byte) (value[0]);
magnitude[4] = (byte) (value[1] >>> 24);
magnitude[5] = (byte) (value[1] >>> 16);
magnitude[6] = (byte) (value[1] >>> 8);
magnitude[7] = (byte) (value[1]);
magnitude[8] = (byte) (value[2] >>> 24);
magnitude[9] = (byte) (value[2] >>> 16);
magnitude[10] = (byte) (value[2] >>> 8);
magnitude[11] = (byte) (value[2]);
magnitude[12] = (byte) (value[3] >>> 24);
magnitude[13] = (byte) (value[3] >>> 16);
magnitude[14] = (byte) (value[3] >>> 8);
magnitude[15] = (byte) (value[3]);
BigInteger bigInt = new BigInteger(sign, magnitude);
BigDecimal bigDec = new BigDecimal(bigInt, -exponent);
return bigDec.toString();
}
// Copied from JTOpen. TODO - Needs optimization.
// Compute the int array of magnitude from input value segments.
private static final int[] computeMagnitude(final int[] input)
{
final int length = input.length;
final int[] mag = new int[length];
final int stop = length-1;
mag[stop] = input[stop];
for (int i=0; i= 0; --j, --k)
{
long product = (input[length-2-i] & 0xFFFFFFFFL) * (TEN_RADIX_MAGNITUDE[i][j] & 0xFFFFFFFFL)
+ (mag[k] & 0xFFFFFFFFL) // add previous value
+ (carry & 0xFFFFFFFFL); // add carry
carry = (int) (product >>> 32);
mag[k] = (int) (product & 0xFFFFFFFFL);
}
mag[k] = (int) carry;
}
return mag;
}
// Copied from JTOpen. TODO - Needs optimization.
// Convert 30 binary bits coefficient to 9 decimal digits.
private static final int decFloatBitsToDigits (int bits)
{
int decimal = 0;
for (int i=2; i>=0; --i)
{
decimal *= 1000;
decimal += unpackDenselyPackedDecimal((int)((bits >> (i * 10)) & 0x03ffL));
}
return decimal;
}
// Copied from JTOpen. TODO - Needs optimization.
// Internal declet decoding helper method.
private static int unpackDenselyPackedDecimal (int bits)
{
//Declet is the three bit encoding of one decimal digit. The Decfloat is made up of declets to represent
//the decfloat 16 or 34 digits
int combination;
if ((bits & 14) == 14)
{
combination = ((bits & 96) >> 5) | 4;
}
else
{
combination = ((bits & 8) == 8) ? (((~bits) & 6) >> 1) : 0;
}
int decoded = 0;
switch (combination)
{
case 0: // bit 6 is 0
decoded = ((bits & 896) << 1) | (bits & 119);
break;
case 1: // bits 6,7,8 are 1-1-0
decoded = ((bits & 128) << 1) | (bits & 113) | ((bits & 768) >> 7) | 2048;
break;
case 2: // bits 6,7,8 are 1-0-1
decoded = ((bits & 896) << 1) | (bits & 17) | ((bits & 96) >> 4) | 128;
break;
case 3: // bits 6,7,8 are 1-0-0
decoded = ((bits & 896) << 1) | (bits & 113) | 8;
break;
case 4: // bits 6,7,8 are 1-1-1, bits 3,4 are 0-0
decoded = ((bits & 128) << 1) | (bits & 17) | ((bits & 768) >> 7) | 2176;
break;
case 5: // bits 6,7,8 are 1-1-1, bits 3,4 are 0-1
decoded = ((bits & 128) << 1) | (bits & 17) | ((bits & 768) >> 3) | 2056;
break;
case 6: // bits 6,7,8 are 1-1-1, bits 3,4 are 1-0
decoded = ((bits & 896) << 1) | (bits & 17) | 136;
break;
case 7: // bits 6,7,8 are 1-1-1, bits 3,4 are 1-1
// NB: we ignore values of bits 0,1 in this case
decoded = ((bits & 128) << 1) | (bits & 17) | 2184;
break;
}
return((decoded & 3840) >> 8) * 100 + ((decoded & 240) >> 4) *10 + (decoded & 15);
}
/**
* Converts the specified packed decimal bytes into a String.
**/
public static final String packedDecimalToString(final byte[] data, final int offset, final int numDigits, final int scale)
{
final int len = numDigits/2+1;
int sign = data[offset+len-1] & 0x0F;
boolean isNegative = sign == 0x0B || sign == 0x0D;
char[] buf = new char[numDigits+(scale > 0 ? 1 : 0)+(isNegative ? 1 : 0)];
return packedDecimalToString(data, offset, numDigits, scale, buf);
}
/**
* Converts the specified packed decimal bytes into a String.
* The number of bytes used from data is equal to numDigits/2+1.
**/
public static final String packedDecimalToString(final byte[] data, int offset, int numDigits, final int scale, final char[] buffer)
{
// even number of digits will have a leading zero
if (numDigits%2 == 0) ++numDigits;
final int len = numDigits/2+1;
int sign = data[offset+len-1] & 0x0F;
boolean isNegative = sign == 0x0B || sign == 0x0D;
int count = 0;
if (isNegative)
{
buffer[count++] = '-';
}
// boolean doHigh = numDigits % 2 == 1;
// FindBugs says: The code uses x % 2 == 1 to check to see if a value is odd, but this won't work for negative numbers (e.g., (-5) % 2 == -1).
// If this code is intending to check for oddness, consider using x & 1 == 1, or x % 2 != 0.
boolean doHigh = numDigits % 2 != 0;
int digitsBeforeDecimal = numDigits-scale;
boolean foundNonZero = false;
for (int i=0; i> 4) : data[offset]) & 0x0F;
if (foundNonZero || nibble != 0)
{
buffer[count++] = NUM[nibble];
foundNonZero = true;
}
if (!doHigh)
{
doHigh = true;
++offset;
}
else
{
doHigh = false;
}
}
if (count == 0 || (isNegative && count == 1))
{
buffer[count++] = '0';
}
if (scale > 0)
{
buffer[count++] = '.';
}
for (int i=digitsBeforeDecimal; i> 4) : data[offset]) & 0x0F;
buffer[count++] = NUM[nibble];
if (!doHigh)
{
doHigh = true;
++offset;
}
else
{
doHigh = false;
}
}
return new String(buffer, 0, count);
}
// Copied from JTOpen AS400PackedDecimal.
public static final double packedDecimalToDouble(final byte[] data, final int offset, final int numDigits, final int scale)
{
// Compute the value.
double doubleValue = 0;
double multiplier = Math.pow(10, -scale);
int rightMostOffset = offset + numDigits/2;
boolean nibble = true; // true for left nibble, false for right nibble.
for (int i = rightMostOffset; i >= offset;)
{
if (nibble)
{
doubleValue += (byte)((data[i] & 0x00F0) >> 4) * multiplier;
--i;
}
else
{
doubleValue += ((byte)(data[i] & 0x000F)) * multiplier;
}
multiplier *= 10;
nibble = ! nibble;
}
// Determine the sign.
switch (data[rightMostOffset] & 0x000F)
{
case 0x000B:
case 0x000D:
// Negative.
doubleValue *= -1;
break;
case 0x000A:
case 0x000C:
case 0x000E:
case 0x000F:
// Positive.
break;
default:
throw new NumberFormatException("Byte sequence not valid for packed decimal ("+rightMostOffset+": "+(data[rightMostOffset] & 0x000F)+").");
}
return doubleValue;
}
public static final byte[] doubleToPackedDecimal(final double d, final int numDigits, final int scale)
{
byte[] data = new byte[numDigits/2+1];
doubleToPackedDecimal(d, data, 0, numDigits, scale);
return data;
}
// Copied from JTOpen AS400PackedDecimal.
public static final void doubleToPackedDecimal(final double d, final byte[] data, final int offset, final int numDigits, final int scale)
{
// GOAL: For performance reasons, we need to do this conversion
// without creating any Java objects (e.g., BigDecimals,
// Strings).
// If the number is too big, we can't do anything with it.
double absValue = Math.abs(d);
if (absValue > Long.MAX_VALUE)
{
throw new NumberFormatException("Double value is too big: "+d);
}
// Extract the normalized value. This is the value represented by
// two longs (one for each side of the decimal point). Using longs
// here improves the quality of the algorithm as well as the
// performance of arithmetic operations. We may need to use an
// "effective" scale due to the lack of precision representable
// by a long.
long leftSide = (long)absValue;
int effectiveScale = (scale > 15) ? 15 : scale;
long rightSide = (long)Math.round((absValue - (double)leftSide) * Math.pow(10, effectiveScale));
// Ok, now we are done with any double arithmetic!
int length = numDigits/2;
int b = offset + length;
boolean nibble = true; // true for left nibble, false for right nibble.
// If the effective scale is different than the actual scale,
// then pad with zeros.
int scaleDifference = scale - effectiveScale;
for (int i = 1; i <= scaleDifference; ++i)
{
if (nibble)
{
data[b] &= (byte)(0x000F);
--b;
}
else
{
data[b] &= (byte)(0x00F0);
}
nibble = !nibble;
}
// Compute the bytes for the right side of the decimal point.
int nextDigit;
for (int i = 1; i <= effectiveScale; ++i)
{
nextDigit = (int)(rightSide % 10);
if (nibble)
{
data[b] &= (byte)(0x000F);
data[b] |= ((byte)nextDigit << 4);
--b;
}
else
{
data[b] &= (byte)(0x00F0);
data[b] |= (byte)nextDigit;
}
nibble = !nibble;
rightSide /= 10;
}
// Compute the bytes for the left side of the decimal point.
int leftSideDigits = numDigits - scale;
for (int i = 1; i <= leftSideDigits; ++i)
{
nextDigit = (int)(leftSide % 10);
if (nibble)
{
data[b] &= (byte)(0x000F);
data[b] |= ((byte)nextDigit << 4);
--b;
}
else
{
data[b] &= (byte)(0x00F0);
data[b] |= (byte)nextDigit;
}
nibble = !nibble;
leftSide /= 10;
}
// Zero out the left part of the value, if needed.
while (b >= offset)
{
if (nibble)
{
data[b] &= (byte)(0x000F);
--b;
}
else
{
data[b] &= (byte)(0x00F0);
}
nibble = !nibble;
}
// Fix the sign.
b = offset + length;
data[b] &= (byte)(0x00F0);
data[b] |= (byte)((d >= 0) ? 0x000F : 0x000D);
// If left side still has digits, then the value was too big
// to fit.
if (leftSide > 0)
{
throw new NumberFormatException("Double value "+d+" too big for output array.");
}
}
/**
* Converts the specified String (number) into packed decimal bytes.
**/
public static final byte[] stringToPackedDecimal(final String s, final int numDigits)
{
byte[] b = new byte[numDigits/2+1];
stringToPackedDecimal(s, numDigits, b, 0);
return b;
}
/**
* Converts the specified String (number) into packed decimal bytes.
* The string must have the correct number of decimal digits for
* the conversion to be correct.
**/
public static final void stringToPackedDecimal(final String s, final int numDigits, final byte[] buffer, final int offset)
{
final int len = numDigits/2+1;
final boolean isNegative = s != null && s.length() > 0 && s.charAt(0) == '-';
int counter = offset+len-1;
buffer[counter] = isNegative ? (byte)0x0D : (byte)0x0F;
final int stop = isNegative ? 1 : 0;
boolean doHigh = true;
if ( s != null) {
for (int i = s.length()-1; i>=stop; --i)
{
char c = s.charAt(i);
if (c != '.')
{
int index = (int)c-'0';
if (index < 0 || index > 9) {
throw new NumberFormatException("Invalid character "+c);
}
if (doHigh)
{
buffer[counter--] |= CHAR_HIGH[index];
doHigh = false;
}
else
{
buffer[counter] = CHAR_LOW[index];
doHigh = true;
}
}
}
}
}
/**
* Converts the specified zoned decimal bytes into a String.
**/
public static final String zonedDecimalToString(final byte[] data, final int offset, final int numDigits, final int scale)
{
int sign = (data[offset+numDigits-1] >> 4) & 0x0F;
boolean isNegative = sign == 0x0B || sign == 0x0D;
char[] buf = new char[numDigits+(scale > 0 ? 1 : 0)+(isNegative ? 1 : 0)];
return zonedDecimalToString(data, offset, numDigits, scale, buf);
}
/**
* Converts the specified zoned decimal bytes into a String.
**/
public static final String zonedDecimalToString(final byte[] data, int offset, final int numDigits, final int scale, final char[] buffer)
{
int sign = (data[offset+numDigits-1] >> 4) & 0x0F;
boolean isNegative = sign == 0x0B || sign == 0x0D;
int count = 0;
boolean foundNonZero = false;
if (isNegative)
{
buffer[count++] = '-';
}
int digitsBeforeDecimal = numDigits-scale;
for (int i=0; i 0)
{
buffer[count++] = '.';
}
for (int i=digitsBeforeDecimal; i Long.MAX_VALUE)
{
throw new NumberFormatException("Double value is too big: "+d);
}
// Extract the normalized value. This is the value represented by
// two longs (one for each side of the decimal point). Using longs
// here improves the quality of the algorithm as well as the
// performance of arithmetic operations. We may need to use an
// "effective" scale due to the lack of precision representable
// by a long.
long leftSide = (long)absValue;
int effectiveScale = (scale > 15) ? 15 : scale;
long rightSide = (long)Math.round((absValue - (double)leftSide) * Math.pow(10, effectiveScale));
// Ok, now we are done with any double arithmetic!
// If the effective scale is different than the actual scale,
// then pad with zeros.
int rightmostOffset = offset + numDigits - 1;
int padOffset = rightmostOffset - (scale - effectiveScale);
for (int i = rightmostOffset; i > padOffset; --i)
data[i] = (byte)0x00F0;
// Compute the bytes for the right side of the decimal point.
int decimalOffset = rightmostOffset - scale;
int nextDigit;
for (int i = padOffset; i > decimalOffset; --i)
{
nextDigit = (int)(rightSide % 10);
data[i] = (byte)(0x00F0 | nextDigit);
rightSide /= 10;
}
// Compute the bytes for the left side of the decimal point.
for (int i = decimalOffset; i >= offset; --i)
{
nextDigit = (int)(leftSide % 10);
data[i] = (byte)(0x00F0 | nextDigit);
leftSide /= 10;
}
// Fix the sign, if negative.
if (d < 0)
data[rightmostOffset] = (byte)(data[rightmostOffset] & 0x00DF);
// If left side still has digits, then the value was too big
// to fit.
if (leftSide > 0)
{
throw new NumberFormatException("Double value "+d+" too big for output array.");
}
}
/**
* The scale is 0, and 0 < numDigits <= 20.
**/
public static final void longToZonedDecimal(long l, final byte[] data, final int offset, final int numDigits)
{
int rightmostOffset = offset + numDigits - 1;
boolean isNegative = (l < 0);
// Compute the bytes for the left side of the decimal point.
for (int i = rightmostOffset; i >= offset; --i)
{
int nextDigit = (int)(l % 10);
data[i] = (byte)(0x00F0 | nextDigit);
l /= 10;
}
if (isNegative) data[rightmostOffset] = (byte)(data[rightmostOffset] & 0x00DF);
if (l != 0)
{
throw new NumberFormatException("Long value too big for ZONED("+numDigits+",0).");
}
}
/**
* Converts the specified String (number) into zoned decimal bytes.
**/
public static final byte[] stringToZonedDecimal(final String s, final int numDigits)
{
byte[] b = new byte[numDigits];
stringToZonedDecimal(s, numDigits, b, 0);
return b;
}
/**
* Converts the specified String (number) into zoned decimal bytes.
**/
public static final void stringToZonedDecimal(final String s, final int numDigits, final byte[] buffer, final int offset)
{
int counter = offset+numDigits-1;
final boolean isNegative = s != null && s.length() > 0 && s.charAt(0) == '-';
final int stop = isNegative ? 1 : 0;
if (s != null) {
for (int i = s.length()-1; i>=stop; --i)
{
char c = s.charAt(i);
if (c != '.')
{
int index = c - '0';
if (index < 0 || index > 9 ) {
throw new NumberFormatException("Invalid character "+c);
}
buffer[counter--] = (byte) ( CHAR_LOW[index] | 0xF0) ;
}
}
}
if (isNegative)
{
buffer[offset+numDigits-1] = (byte) ((buffer[offset+numDigits-1] & ((byte) 0x0F)) | (byte) 0xD0);
}
}
/**
* Return the default NLV for the client corresponding to the Java locale.
* @return the default client NLV
*/
public static String getDefaultNLV() {
if (localeNlvMap_ == null) {
localeNlvMap_ = new Hashtable(100); // 74 actual entries.
// 74 entries.
localeNlvMap_.put("ar", "2954");
localeNlvMap_.put("ar_SA", "2954");
localeNlvMap_.put("be", "2979");
localeNlvMap_.put("bg", "2974");
localeNlvMap_.put("ca", "2931");
localeNlvMap_.put("cs", "2975");
localeNlvMap_.put("da", "2926");
localeNlvMap_.put("de", "2929");
localeNlvMap_.put("de_CH", "2939");
localeNlvMap_.put("de_DE", "2929");
localeNlvMap_.put("el", "2957");
localeNlvMap_.put("en", "2924");
localeNlvMap_.put("en_BE", "2909");
localeNlvMap_.put("en_CN", "2984");
localeNlvMap_.put("en_JP", "2938");
localeNlvMap_.put("en_KR", "2984");
localeNlvMap_.put("en_SG", "2984");
localeNlvMap_.put("en_TW", "2984");
localeNlvMap_.put("es", "2931");
localeNlvMap_.put("es_ES", "2931");
localeNlvMap_.put("et", "2902");
localeNlvMap_.put("fa", "2998");
localeNlvMap_.put("fi", "2925");
localeNlvMap_.put("fr", "2928");
localeNlvMap_.put("fr_BE", "2966");
localeNlvMap_.put("fr_CA", "2981");
localeNlvMap_.put("fr_CH", "2940");
localeNlvMap_.put("fr_FR", "2928");
localeNlvMap_.put("hr", "2912");
localeNlvMap_.put("hu", "2976");
localeNlvMap_.put("is", "2958");
localeNlvMap_.put("it", "2932");
localeNlvMap_.put("it_CH", "2942");
localeNlvMap_.put("iw", "2961");
localeNlvMap_.put("ja", "2962");
localeNlvMap_.put("ji", "2961");
localeNlvMap_.put("ka", "2979");
localeNlvMap_.put("kk", "2979");
localeNlvMap_.put("ko", "2986");
localeNlvMap_.put("ko_KR", "2986");
localeNlvMap_.put("lo", "2906");
localeNlvMap_.put("lt", "2903");
localeNlvMap_.put("lv", "2904");
localeNlvMap_.put("mk", "2913");
localeNlvMap_.put("nl", "2923");
localeNlvMap_.put("nl_BE", "2963");
localeNlvMap_.put("nl_NL", "2923");
localeNlvMap_.put("no", "2933");
localeNlvMap_.put("pl", "2978");
localeNlvMap_.put("pt", "2996");
localeNlvMap_.put("pt_BR", "2980");
localeNlvMap_.put("pt_PT", "2922");
localeNlvMap_.put("ro", "2992");
localeNlvMap_.put("ru", "2979");
localeNlvMap_.put("sh", "2912");
localeNlvMap_.put("sk", "2994");
localeNlvMap_.put("sl", "2911");
localeNlvMap_.put("sq", "2995");
localeNlvMap_.put("sr", "2914");
localeNlvMap_.put("sv", "2937");
localeNlvMap_.put("sv_SE", "2937");
localeNlvMap_.put("th", "2972");
localeNlvMap_.put("th_TH", "2972");
localeNlvMap_.put("tr", "2956");
localeNlvMap_.put("uk", "2979");
localeNlvMap_.put("uz", "2979");
localeNlvMap_.put("vi", "2905");
localeNlvMap_.put("zh", "2989");
localeNlvMap_.put("zh_CN", "2989");
localeNlvMap_.put("zh_HK", "2987");
localeNlvMap_.put("zh_SG", "2989");
localeNlvMap_.put("zh_TW", "2987");
localeNlvMap_.put("cht", "2987"); // Chinese/Taiwan
localeNlvMap_.put("cht_CN", "2987"); // Chinese/Taiwan
}
String defaultNLV = null;
try {
Locale locale = Locale.getDefault();
if (locale != null) {
String localeString = locale.toString();
defaultNLV = (String) localeNlvMap_.get(localeString);
if (defaultNLV == null) {
// Check for underscore index in locale
int underscoreIndex = localeString.indexOf('_');
if (underscoreIndex > 0) {
localeString = localeString.substring(0,underscoreIndex);
defaultNLV = (String) localeNlvMap_.get(localeString);
}
}
}
} catch (Exception e) {
// Ignore any errors
}
if (defaultNLV == null) defaultNLV="2924";
return defaultNLV;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy