
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 Show documentation
Show all versions of jt400 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