Path: blob/master/jcl/src/openj9.dataaccess/share/classes/com/ibm/dataaccess/DecimalData.java
12558 views
/*[INCLUDE-IF DAA]*/1/*******************************************************************************2* Copyright (c) 2013, 2021 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package com.ibm.dataaccess;2324import java.math.BigDecimal;25import java.math.BigInteger;26import java.util.Arrays;2728import com.ibm.dataaccess.ByteArrayMarshaller;29import com.ibm.dataaccess.ByteArrayUnmarshaller;30import com.ibm.dataaccess.CommonData;31import com.ibm.dataaccess.PackedDecimal;3233/**34* Routines to convert between decimal data types stored in byte arrays and Java binary types.35*36* <p>37* All the converter routines require the precision of the decimal value to convert, which represents the number of38* decimal digits in the decimal value, not including the sign.39* </p>40*41* <p>42* Unicode Decimal values can be represented as either a char array or as a byte array where every Unicode character is43* represented by a pair of adjacent bytes.44* </p>45*46* <p>47* For embedded sign nibbles (4 bit integers representing values between <code>0x0</code> and <code>0xF</code>48* inclusive) in External Decimal or Packed Decimal data, <code>0xB</code> and <code>0xD</code> represent a negative49* sign. All other sign nibble values represent a positive sign. For operations that produce an External Decimal or50* Packed Decimal result, the Data Access Accelerator library inserts the preferred positive sign code of51* <code>0xC</code> if the result is positive, and a preferred negative sign code of <code>0xD</code> if the result is52* negative. All values between <code>0x0</code> and <code>0xF</code> inclusive are interpreted as valid sign codes.53* </p>54*55* <p>56* This library has full support for signed integers but only limited support for scale points (decimals). Scale points57* and other unrecognized characters found in input External, Unicode, or Packed Decimal byte arrays are not supported,58* and may cause IllegalArgumentExceptions or undefined results. BigDecimal <i>inputs</i> will have scale ignored (i.e.59* -1.23 will be interpreted as -123). When converting to BigDecimal (as <i>output</i>), a scale value may be explicitly60* specified as a separate parameter.61* </p>62*63* @author IBM64* @version $Revision$ on $Date$65*/66public final class DecimalData67{68/**69* External Decimal data format where each byte is an EBCDIC character representing a decimal digit, the sign is70* encoded in the top nibble of the last byte.71*/72public static final int EBCDIC_SIGN_EMBEDDED_TRAILING = 1;7374/**75* External Decimal data format where each byte is an EBCDIC character representing a decimal digit, the sign is76* encoded in the top nibble of the first byte.77*/78public static final int EBCDIC_SIGN_EMBEDDED_LEADING = 2;7980/**81* External Decimal data format where each byte is an EBCDIC character representing a decimal digit, the sign is82* encoded in a separate byte that comes after the last byte of the number.83*/84public static final int EBCDIC_SIGN_SEPARATE_TRAILING = 3;8586/**87* External Decimal data format where each byte is an EBCDIC character representing a decimal digit, the sign is88* encoded in a separate byte that comes before the first byte of the number.89*/90public static final int EBCDIC_SIGN_SEPARATE_LEADING = 4;9192/**93* Unicode Decimal data format where each digit is a Unicode character, there is no sign.94*/95public static final int UNICODE_UNSIGNED = 5;9697/**98* Unicode Decimal data format where each digit is a Unicode character, the sign is stored in the first character.99*/100public static final int UNICODE_SIGN_SEPARATE_LEADING = 6;101102/**103* Unicode Decimal data format where each digit is a Unicode character, the sign is stored in the last character.104*/105public static final int UNICODE_SIGN_SEPARATE_TRAILING = 7;106107/**108* External Decimal format for positive separate sign109*/110private static final byte EBCDIC_SIGN_POSITIVE = 0x4E;111112/**113* External Decimal format for negative separate sign114*/115private static final byte EBCDIC_SIGN_NEGATIVE = 0x60;116117/**118* External Decimal High Nibble Mask119*/120private static final byte EXTERNAL_HIGH_MASK = (byte) 0xF0;121122private static final byte UNICODE_HIGH_MASK = (byte) 0x30;123124static final int EXTERNAL_DECIMAL_MIN = 1;125126static final int EXTERNAL_DECIMAL_MAX = 4;127128private static final int EBCDIC_MIN = 1;129130private static final int EBCDIC_MAX = 4;131132private static final int UNICODE_MIN = 5;133134private static final int UNICODE_MAX = 7;135136private static byte[] PD2EDTranslationTable;137private static byte[] ED2UDTranslationTable;138139private static char UNICODE_SIGN_MINUS = '-';140private static char UNICODE_SIGN_PLUS = '+';141private static char UNICODE_ZERO = '0';142143private static final boolean JIT_INTRINSICS_ENABLED = false;144145static {146PD2EDTranslationTable = new byte[512];147ED2UDTranslationTable = new byte[256];148149Arrays.fill(PD2EDTranslationTable, (byte) 0);150Arrays.fill(ED2UDTranslationTable, (byte) 0);151152for (int tenDigit = 0; tenDigit < 10; ++tenDigit)153for (int oneDigit = 0; oneDigit < 10; ++oneDigit)154{155int pdValue = tenDigit * 16 + oneDigit;156// ED tenDigit157PD2EDTranslationTable[pdValue*2 ] = (byte)(0xF0 | tenDigit);158PD2EDTranslationTable[pdValue*2+1] = (byte)(0xF0 | oneDigit);159}160161for (int digit = 0; digit < 10; ++digit)162{163int edValue = (0xF0 | digit);164ED2UDTranslationTable[edValue + 1] = (byte)(0x30 | digit);165}166167BigDecimal dummy = new BigDecimal("0");168169170}171172// Private constructor, class contains only static methods.173private DecimalData() {174}175176private static final int PACKED_BYTES_LENGTH = 33;177// Pre-compute all of the possible values for one byte of a Packed Decimal178private static final byte[] PACKED_BYTES = new byte[200];179static {180int i = 100;181for (int j = 0; j < 100; j++, i--) {182int low = i % 10;183int high = (i / 10) % 10;184PACKED_BYTES[j] = (byte) ((high << 4) + low);185}186i = 0;187for (int j = 100; j < 200; j++, i++) {188int low = i % 10;189int high = (i / 10) % 10;190PACKED_BYTES[j] = (byte) ((high << 4) + low);191}192}193194/**195* This method is recognized by the JIT. The ILGenerator and Walker will replace this method with an appropriate196* iconst bytecode value corresponding to whether or not the architecture supports DAA JIT intrinsics. Currently197* the JIT will generate an iconst 1 if and only if we are executing under zOS.198*199* @return true if DAA JIT intrinsics are enabled on the current platform, false otherwise200*201*/202private final static boolean JITIntrinsicsEnabled()203{204return JIT_INTRINSICS_ENABLED;205}206207// Binary search on the number of digits in value208private static int numDigits(int value)209{210value = (value == Integer.MIN_VALUE) ? Integer.MAX_VALUE : Math.abs(value);211212return (value >= 10000) ?213(value >= 10000000) ?214(value >= 100000000) ?215(value >= 1000000000) ? 10 : 9 : 8 :216(value >= 100000) ?217(value >= 1000000) ? 7 : 6 : 5 :218(value >= 100) ?219(value >= 1000) ? 4 : 3 :220(value >= 10) ? 2 : 1;221}222223// Binary search on the number of digits in value224private static int numDigits(long value)225{226value = value == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(value);227228return (value >= 1000000000L) ?229(value >= 100000000000000L) ?230(value >= 10000000000000000L) ?231(value >= 100000000000000000L) ?232(value >= 1000000000000000000L) ? 19 : 18 : 17 :233(value >= 1000000000000000L) ? 16 : 15 :234(value >= 100000000000L) ?235(value >= 1000000000000L) ?236(value >= 10000000000000L) ? 14 : 13 : 12 :237(value >= 10000000000L) ? 11 : 10 :238(value >= 10000L) ?239(value >= 1000000L) ?240(value >= 10000000L) ?241(value >= 100000000L) ? 9 : 8 : 7 :242(value >= 100000L) ? 6 : 5 :243(value >= 100L) ?244(value >= 1000L) ? 4 : 3 :245(value >= 10L) ? 2 : 1;246}247248/**249* Converts a binary integer value into a signed Packed Decimal format. The Packed Decimal will be padded with zeros250* on the left if necessary.251*252* Overflow can happen if the resulting Packed Decimal does not fit into the result byte array, given the offset and253* precision. In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown,254* when false a truncated or invalid result is returned.255*256* @param integerValue257* the binary integer value to convert258* @param packedDecimal259* byte array that will store the resulting Packed Decimal value260* @param offset261* offset of the first byte of the Packed Decimal in <code>packedDecimal</code>262* @param precision263* number of Packed Decimal digits. Maximum valid precision is 253264* @param checkOverflow265* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the266* specified precision (overflow)267*268* @throws ArrayIndexOutOfBoundsException269* if an invalid array access occurs270* @throws NullPointerException271* if <code>packedDecimal</code> is null272* @throws ArithmeticException273* if the <code>checkOverflow</code> parameter is true and overflow occurs274*/275public static void convertIntegerToPackedDecimal(int integerValue,276byte[] packedDecimal, int offset, int precision,277boolean checkOverflow) {278if ((offset + ((precision/ 2) + 1) > packedDecimal.length) || (offset < 0))279throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +280"convertIntegerToPackedDecimal is trying to access packedDecimal[" + offset + "] to packedDecimal[" + (offset + (precision/ 2)) + "], " +281" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");282283convertIntegerToPackedDecimal_(integerValue, packedDecimal, offset, precision, checkOverflow);284}285286private static void convertIntegerToPackedDecimal_(int integerValue,287byte[] packedDecimal, int offset, int precision,288boolean checkOverflow) {289int value;290int bytes = CommonData.getPackedByteCount(precision);291int last = offset + bytes - 1;292int i;293boolean evenPrecision = (precision % 2 == 0) ? true : false;294295// avoid invalid precision296if (checkOverflow) {297if (precision < 1)298throw new ArithmeticException(299"Decimal overflow - Packed Decimal precision lesser than 1");300301if (numDigits(integerValue) > precision)302throw new ArithmeticException(303"Decimal overflow - Packed Decimal precision insufficient");304}305if (integerValue < 0) {306packedDecimal[last] = (byte) ((Math.abs(integerValue) % 10) << 4 | CommonData.PACKED_MINUS);307value = Math.abs(integerValue / 10);308} else {309value = integerValue;310packedDecimal[last] = (byte) ((value % 10) << 4 | CommonData.PACKED_PLUS);311value = value / 10;312}313314// fill in high/low nibble pairs from next-to-last up to first315for (i = last - 1; i > offset && value != 0; i--) {316packedDecimal[i] = CommonData.getBinaryToPackedValues(value % 100);317value = value / 100;318}319320if (i == offset && value != 0) {321if (evenPrecision)322packedDecimal[i] = (byte) (CommonData.getBinaryToPackedValues(value % 100) & CommonData.LOWER_NIBBLE_MASK);323else324packedDecimal[i] = CommonData.getBinaryToPackedValues(value % 100);325value = value / 100;326i--;327}328329if (checkOverflow && value != 0) {330throw new ArithmeticException(331"Decimal overflow - Packed Decimal precision insufficient");332}333if (i >= offset) {334for (int j = 0; j < i - offset + 1; ++j)335packedDecimal[j+offset] = CommonData.PACKED_ZERO;336}337}338339/**340* Converts an integer to an External Decimal in a byte array. The External Decimal will be padded with zeros on the341* left if necessary.342*343* Overflow can happen if the resulting External Decimal value does not fit into the byte array, given the precision344* and offset. In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown,345* when false a truncated or invalid result is returned.346*347* @param integerValue348* the value to convert349* @param externalDecimal350* the byte array which will hold the External Decimal on a successful return351* @param offset352* the offset in the byte array at which the External Decimal should be located353* @param precision354* the number of decimal digits. Maximum valid precision is 253355* @param checkOverflow356* if true an <code>ArithmeticException</code>will be thrown if the designated array cannot hold the357* External Decimal.358* @param decimalType359* constant value indicating the type of External Decimal360*361* @throws NullPointerException362* if <code>externalDecimal</code> is null363* @throws ArrayIndexOutOfBoundsException364* if an invalid array access occurs365* @throws ArithmeticException366* if the <code>checkOverflow</code> parameter is true and overflow occurs367* @throws IllegalArgumentException368* if <code>decimalType</code> or <code>precision</code> is invalid369*/370public static void convertIntegerToExternalDecimal(int integerValue,371byte[] externalDecimal, int offset, int precision,372boolean checkOverflow, int decimalType) {373if ((offset < 0)374|| (offset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length))375throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. "376+ "convertIntegerToExternalDecimal is trying to access externalDecimal[" + offset377+ "] to externalDecimal[" + (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1)378+ "], " + " but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");379if (JITIntrinsicsEnabled()) {380byte[] packedDecimal = new byte[precision / 2 + 1];381convertIntegerToPackedDecimal_(integerValue, packedDecimal, 0, precision, checkOverflow);382convertPackedDecimalToExternalDecimal_(packedDecimal, 0, externalDecimal, offset, precision, decimalType);383} else {384convertIntegerToExternalDecimal_(integerValue, externalDecimal, offset, precision, checkOverflow, decimalType);385}386}387388private static void convertIntegerToExternalDecimal_(int integerValue, byte[] externalDecimal, int offset,389int precision, boolean checkOverflow, int decimalType) {390int i;391byte zoneVal = EXTERNAL_HIGH_MASK;392393int externalSignOffset = offset;394if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING)395offset++;396int end = offset + precision - 1;397398if (decimalType < EXTERNAL_DECIMAL_MIN || decimalType > EXTERNAL_DECIMAL_MAX)399throw new IllegalArgumentException("invalid decimalType");400401if (checkOverflow) {402if (precision < 1)403throw new ArithmeticException("Decimal overflow - External Decimal precision lesser than 1");404405if (numDigits(integerValue) > precision)406throw new ArithmeticException("Decimal overflow - External Decimal precision insufficient");407}408409externalDecimal[end] = (byte) (zoneVal | Math.abs(integerValue % 10));410int value = Math.abs(integerValue / 10);411// fill in high/low nibble pairs from next-to-last up to first412for (i = end - 1; i >= offset && value != 0; i--) {413externalDecimal[i] = (byte) (zoneVal | (value % 10));414value = value / 10;415}416417if (i >= offset) {418for (int j = offset; j <= i; j++) {419externalDecimal[j] = (byte) (zoneVal | CommonData.PACKED_ZERO);420}421}422423switch (decimalType) {424case EBCDIC_SIGN_EMBEDDED_TRAILING:425case EBCDIC_SIGN_EMBEDDED_LEADING:426if (decimalType == EBCDIC_SIGN_EMBEDDED_TRAILING) {427externalSignOffset += precision - 1;428}429byte sign;430if (integerValue >= 0) {431sign = (byte) (CommonData.PACKED_PLUS << 4);432} else {433sign = (byte) (CommonData.PACKED_MINUS << 4);434}435externalDecimal[externalSignOffset] = (byte) ((externalDecimal[externalSignOffset] & CommonData.LOWER_NIBBLE_MASK) | sign);436break;437case EBCDIC_SIGN_SEPARATE_TRAILING:438case EBCDIC_SIGN_SEPARATE_LEADING:439if (decimalType == EBCDIC_SIGN_SEPARATE_TRAILING) {440externalSignOffset += precision;441}442if (integerValue >= 0)443externalDecimal[externalSignOffset] = EBCDIC_SIGN_POSITIVE;444else445externalDecimal[externalSignOffset] = EBCDIC_SIGN_NEGATIVE;446break;447}448}449450/**451* Converts an integer to a Unicode Decimal in a char array452*453* Overflow can happen if the resulting External Decimal value does not fit into the char array, given the offset and454* precision. In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown,455* when false a truncated or invalid result is returned.456*457* @param integerValue458* the long value to convert459* @param unicodeDecimal460* the char array which will hold the Unicode Decimal on a successful return461* @param offset462* the offset in the char array where the Unicode Decimal would be located463* @param precision464* the number of decimal digits. Maximum valid precision is 253465* @param checkoverflow466* if true, when the designated an <code>ArithmeticException</code>467* @param unicodeType468* constant value indicating the type of Unicode Decimal469*470* @throws NullPointerException471* if <code>unicodeDecimal</code> is null472* @throws ArrayIndexOutOfBoundsException473* if an invalid array access occurs474*475* @throws ArithmeticException476* if the <code>checkOverflow</code> parameter is true and overflow occurs477* @throws IllegalArgumentException478* if the <code>decimalType</code> or <code>precision</code> is invalid479*/480public static void convertIntegerToUnicodeDecimal(int integerValue,481char[] unicodeDecimal, int offset, int precision,482boolean checkoverflow, int unicodeType) {483int size = unicodeType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;484if ((offset + size > unicodeDecimal.length) || (offset < 0))485throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +486"convertIntegerToUnicodeDecimal is trying to access unicodeDecimal[" + offset + "] to unicodeDecimal[" + (offset + size - 1) + "], " +487" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");488489if (JITIntrinsicsEnabled()) {490byte[] packedDecimal = new byte[precision / 2 + 1];491convertIntegerToPackedDecimal_(integerValue, packedDecimal, 0, precision, checkoverflow);492convertPackedDecimalToUnicodeDecimal_(packedDecimal, 0, unicodeDecimal, offset, precision, unicodeType);493} else {494convertIntegerToUnicodeDecimal_(integerValue, unicodeDecimal, offset, precision, checkoverflow, unicodeType);495}496}497498private static void convertIntegerToUnicodeDecimal_(int integerValue, char[] unicodeDecimal, int offset, int precision, boolean checkOverflow, int unicodeType)499{500// Avoid invalid precisions501if (checkOverflow) {502if (precision < 1)503throw new ArithmeticException("Decimal overflow - Unicode Decimal precision lesser than 1");504505if (precision < numDigits(integerValue))506throw new ArithmeticException("Decimal overflow - Unicode Decimal precision insufficient");507}508509switch (unicodeType)510{511case UNICODE_UNSIGNED: break;512513case UNICODE_SIGN_SEPARATE_LEADING:514unicodeDecimal[offset++] = integerValue < 0 ? UNICODE_SIGN_MINUS : UNICODE_SIGN_PLUS;515break;516517case UNICODE_SIGN_SEPARATE_TRAILING:518unicodeDecimal[offset + precision] = integerValue < 0 ? UNICODE_SIGN_MINUS : UNICODE_SIGN_PLUS;519break;520521default: throw new IllegalArgumentException("Invalid decimalType");522}523524unicodeDecimal[offset + precision - 1] = (char) (UNICODE_HIGH_MASK | (Math.abs(integerValue) % 10));525526// Normalize the value527integerValue = Math.abs(integerValue / 10);528529int i;530531// fill in high/low nibble pairs from next-to-last up to first532for (i = offset + precision - 2; i >= offset && integerValue != 0; i--) {533unicodeDecimal[i] = (char) (UNICODE_HIGH_MASK | (integerValue % 10));534535integerValue = integerValue / 10;536}537538if (checkOverflow && integerValue != 0) {539throw new ArithmeticException("Decimal overflow - Unicode Decimal precision insufficient");540}541542for (; i >= offset; i--) {543unicodeDecimal[i] = (char) UNICODE_HIGH_MASK;544}545}546547/**548* Converts a binary long value into signed Packed Decimal format. The Packed Decimal will be padded with zeros on549* the left if necessary.550*551* Overflow can happen if the resulting Packed Decimal does not fit into the result byte array, given the offset and552* precision . In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown,553* when false a truncated or invalid result is returned.554*555* @param longValue556* the binary long value to convert557* @param packedDecimal558* byte array that will store the resulting Packed Decimal value559* @param offset560* offset of the first byte of the Packed Decimal in <code>packedDecimal</code>561* @param precision562* number of Packed Decimal digits. Maximum valid precision is 253563* @param checkOverflow564* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the565* specified precision (overflow), otherwise a truncated value is returned566*567* @throws ArrayIndexOutOfBoundsException568* if an invalid array access occurs569* @throws NullPointerException570* if <code>packedDecimal</code> is null571* @throws ArithmeticException572* the <code>checkOverflow</code> parameter is true and overflow occurs573*/574public static void convertLongToPackedDecimal(long longValue,575byte[] packedDecimal, int offset, int precision,576boolean checkOverflow) {577if ((offset + ((precision/ 2) + 1) > packedDecimal.length) || (offset < 0))578throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +579"convertLongToPackedDecimal is trying to access packedDecimal[" + offset + "] to packedDecimal[" + (offset + (precision/ 2)) + "], " +580" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");581582convertLongToPackedDecimal_(longValue, packedDecimal, offset, precision, checkOverflow);583}584private static void convertLongToPackedDecimal_(long longValue,585byte[] packedDecimal, int offset, int precision,586boolean checkOverflow) {587long value;588int bytes = CommonData.getPackedByteCount(precision);589int last = offset + bytes - 1;590int i;591boolean evenPrecision = (precision % 2 == 0) ? true : false;592593if (checkOverflow) {594if (precision < 1)595throw new ArithmeticException(596"Decimal overflow - Packed Decimal precision lesser than 1");597598if (numDigits(longValue) > precision)599throw new ArithmeticException(600"Decimal overflow - Packed Decimal precision insufficient");601}602603if (longValue < 0) {604packedDecimal[last] = (byte) ((Math.abs(longValue) % 10) << 4 | CommonData.PACKED_MINUS);605value = Math.abs(longValue / 10);606} else {607value = longValue;608packedDecimal[last] = (byte) ((value % 10) << 4 | CommonData.PACKED_PLUS);609value = value / 10;610}611612// fill in high/low nibble pairs from next-to-last up to first613for (i = last - 1; i > offset && value != 0; i--) {614packedDecimal[i] = CommonData615.getBinaryToPackedValues((int) (value % 100));616value = value / 100;617}618619if (i == offset && value != 0) {620if (evenPrecision)621packedDecimal[i] = (byte) (CommonData622.getBinaryToPackedValues((int) (value % 100)) & CommonData.LOWER_NIBBLE_MASK);623else624packedDecimal[i] = CommonData625.getBinaryToPackedValues((int) (value % 100));626value = value / 100;627i--;628}629630if (checkOverflow && value != 0) {631throw new ArithmeticException(632"Decimal overflow - Packed Decimal precision insufficient");633}634if (i >= offset) {635for (int j = 0; j < i - offset + 1; ++j)636packedDecimal[j+offset] = CommonData.PACKED_ZERO;637}638}639640/**641* Converts a long into an External Decimal in a byte array. The External Decimal will be padded with zeros on the642* left if necessary.643*644* Overflow can happen if the External Decimal value does not fit into the byte array, given its precision and offset.645* In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a646* truncated or invalid result is returned.647*648* @param longValue649* the value to convert650* @param externalDecimal651* the byte array which will hold the External Decimal on a successful return652* @param offset653* the offset into <code>externalDecimal</code> where External Decimal should be located654* @param precision655* the number of decimal digits to convert. Maximum valid precision is 253656* @param checkOverflow657* if true an <code>ArithmeticException</code> or <code>IllegalArgumentException</code> may be thrown658* @param decimalType659* constant value indicating the type of External Decimal660*661* @throws NullPointerException662* if <code>externalDecimal</code> is null663* @throws ArrayIndexOutOfBoundsException664* if an invalid array access occurs665* @throws ArithmeticException666* if the <code>checkOverflow</code> parameter is true and overflow occurs667* @throws IllegalArgumentException668* if the <code>decimalType</code> or <code>precision</code> is invalid669*/670public static void convertLongToExternalDecimal(long longValue, byte[] externalDecimal, int offset, int precision,671boolean checkOverflow, int decimalType) {672if ((offset < 0)673|| (offset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length))674throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. "675+ "convertLongToExternalDecimal is trying to access externalDecimal[" + offset676+ "] to externalDecimal[" + (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1)677+ "], " + " but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");678if (JITIntrinsicsEnabled()) {679byte[] packedDecimal = new byte[precision / 2 + 1];680convertLongToPackedDecimal_(longValue, packedDecimal, 0, precision, checkOverflow);681convertPackedDecimalToExternalDecimal_(packedDecimal, 0, externalDecimal, offset, precision, decimalType);682} else {683convertLongToExternalDecimal_(longValue, externalDecimal, offset, precision, checkOverflow, decimalType);684}685}686687private static void convertLongToExternalDecimal_(long longValue, byte[] externalDecimal, int offset,688int precision, boolean checkOverflow, int decimalType) {689int i;690byte zoneVal = EXTERNAL_HIGH_MASK;691692int externalSignOffset = offset;693if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING)694offset++;695int end = offset + precision - 1;696697if (decimalType < EXTERNAL_DECIMAL_MIN || decimalType > EXTERNAL_DECIMAL_MAX)698throw new IllegalArgumentException("invalid decimalType");699700if (checkOverflow) {701if (precision < 1)702throw new ArithmeticException("Decimal overflow - External Decimal precision lesser than 1");703704if (numDigits(longValue) > precision)705throw new ArithmeticException("Decimal overflow - External Decimal precision insufficient");706}707708externalDecimal[end] = (byte) (zoneVal | Math.abs(longValue % 10));709long value = Math.abs(longValue / 10);710// fill in high/low nibble pairs from next-to-last up to first711for (i = end - 1; i >= offset && value != 0; i--) {712externalDecimal[i] = (byte) (zoneVal | (value % 10));713value = value / 10;714}715716if (i >= offset) {717for (int j = offset; j <= i; j++) {718externalDecimal[j] = (byte) (zoneVal | CommonData.PACKED_ZERO);719}720}721722switch (decimalType) {723case EBCDIC_SIGN_EMBEDDED_TRAILING:724case EBCDIC_SIGN_EMBEDDED_LEADING:725if (decimalType == EBCDIC_SIGN_EMBEDDED_TRAILING) {726externalSignOffset += precision - 1;727}728byte sign;729if (longValue >= 0) {730sign = (byte) (CommonData.PACKED_PLUS << 4);731} else {732sign = (byte) (CommonData.PACKED_MINUS << 4);733}734externalDecimal[externalSignOffset] = (byte) ((externalDecimal[externalSignOffset] & CommonData.LOWER_NIBBLE_MASK) | sign);735break;736case EBCDIC_SIGN_SEPARATE_TRAILING:737case EBCDIC_SIGN_SEPARATE_LEADING:738if (decimalType == EBCDIC_SIGN_SEPARATE_TRAILING) {739externalSignOffset += precision;740}741if (longValue >= 0)742externalDecimal[externalSignOffset] = EBCDIC_SIGN_POSITIVE;743else744externalDecimal[externalSignOffset] = EBCDIC_SIGN_NEGATIVE;745break;746}747}748749/**750* Converts a long to a Unicode Decimal in a char array751*752* Overflow can happen if the resulting Unicode Decimal value does not fit into the char array, given its precision753* and offset . In this case, when <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown,754* when false a truncated or invalid result is returned.755*756* @param longValue757* the long value to convert758* @param unicodeDecimal759* the char array which will hold the Unicode Decimal on a successful return760* @param offset761* the offset in the char array where the Unicode Decimal would be located762* @param precision763* the number of Unicode Decimal digits. Maximum valid precision is 253764* @param checkOverflow765* if true an <code>ArithmeticException</code> or <code>IllegalArgumentException</code> may be thrown766* @param decimalType767* constant value indicating the type of External Decimal768*769* @throws NullPointerException770* if <code>unicodeDecimal</code> is null771* @throws ArrayIndexOutOfBoundsException772* if an invalid array access occurs773* @throws ArithmeticException774* if the <code>checkOverflow</code> parameter is true and overflow occurs775* @throws IllegalArgumentException776* if <code>decimalType</code> or <code>precision</code> is invalid777*/778public static void convertLongToUnicodeDecimal(long longValue,779char[] unicodeDecimal, int offset, int precision,780boolean checkOverflow, int decimalType) {781int size = decimalType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;782if ((offset + size > unicodeDecimal.length) || (offset < 0))783throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +784"convertIntegerToUnicodeDecimal is trying to access unicodeDecimal[" + offset + "] to unicodeDecimal[" + (offset + size - 1) + "], " +785" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");786787if (JITIntrinsicsEnabled()) {788byte[] packedDecimal = new byte[precision / 2 + 1];789convertLongToPackedDecimal_(longValue, packedDecimal, 0, precision, checkOverflow);790convertPackedDecimalToUnicodeDecimal_(packedDecimal, 0, unicodeDecimal, offset, precision, decimalType);791} else {792convertLongToUnicodeDecimal_(longValue, unicodeDecimal, offset, precision, checkOverflow, decimalType);793}794}795796private static void convertLongToUnicodeDecimal_(long longValue, char[] unicodeDecimal, int offset, int precision, boolean checkOverflow, int unicodeType)797{798// Avoid invalid precisions799if (checkOverflow) {800if (precision < 1)801throw new ArithmeticException("Decimal overflow - Unicode Decimal precision lesser than 1");802803if (precision < numDigits(longValue))804throw new ArithmeticException("Decimal overflow - Unicode Decimal precision insufficient");805}806807switch (unicodeType)808{809case UNICODE_UNSIGNED: break;810811case UNICODE_SIGN_SEPARATE_LEADING:812unicodeDecimal[offset++] = longValue < 0 ? UNICODE_SIGN_MINUS : UNICODE_SIGN_PLUS;813break;814815case UNICODE_SIGN_SEPARATE_TRAILING:816unicodeDecimal[offset + precision] = longValue < 0 ? UNICODE_SIGN_MINUS : UNICODE_SIGN_PLUS;817break;818819default: throw new IllegalArgumentException("Invalid decimalType");820}821822unicodeDecimal[offset + precision - 1] = (char) (UNICODE_HIGH_MASK | (Math.abs(longValue) % 10));823824// Normalize the value825longValue = Math.abs(longValue / 10);826827int i;828829// fill in high/low nibble pairs from next-to-last up to first830for (i = offset + precision - 2; i >= offset && longValue != 0; i--) {831unicodeDecimal[i] = (char) (UNICODE_HIGH_MASK | (longValue % 10));832833longValue = longValue / 10;834}835836if (checkOverflow && longValue != 0) {837throw new ArithmeticException("Decimal overflow - Unicode Decimal precision insufficient");838}839840for (; i >= offset; i--) {841unicodeDecimal[i] = (char) UNICODE_HIGH_MASK;842}843}844845/**846* Converts a Packed Decimal value in a byte array into a binary integer. If the digital part of the input Packed847* Decimal is not valid then the digital part of the output will not be valid. The sign of the input Packed Decimal848* is assumed to be positive unless the sign nibble contains one of the negative sign codes, in which case the849* sign of the input Packed Decimal is interpreted as negative.850*851* Overflow can happen if the Packed Decimal value does not fit into a binary integer. When852* <code>checkOverflow</code> is true overflow results in an <code>ArithmeticException</code>, when false a853* truncated or invalid result is returned.854*855* @param packedDecimal856* byte array which contains the Packed Decimal value857* @param offset858* offset of the first byte of the Packed Decimal in <code>packedDecimal</code>859* @param precision860* number of Packed Decimal digits. Maximum valid precision is 253861* @param checkOverflow862* if true an <code>ArithmeticException</code> may be thrown863*864* @return int the resulting binary integer value865*866* @throws NullPointerException867* if <code>packedDecimal</code> is null868* @throws ArrayIndexOutOfBoundsException869* if an invalid array access occurs870* @throws ArithmeticException871* if <code>checkOverflow</code> is true and the result does not fit into an int (overflow)872*/873public static int convertPackedDecimalToInteger(byte[] packedDecimal,874int offset, int precision, boolean checkOverflow) {875if ((offset + ((precision/ 2) + 1) > packedDecimal.length) || (offset < 0))876throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +877"convertPackedDecimalToInteger is trying to access packedDecimal[" + offset + "] to packedDecimal[" + (offset + (precision/ 2)) + "], " +878" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");879880return convertPackedDecimalToInteger_(packedDecimal, offset, precision, checkOverflow);881}882883private static int convertPackedDecimalToInteger_(byte[] packedDecimal,884int offset, int precision, boolean checkOverflow) {885int bytes = CommonData.getPackedByteCount(precision);886int end = offset + bytes - 1;887long value = 0;// = (packedDecimal[end] & CommonData.INTEGER_MASK) >> 4;888889byte sign = CommonData.getSign((byte) (packedDecimal[end] & CommonData.LOWER_NIBBLE_MASK));890891// Skip the first byte if the precision is even and the low-order nibble is zero892if (precision % 2 == 0 && (packedDecimal[offset] & CommonData.LOWER_NIBBLE_MASK) == 0x00)893{894precision--;895offset++;896}897898// Skip consecutive zero bytes899for (; offset < end && packedDecimal[offset] == CommonData.PACKED_ZERO; offset++)900{901precision -= 2;902}903904if (checkOverflow)905{906// Skip high-order zero if and only if precision is odd907if (precision % 2 == 1 && (packedDecimal[offset] & CommonData.HIGHER_NIBBLE_MASK) == 0x00)908{909precision--;910}911912// At this point we are guaranteed that the nibble pointed by a non-zero precision value is non-zero913if (precision > 10)914throw new ArithmeticException(915"Decimal overflow - Packed Decimal too large for an int");916}917918// For checkOverflow == true at this point we are guaranteed that precision <= 10. The following loop919// will never overflow because the long value can always contain an integer of precision 10.920921for (int pos = offset; pos <= end - 1; ++pos)922{923value = value * 100 + CommonData.getPackedToBinaryValues(packedDecimal[pos]);924}925926value = value * 10 + ((packedDecimal[end] & CommonData.HIGHER_NIBBLE_MASK) >> 4);927928if (sign == CommonData.PACKED_MINUS)929value = -1 * value;930931if (checkOverflow && (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE))932{933throw new ArithmeticException(934"Decimal overflow - Packed Decimal too large for a int");935}936937return (int)value;938}939940/**941* Converts a Packed Decimal value in a byte array into a binary long. If the digital part of the input Packed942* Decimal is not valid then the digital part of the output will not be valid. The sign of the input Packed Decimal943* is assumed to be positive unless the sign nibble contains one of the negative sign codes, in which case the944* sign of the input Packed Decimal is interpreted as negative.945*946* Overflow can happen if the Packed Decimal value does not fit into a binary long. In this case, when947* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or948* invalid result is returned.949*950* @param packedDecimal951* byte array which contains the Packed Decimal value952* @param offset953* offset of the first byte of the Packed Decimal in <code>packedDecimal</code>954* @param precision955* number of decimal digits. Maximum valid precision is 253956* @param checkOverflow957* if true an <code>ArithmeticException</code> may be thrown958*959* @return long the resulting binary long value960*961* @throws NullPointerException962* if <code>packedDecimal</code> is null963* @throws ArrayIndexOutOfBoundsException964* if an invalid array access occurs965* @throws ArithmeticException966* if <code>checkOverflow</code> is true and the result does not fit into a long (overflow)967*/968public static long convertPackedDecimalToLong(byte[] packedDecimal,969int offset, int precision, boolean checkOverflow) {970if ((offset + ((precision/ 2) + 1) > packedDecimal.length) || (offset < 0))971throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +972"convertPackedDecimalToLong is trying to access packedDecimal[" + offset + "] to packedDecimal[" + (offset + (precision/ 2)) + "], " +973" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");974975return convertPackedDecimalToLong_(packedDecimal, offset, precision, checkOverflow);976}977978private static long convertPackedDecimalToLong_(byte[] packedDecimal,979int offset, int precision, boolean checkOverflow) {980long value = 0;981int bytes = CommonData.getPackedByteCount(precision);982int end = offset + bytes - 1;983int last = packedDecimal[end] & CommonData.INTEGER_MASK;984byte sign = CommonData.getSign((byte) (last & CommonData.LOWER_NIBBLE_MASK));985986// Skip the first byte if the precision is even and the low-order nibble is zero987if (precision % 2 == 0 && (packedDecimal[offset] & CommonData.LOWER_NIBBLE_MASK) == 0x00)988{989precision--;990offset++;991}992993// Skip consecutive zero bytes994for (; offset < end && packedDecimal[offset] == CommonData.PACKED_ZERO; offset++)995{996precision -= 2;997}998999if (checkOverflow)1000{1001// Skip high-order zero if and only if precision is odd1002if (precision % 2 == 1 && (packedDecimal[offset] & CommonData.HIGHER_NIBBLE_MASK) == 0x00)1003{1004precision--;1005}10061007// At this point we are guaranteed that the nibble pointed by a non-zero precision value is non-zero1008if (precision > 19)1009throw new ArithmeticException(1010"Decimal overflow - Packed Decimal too large for a long");1011}10121013// For checkOverflow == true at this point we are guaranteed that precision <= 19. The following loop1014// may cause the signed long value to overflow. Because the first digit of Long.MAX_VALUE is a 9 the1015// overflowed signed long value cannot overflow an unsigned long. This guarantees that if an overflow1016// occurs, value will be negative. We will use this fact along with the sign code calculated earlier1017// to determine whether overflow occurred.10181019for (int pos = offset; pos <= end - 1; ++pos)1020{1021value = value * 100 + CommonData.getPackedToBinaryValues(packedDecimal[pos]);1022}10231024value = value * 10 + ((last & CommonData.HIGHER_NIBBLE_MASK) >> 4);102510261027if (sign == CommonData.PACKED_MINUS)1028value = -value;10291030if (checkOverflow)1031{1032if (sign == CommonData.PACKED_PLUS && value < 0)1033throw new ArithmeticException(1034"Decimal overflow - Packed Decimal too large for a long");1035else if (sign == CommonData.PACKED_MINUS && value > 0)1036throw new ArithmeticException(1037"Decimal overflow - Packed Decimal too large for a long");1038}10391040return value;1041}10421043/**1044* Converts a Packed Decimal in a byte array into an External Decimal in another byte array. If the digital part of1045* the input Packed Decimal is not valid then the digital part of the output will not be valid. The sign of the1046* input Packed Decimal is assumed to be positive unless the sign nibble contains one of the negative sign codes,1047* in which case the sign of the input Packed Decimal is interpreted as negative.1048*1049* @param packedDecimal1050* byte array that holds the Packed Decimal to be converted1051* @param packedOffset1052* offset in <code>packedDecimal</code> where the Packed Decimal is located1053* @param externalDecimal1054* byte array that will hold the External Decimal on a successful return1055* @param externalOffset1056* offset in <code>externalOffset</code> where the External Decimal is expected to be located1057* @param precision1058* number of decimal digits1059* @param decimalType1060* constant indicating the type of the decimal1061*1062* @throws ArrayIndexOutOfBoundsException1063* if an invalid array access occurs1064* @throws NullPointerException1065* if <code>packedDecimal</code> or <code>externalDecimal</code> are null1066* @throws IllegalArgumentException1067* if <code>precision</code> or <code>decimalType</code> is invalid1068*/1069public static void convertPackedDecimalToExternalDecimal(1070byte[] packedDecimal, int packedOffset, byte[] externalDecimal,1071int externalOffset, int precision, int decimalType) {1072if ((packedOffset + ((precision/ 2) + 1) > packedDecimal.length) || (packedOffset < 0))1073throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1074"convertPackedDecimalToExternalDecimal is trying to access packedDecimal[" + packedOffset + "] to packedDecimal[" + (packedOffset + (precision/ 2)) + "], " +1075" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");1076if ((externalOffset < 0) || (externalOffset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length))1077throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1078"convertPackedDecimalToExternalDecimal is trying to access externalDecimal[" + externalOffset + "] to externalDecimal[" + (externalOffset + CommonData.getExternalByteCounts(precision, decimalType) - 1) + "], " +1079" but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");10801081convertPackedDecimalToExternalDecimal_(packedDecimal, packedOffset, externalDecimal,1082externalOffset, precision, decimalType);1083}10841085private static void convertPackedDecimalToExternalDecimal_(1086byte[] packedDecimal, int packedOffset, byte[] externalDecimal,1087int externalOffset, int precision, int decimalType) {10881089if (decimalType < EXTERNAL_DECIMAL_MIN1090|| decimalType > EXTERNAL_DECIMAL_MAX)1091throw new IllegalArgumentException("invalid decimalType");1092if (precision <= 0)1093throw new IllegalArgumentException("negative precision");10941095int externalSignOffset = externalOffset;1096if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING)1097externalOffset++;10981099int end = packedOffset + precision / 2;1100int edEnd = externalOffset + precision - 1;11011102byte zoneVal = EXTERNAL_HIGH_MASK;11031104// handle even precision1105if (precision % 2 == 0) {1106externalDecimal[externalOffset++] = (byte) (zoneVal | (packedDecimal[packedOffset++] & CommonData.LOWER_NIBBLE_MASK));1107}11081109// compute all the intermediate digits1110for (int i = packedOffset; i < end; i++) {1111externalDecimal[externalOffset++] = (byte) (zoneVal | (((packedDecimal[i] & CommonData.HIGHER_NIBBLE_MASK) >> 4) & CommonData.LOWER_NIBBLE_MASK));1112externalDecimal[externalOffset++] = (byte) (zoneVal | (packedDecimal[i] & CommonData.LOWER_NIBBLE_MASK));1113}111411151116// deal with the last digit1117externalDecimal[edEnd] = (byte) (zoneVal | (((packedDecimal[end] & 0xF0) >> 4) & CommonData.LOWER_NIBBLE_MASK));11181119//byte sign = (byte)((packedDecimal[end] & CommonData.LOWER_NIBBLE_MASK) << 4);1120byte sign = (byte)(CommonData.getSign(packedDecimal[end] & CommonData.LOWER_NIBBLE_MASK) << 4);11211122switch (decimalType) {1123case EBCDIC_SIGN_SEPARATE_LEADING:1124if (sign == (byte) 0xC0)1125externalDecimal[externalSignOffset] = EBCDIC_SIGN_POSITIVE;1126else1127externalDecimal[externalSignOffset] = EBCDIC_SIGN_NEGATIVE;1128break;1129case EBCDIC_SIGN_EMBEDDED_LEADING:1130externalDecimal[externalSignOffset] = (byte) ((externalDecimal[externalSignOffset] & CommonData.LOWER_NIBBLE_MASK) | sign);1131break;1132case EBCDIC_SIGN_EMBEDDED_TRAILING:1133externalSignOffset += precision - 1;1134externalDecimal[externalSignOffset] = (byte) ((externalDecimal[externalSignOffset] & CommonData.LOWER_NIBBLE_MASK) | sign);1135break;1136case EBCDIC_SIGN_SEPARATE_TRAILING:1137externalSignOffset += precision;1138if (sign == (byte) 0xC0)1139externalDecimal[externalSignOffset] = EBCDIC_SIGN_POSITIVE;1140else1141externalDecimal[externalSignOffset] = EBCDIC_SIGN_NEGATIVE;1142break;1143default:1144//unreachable code1145//throw new IllegalArgumentException("invalid decimalType");1146}1147}11481149/**1150* Convert a Packed Decimal in a byte array to a Unicode Decimal in a char array. If the digital part of the input1151* Packed Decimal is not valid then the digital part of the output will not be valid. The sign of the input Packed1152* Decimal is assumed to be positive unless the sign nibble contains one of the negative sign codes, in which1153* case the sign of the input Packed Decimal is interpreted as negative.1154*1155* @param packedDecimal1156* byte array that holds a Packed Decimal to be converted1157* @param packedOffset1158* offset in <code>packedDecimal</code> where the Packed Decimal is located1159* @param unicodeDecimal1160* char array that will hold the Unicode Decimal on a successful return1161* @param unicodeOffset1162* offset in the byte array where the Unicode Decimal is expected to be located1163* @param precision1164* number of decimal digits1165* @param decimalType1166* constant value indicating the type of the External Decimal1167*1168* @throws ArrayIndexOutOfBoundsException1169* if an invalid array access occurs1170* @throws NullPointerException1171* if <code>packedDecimal</code> or <code>unicodeDecimal</code> are null1172* @throws IllegalArgumentException1173* if <code>precision</code> or <code>decimalType</code> is invalid1174*/1175public static void convertPackedDecimalToUnicodeDecimal(1176byte[] packedDecimal, int packedOffset, char[] unicodeDecimal,1177int unicodeOffset, int precision, int decimalType) {1178int size = decimalType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;1179if ((unicodeOffset + size > unicodeDecimal.length) || (unicodeOffset < 0))1180throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1181"convertPackedDecimalToUnicodeDecimal is trying to access unicodeDecimal[" + unicodeOffset + "] to unicodeDecimal[" + (unicodeOffset + size - 1) + "], " +1182" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");1183if ((packedOffset < 0) || (packedOffset + ((precision/ 2) + 1) > packedDecimal.length))1184throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1185"convertPackedDecimalToUnicodeDecimal is trying to access packedDecimal[" + packedOffset + "] to packedDecimal[" + (packedOffset + (precision/ 2)) + "], " +1186" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");11871188convertPackedDecimalToUnicodeDecimal_(packedDecimal, packedOffset, unicodeDecimal,1189unicodeOffset, precision, decimalType);1190}11911192private static void convertPackedDecimalToUnicodeDecimal_(1193byte[] packedDecimal, int packedOffset, char[] unicodeDecimal,1194int unicodeOffset, int precision, int decimalType) {11951196if (precision <= 0)1197throw new IllegalArgumentException("negative precision");11981199int externalSignOffset = -1;1200switch (decimalType) {1201case UNICODE_UNSIGNED:1202break;1203case UNICODE_SIGN_SEPARATE_LEADING:1204externalSignOffset = unicodeOffset++;1205break;1206case UNICODE_SIGN_SEPARATE_TRAILING:1207externalSignOffset = unicodeOffset + precision;1208break;1209default:1210throw new IllegalArgumentException("invalid decimalType");1211}12121213byte zoneVal = UNICODE_HIGH_MASK;12141215// Get sign from Packed Decimal1216int end = packedOffset + precision / 2;1217byte sign = (byte) (packedDecimal[end] & CommonData.LOWER_NIBBLE_MASK);1218sign = CommonData.getSign(sign);12191220// handle even precision1221if (precision % 2 == 0) {1222unicodeDecimal[unicodeOffset] = (char) (zoneVal | (packedDecimal[packedOffset++] & CommonData.LOWER_NIBBLE_MASK));1223unicodeOffset++;1224}12251226// compute all the intermediate digits1227for (int i = packedOffset; i < end; i++) {1228unicodeDecimal[unicodeOffset] = (char) (zoneVal | (((packedDecimal[i] & CommonData.HIGHER_NIBBLE_MASK) >> 4) & CommonData.LOWER_NIBBLE_MASK));1229unicodeOffset++;1230unicodeDecimal[unicodeOffset] = (char) (zoneVal | (packedDecimal[i] & CommonData.LOWER_NIBBLE_MASK));1231unicodeOffset++;1232}12331234// deal with the last digit1235unicodeDecimal[unicodeOffset] = (char) (zoneVal | (((packedDecimal[end] & 0xF0) >> 4) & CommonData.LOWER_NIBBLE_MASK));12361237// put the sign1238if (decimalType != UNICODE_UNSIGNED) {1239if (sign == CommonData.PACKED_PLUS) {1240// put 2B for positive1241unicodeDecimal[externalSignOffset] = 0x2B;1242} else {1243// put 2D for negative1244unicodeDecimal[externalSignOffset] = 0x2D;1245}1246}1247}12481249/**1250* Convert a Packed Decimal in a byte array to a BigInteger. If the digital part of the input Packed Decimal is not1251* valid then the digital part of the output will not be valid. The sign of the input Packed Decimal is assumed to1252* to be positive unless the sign nibble contains one of the negative sign codes, in which case the sign of the1253* input Packed Decimal is interpreted as negative.1254*1255* Overflow can happen if the Packed Decimal value does not fit into the BigInteger. In this case, when1256* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1257* invalid result is returned.1258*1259* @param packedDecimal1260* byte array that holds the Packed Decimal to be converted1261* @param offset1262* offset in <code>packedDecimal</code> where the Packed Decimal is located1263* @param precision1264* number of decimal digits. Maximum valid precision is 2531265* @param checkOverflow1266* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the1267* specified precision (overflow)1268* @return BigInteger the resulting BigInteger1269*1270* @throws ArrayIndexOutOfBoundsException1271* if an invalid array access occurs1272* @throws NullPointerException1273* if <code>packedDecimal</code> is null1274*/1275public static BigInteger convertPackedDecimalToBigInteger(1276byte[] packedDecimal, int offset, int precision,1277boolean checkOverflow) {1278return convertPackedDecimalToBigDecimal(packedDecimal, offset,1279precision, 0, checkOverflow).toBigInteger();1280}12811282/**1283* Convert a Packed Decimal in a byte array to a BigDecimal. If the digital part of the input Packed Decimal is not1284* valid then the digital part of the output will not be valid. The sign of the input Packed Decimal is assumed to1285* to be positive unless the sign nibble contains one of the negative sign codes, in which case the sign of the1286* input Packed Decimal is interpreted as negative.1287*1288* Overflow can happen if the Packed Decimal value does not fit into the BigDecimal. In this case, when1289* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1290* invalid result is returned.1291*1292* @param packedDecimal1293* byte array that holds the Packed Decimal to be converted1294* @param offset1295* offset in <code>packedDecimal</code> where the Packed Decimal is located1296* @param precision1297* number of decimal digits. Maximum valid precision is 2531298* @param scale1299* scale of the BigDecimal to be returned1300* @param checkOverflow1301* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the1302* specified precision (overflow)1303*1304* @return BigDecimal the resulting BigDecimal1305*1306* @throws NullPointerException1307* if <code>packedDecimal</code> is null1308* @throws ArrayIndexOutOfBoundsException1309* /requires rounding if an invalid array access occurs1310*/1311public static BigDecimal convertPackedDecimalToBigDecimal(1312byte[] packedDecimal, int offset, int precision, int scale,1313boolean checkOverflow) {13141315if (precision <= 9) {1316return BigDecimal.valueOf(1317convertPackedDecimalToInteger(packedDecimal, offset, precision,1318checkOverflow), scale);1319} else if (precision <= 18) {1320return BigDecimal.valueOf(1321convertPackedDecimalToLong(packedDecimal, offset, precision,1322checkOverflow), scale);1323}13241325return slowSignedPackedToBigDecimal(packedDecimal, offset, precision,1326scale, checkOverflow);1327}13281329/**1330* Converts an External Decimal value in a byte array into a binary integer. If the digital part of the input1331* External Decimal is not valid then the digital part of the output will not be valid. The sign of the input1332* External Decimal is assumed to be positive unless the sign nibble or byte (depending on1333* <code>decimalType</code>) contains one of the negative sign codes, in which case the sign of the input External1334* Decimal is interpreted as negative.1335*1336* Overflow can happen if the External Decimal value does not fit into a binary integer. In this case, when1337* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false the resulting number1338* will be wrapped around starting at the minimum/maximum possible integer value.1339*1340* @param externalDecimal1341* byte array which contains the External Decimal value1342* @param offset1343* the offset where the External Decimal value is located1344* @param precision1345* number of decimal digits. Maximum valid precision is 2531346* @param checkOverflow1347* if true an <code>ArithmeticException</code> or <code>IllegalArgumentException</code> may be thrown. If1348* false and there is an overflow, the result is undefined.1349* @param decimalType1350* constant value indicating the type of External Decimal1351*1352* @return int the resulting binary integer1353*1354* @throws NullPointerException1355* if <code>externalDecimal</code> is null1356* @throws ArrayIndexOutOfBoundsException1357* if an invalid array access occurs1358* @throws ArithmeticException1359* if <code>checkOverflow</code> is true and the result does not fit into a int (overflow)1360* @throws IllegalArgumentException1361* if <code>precision</code> or <code>decimalType</code> is invalid1362*/1363public static int convertExternalDecimalToInteger(byte[] externalDecimal,1364int offset, int precision, boolean checkOverflow, int decimalType) {1365if ((offset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length) || (offset < 0))1366throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1367"convertExternalDecimalToInteger is trying to access externalDecimal[" + offset + "] to externalDecimal[" + (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1) + "], " +1368" but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");13691370if (precision <= 0)1371throw new IllegalArgumentException("Precision can't be negative.");13721373if (JITIntrinsicsEnabled()) {1374byte[] packedDecimal = new byte[precision / 2 + 1];1375convertExternalDecimalToPackedDecimal_(externalDecimal, offset, packedDecimal, 0, precision, decimalType);1376return convertPackedDecimalToInteger_(packedDecimal, 0, precision, checkOverflow);1377} else {1378return convertExternalDecimalToInteger_(externalDecimal, offset, precision, checkOverflow, decimalType);1379}1380}13811382private static int convertExternalDecimalToInteger_(byte[] externalDecimal,1383int offset, int precision, boolean checkOverflow, int decimalType) {1384int end = (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1);1385boolean isNegative = isExternalDecimalSignNegative(externalDecimal, offset, precision, decimalType);138613871388if (decimalType == EBCDIC_SIGN_SEPARATE_TRAILING) {1389end--;1390} else if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING) {1391offset++;1392}13931394int value = 0;1395if (isNegative)1396{1397if (precision < 10 || (checkOverflow == false)) //max/min values are -2,147,483,648 and 2,147,483,647, so no overflow possible1398{1399for (int i = offset; i <= end; i++)1400{1401value = value * 10 - (externalDecimal[i] & 0x0F);1402}1403}1404else //checkOverflow true, precision >= 101405{1406int tenthOffset = end-9; //location of 10th digit if existent1407int offsetMod = offset > tenthOffset ? offset : tenthOffset; //only read last 10 digits1408for (int i = offsetMod; i <= end; i++)1409{1410value = value * 10 - (externalDecimal[i] & 0x0F);1411}1412//need value>0 for cases like 2,900,000,000 and digit>2 for 5,000,000,0001413if (value > 0 || (tenthOffset >= offset && (externalDecimal[tenthOffset] & 0x0F) > 2)) //check 10th digit1414{1415throw new ArithmeticException(1416"Decimal overflow - External Decimal too small for an int");1417}14181419//any more digits are overflow1420for (int i = offset; i < offsetMod; i++)1421{1422if ((externalDecimal[i] & 0x0F) > 0)1423{1424throw new ArithmeticException(1425"Decimal overflow - External Decimal too small for an int");1426}1427}1428}1429}1430else1431{1432if (precision < 10 || (checkOverflow == false)) //max/min values are -2,147,483,648 and 2,147,483,647, so no overflow possible1433{1434for (int i = offset; i <= end; i++)1435{1436value = value * 10 + (externalDecimal[i] & 0x0F);1437}1438}1439else //checkOverflow true, precision >= 101440{1441int tenthOffset = end-9; //location of 10th digit if existent1442int offsetMod = offset > tenthOffset ? offset : tenthOffset; //only read last 10 digits1443for (int i = offsetMod; i <= end; i++)1444{1445value = value * 10 + (externalDecimal[i] & 0x0F);1446}1447//need value<0 for cases like 2,900,000,000 and digit>2 for 5,000,000,0001448if (value < 0 || (tenthOffset >= offset && (externalDecimal[tenthOffset] & 0x0F) > 2)) //check 10th digit1449{1450throw new ArithmeticException(1451"Decimal overflow - External Decimal too large for an int");1452}14531454//any more digits are overflow1455for (int i = offset; i < offsetMod; i++)1456{1457if ((externalDecimal[i] & 0x0F) > 0)1458{1459throw new ArithmeticException(1460"Decimal overflow - External Decimal too large for an int");1461}1462}1463}1464}1465return value;1466}14671468/**1469* Converts an External Decimal value in a byte array into a long. If the digital part of the input External Decimal1470* is not valid then the digital part of the output will not be valid. The sign of the input External Decimal is1471* assumed to be positive unless the sign nibble or byte (depending on <code>decimalType</code>) contains one of1472* the negative sign codes, in which case the sign of the input External Decimal is interpreted as negative.1473*1474* Overflow can happen if the External Decimal value does not fit into a binary long. When1475* <code>checkOverflow</code> is true overflow results in an <code>ArithmeticException</code>, when false the1476* resulting number will be wrapped around starting at the minimum/maximum possible long value.1477*1478* @param externalDecimal1479* byte array which contains the External Decimal value1480* @param offset1481* offset of the first byte of the Packed Decimal in the <code>externalDecimal</code>1482* @param precision1483* number of External Decimal digits. Maximum valid precision is 2531484* @param checkOverflow1485* if true an <code>ArithmeticException</code> will be thrown when the converted value cannot fit into1486* designated External Decimal array. If false and there is an overflow, the result is undefined.1487* @param decimalType1488* constant value indicating the type of External Decimal1489*1490* @return long the resulting binary long value1491*1492* @throws NullPointerException1493* if <code>externalDecimal</code> is null1494* @throws ArrayIndexOutOfBoundsException1495* if an invalid array access occurs1496* @throws ArithmeticException1497* if <code>checkOverflow</code> is true and the result does not fit into a long (overflow)1498* @throws IllegalArgumentException1499* if <code>precision</code> or <code>decimalType</code> is invalid1500*/1501public static long convertExternalDecimalToLong(byte[] externalDecimal,1502int offset, int precision, boolean checkOverflow, int decimalType) {1503if ((offset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length) || (offset < 0))1504throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1505"convertExternalDecimalToLong is trying to access externalDecimal[" + offset + "] to externalDecimal[" + (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1) + "], " +1506" but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");15071508if (precision <= 0)1509throw new IllegalArgumentException("Precision can't be negative.");15101511if (JITIntrinsicsEnabled()) {1512byte[] packedDecimal = new byte[precision / 2 + 1];1513convertExternalDecimalToPackedDecimal_(externalDecimal, offset, packedDecimal, 0, precision, decimalType);1514return convertPackedDecimalToLong_(packedDecimal, 0, precision, checkOverflow);1515} else {1516return convertExternalDecimalToLong_(externalDecimal, offset, precision, checkOverflow, decimalType);1517}1518}15191520private static long convertExternalDecimalToLong_(byte[] externalDecimal,1521int offset, int precision, boolean checkOverflow, int decimalType) {1522int end = (offset + CommonData.getExternalByteCounts(precision, decimalType) - 1);1523boolean isNegative = isExternalDecimalSignNegative(externalDecimal, offset, precision, decimalType);15241525if (decimalType == EBCDIC_SIGN_SEPARATE_TRAILING) {1526end--;1527} else if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING) {1528offset++;1529}15301531long value = 0;1532if (isNegative)1533{1534if (precision < 19 || (checkOverflow == false)) //max/min values are -9,223,372,036,854,775,808 and 9,223,372,036,854,775,807, so no overflow possible1535{1536for (int i = offset; i <= end; i++)1537{1538value = value * 10 - (externalDecimal[i] & 0x0F);1539}1540}1541else //checkOverflow true, precision >= 191542{1543int offsetMod = offset > end-18 ? offset : end-18; //only read last 19 digits1544for (int i = offsetMod; i <= end; i++)1545{1546value = value * 10 - (externalDecimal[i] & 0x0F);1547}1548if (value > 0) //check 19th digit1549{1550throw new ArithmeticException(1551"Decimal overflow - External Decimal too small for a long");1552}15531554//any more digits are overflow1555for (int i = offset; i < offsetMod; i++)1556{1557if ((externalDecimal[i] & 0x0F) > 0)1558{1559throw new ArithmeticException(1560"Decimal overflow - External Decimal too small for a long");1561}1562}1563}1564}1565else1566{1567if (precision < 19 || (checkOverflow == false)) //max/min values are -9,223,372,036,854,775,808 and 9,223,372,036,854,775,807, so no overflow possible1568{1569for (int i = offset; i <= end; i++)1570{1571value = value * 10 + (externalDecimal[i] & 0x0F);1572}1573}1574else //checkOverflow true, precision >= 191575{1576int offsetMod = offset > end-18 ? offset : end-18; //only read last 19 digits1577for (int i = offsetMod; i <= end; i++)1578{1579value = value * 10 + (externalDecimal[i] & 0x0F);1580}1581if (value < 0) //check 19th digit1582{1583throw new ArithmeticException(1584"Decimal overflow - External Decimal too large for a long");1585}15861587//any more digits are overflow1588for (int i = offset; i < offsetMod; i++)1589{1590if ((externalDecimal[i] & 0x0F) > 0)1591{1592throw new ArithmeticException(1593"Decimal overflow - External Decimal too large for a long");1594}1595}1596}1597}1598return value;1599}16001601/**1602* Converts an External Decimal in a byte array to a Packed Decimal in another byte array. If the digital part of1603* the input External Decimal is not valid then the digital part of the output will not be valid. The sign of the1604* input External Decimal is assumed to be positive unless the sign nibble or byte (depending on1605* <code>decimalType</code>) contains one of the negative sign codes, in which case the sign of the input External1606* Decimal is interpreted as negative.1607*1608* @param externalDecimal1609* byte array holding the External Decimal to be converted1610* @param externalOffset1611* offset in <code>externalDecimal</code> where the External Decimal is located1612* @param packedDecimal1613* byte array which will hold the Packed Decimal on a successful return1614* @param packedOffset1615* offset in <code>packedDecimal</code> where the Packed Decimal is expected to be located1616* @param precision1617* the number of decimal digits1618* @param decimalType1619* constant value indicating the type of External Decimal1620*1621*1622* @throws ArrayIndexOutOfBoundsException1623* if an invalid array access occurs1624* @throws NullPointerException1625* if <code>packedDecimal</code> or <code>externalDecimal</code> is null1626* @throws IllegalArgumentException1627* if <code>precision</code> or <code>decimalType</code> is invalid1628*/1629public static void convertExternalDecimalToPackedDecimal(1630byte[] externalDecimal, int externalOffset, byte[] packedDecimal,1631int packedOffset, int precision, int decimalType) {1632if ((externalOffset + CommonData.getExternalByteCounts(precision, decimalType) > externalDecimal.length) || (externalOffset < 0))1633throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1634"convertExternalDecimalToPackedDecimal is trying to access externalDecimal[" + externalOffset + "] to externalDecimal[" + (externalOffset + CommonData.getExternalByteCounts(precision, decimalType) - 1) + "], " +1635" but valid indices are from 0 to " + (externalDecimal.length - 1) + ".");16361637if ((packedOffset < 0) || (packedOffset + ((precision/ 2) + 1) > packedDecimal.length))1638throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1639"convertExternalDecimalToPackedDecimal is trying to access packedDecimal[" + packedOffset + "] to packedDecimal[" + (packedOffset + (precision/ 2)) + "], " +1640" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");16411642convertExternalDecimalToPackedDecimal_(externalDecimal, externalOffset, packedDecimal,1643packedOffset, precision, decimalType);1644}16451646private static void convertExternalDecimalToPackedDecimal_(1647byte[] externalDecimal, int externalOffset, byte[] packedDecimal,1648int packedOffset, int precision, int decimalType) {16491650boolean isNegative = isExternalDecimalSignNegative(externalDecimal, externalOffset, precision, decimalType);16511652if (decimalType < EXTERNAL_DECIMAL_MIN1653|| decimalType > EXTERNAL_DECIMAL_MAX)1654throw new IllegalArgumentException("invalid decimalType");1655if (precision <= 0)1656throw new IllegalArgumentException("negative precision");16571658int end = packedOffset + precision / 2;16591660// deal with sign leading1661if (decimalType == EBCDIC_SIGN_SEPARATE_LEADING) {1662externalOffset++;1663}16641665// handle even precision1666if (precision % 2 == 0) {1667packedDecimal[packedOffset++] = (byte) (externalDecimal[externalOffset++] & CommonData.LOWER_NIBBLE_MASK);1668}16691670for (int i = packedOffset; i < end; i++) {1671byte top = (byte) ((externalDecimal[externalOffset++] & CommonData.LOWER_NIBBLE_MASK) << 4);1672byte bottom = (byte) (externalDecimal[externalOffset++] & CommonData.LOWER_NIBBLE_MASK);1673packedDecimal[i] = (byte) (top | bottom);1674}16751676// deal with the last digit1677packedDecimal[end] = (byte) ((externalDecimal[externalOffset] & CommonData.LOWER_NIBBLE_MASK) << 4);16781679// Compute the sign1680if (isNegative)1681packedDecimal[end] |= CommonData.PACKED_MINUS;1682else1683packedDecimal[end] |= CommonData.PACKED_PLUS;1684}16851686/**1687* Convert an External Decimal in a byte array to a BigInteger. The sign of the input External Decimal is assumed to1688* to be positive unless the sign nibble or byte (depending on <code>decimalType</code>) contains one of the1689* negative sign codes, in which case the sign of the input External Decimal is interpreted as negative.1690*1691* Overflow can happen if the External Decimal value does not fit into the BigInteger. In this case, when1692* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1693* invalid result is returned.1694*1695* @param externalDecimal1696* byte array that holds the Packed Decimal to be converted1697* @param offset1698* offset in <code>externalDecimal</code> where the Packed Decimal is located1699* @param precision1700* number of decimal digits. Maximum valid precision is 2531701* @param checkOverflow1702* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the1703* specified precision (overflow)1704* @param decimalType1705* constant value indicating the type of External Decimal1706*1707* @return BigInteger the resulting BigInteger1708*1709* @throws ArrayIndexOutOfBoundsException1710* if an invalid array access occurs1711* @throws NullPointerException1712* if <code>externalDecimal</code> is null1713* @throws ArithmeticException1714* if <code>checkOverflow</code> is true and the result overflows1715* @throws IllegalArgumentException1716* if <code>decimalType</code> or <code>precision</code> is invalid, or the digital part of the input is1717* invalid.1718*/1719public static BigInteger convertExternalDecimalToBigInteger(1720byte[] externalDecimal, int offset, int precision,1721boolean checkOverflow, int decimalType) {1722byte[] packedDecimal = new byte[precision / 2 + 1];1723convertExternalDecimalToPackedDecimal(externalDecimal, offset,1724packedDecimal, 0, precision, decimalType);17251726int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0, precision,true, true);1727if (cc != 0)1728throw new IllegalArgumentException("The input External Decimal is not valid.");17291730return convertPackedDecimalToBigDecimal(packedDecimal, 0, precision, 0,1731checkOverflow).toBigInteger();1732}17331734/**1735* Converts an External Decimal in a byte array to a BigDecimal. The sign of the input External Decimal is assumed1736* to be positive unless the sign nibble or byte (depending on <code>decimalType</code>) contains one of the1737* negative sign codes, in which case the sign of the input External Decimal is interpreted as negative.1738*1739* Overflow can happen if the External Decimal value does not fit into the BigDecimal. In this case, when1740* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1741* invalid result is returned.1742*1743* @param externalDecimal1744* byte array holding the External Decimal to be converted1745* @param offset1746* offset in <code>externalDecimal</code> where the External Decimal is located1747* @param precision1748* number of decimal digits. Maximum valid precision is 2531749* @param scale1750* scale of the BigDecimal1751* @param checkOverflow1752* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the1753* specified precision (overflow)1754* @param decimalType1755* constant value that indicates the type of External Decimal1756*1757* @return BigDecimal the resulting BigDecimal1758*1759* @throws NullPointerException1760* if <code>externalDecimal</code> is null1761* @throws ArrayIndexOutOfBoundsException1762* if an invalid array access occurs1763* @throws ArithmeticException1764* if <code>checkOverflow</code> is true and the result overflows1765* @throws IllegalArgumentException1766* if <code>checkOverflow</code> is true and the Packed Decimal is in an invalid format, or the digital1767* part of the input is invalid.1768*/1769public static BigDecimal convertExternalDecimalToBigDecimal(1770byte[] externalDecimal, int offset, int precision, int scale,1771boolean checkOverflow, int decimalType) {1772if (precision <= 9) {1773return BigDecimal.valueOf(1774convertExternalDecimalToInteger(externalDecimal, offset, precision,1775checkOverflow, decimalType), scale);1776} else if (precision <= 18) {1777return BigDecimal.valueOf(1778convertExternalDecimalToLong(externalDecimal, offset, precision,1779checkOverflow, decimalType), scale);1780}17811782byte[] packedDecimal = new byte[precision / 2 + 1];1783convertExternalDecimalToPackedDecimal(externalDecimal, offset,1784packedDecimal, 0, precision, decimalType);17851786int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0, precision,true, true);1787if (cc != 0)1788throw new IllegalArgumentException("The input External Decimal is not valid.");17891790return convertPackedDecimalToBigDecimal(packedDecimal, 0, precision,1791scale, checkOverflow);1792}17931794private static boolean isExternalDecimalSignNegative(byte[] externalDecimal, int externalOffset,1795int precision, int decimalType)1796{1797byte signByte = 0;1798switch (decimalType)1799{1800case EBCDIC_SIGN_EMBEDDED_LEADING:1801signByte = (byte) (externalDecimal[externalOffset] & EXTERNAL_HIGH_MASK);1802if (signByte == CommonData.EXTERNAL_EMBEDDED_SIGN_MINUS ||1803signByte == CommonData.EXTERNAL_EMBEDDED_SIGN_MINUS_ALTERNATE_B)1804return true;1805break;18061807case EBCDIC_SIGN_EMBEDDED_TRAILING:1808signByte = (byte)(externalDecimal[externalOffset + precision - 1] & EXTERNAL_HIGH_MASK);1809if (signByte == CommonData.EXTERNAL_EMBEDDED_SIGN_MINUS ||1810signByte == CommonData.EXTERNAL_EMBEDDED_SIGN_MINUS_ALTERNATE_B)1811return true;1812break;18131814case EBCDIC_SIGN_SEPARATE_LEADING:1815signByte = externalDecimal[externalOffset];1816if (signByte == CommonData.EXTERNAL_SIGN_MINUS)1817return true;1818break;18191820case EBCDIC_SIGN_SEPARATE_TRAILING:1821signByte = externalDecimal[externalOffset + precision];1822if (signByte == CommonData.EXTERNAL_SIGN_MINUS)1823return true;1824break;18251826default:1827throw new IllegalArgumentException("Invalid decimal sign type.");1828}18291830return false;1831}18321833/**1834* Converts a Unicode Decimal value in a char array into a binary integer. The sign of the input Unicode Decimal is1835* assumed to be positive unless the sign char contains the negative sign code, in which case the sign of the1836* input Unicode Decimal is interpreted as negative.1837*1838* Overflow can happen if the Unicode Decimal value does not fit into a binary int. In this case, when1839* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1840* invalid result is returned.1841*1842* @param unicodeDecimal1843* char array which contains the Unicode Decimal value1844* @param offset1845* the offset where the Unicode Decimal value is located1846* @param precision1847* number of decimal digits. Maximum valid precision is 2531848* @param checkOverflow1849* if true an <code>ArithmeticException</code> or <code>IllegalArgumentException</code> may be thrown1850* @param unicodeType1851* constant value indicating the type of External Decimal1852*1853* @return int the resulting binary integer1854*1855* @throws NullPointerException1856* if <code>unicodeDecimal</code> is null1857* @throws ArrayIndexOutOfBoundsException1858* if an invalid array access occurs1859* @throws ArithmeticException1860* if <code>checkOverflow</code> is true and the result does not fit into a long (overflow)1861* @throws IllegalArgumentException1862* if <code>precision</code> or <code>decimalType</code> is invalid, or the digital part of the input is1863* invalid.1864*/1865public static int convertUnicodeDecimalToInteger(char[] unicodeDecimal,1866int offset, int precision, boolean checkOverflow, int unicodeType) {1867int size = unicodeType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;1868if ((offset + size > unicodeDecimal.length) || (offset < 0))1869throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1870"convertUnicodeDecimalToInteger is trying to access unicodeDecimal[" + offset + "] to unicodeDecimal[" + (offset + size - 1) + "], " +1871" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");18721873if (JITIntrinsicsEnabled()) {1874byte[] packedDecimal = new byte[precision / 2 + 1];1875convertUnicodeDecimalToPackedDecimal_(unicodeDecimal, offset,1876packedDecimal, 0, precision, unicodeType);1877int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0,1878precision, true, true);1879if (cc != 0)1880throw new IllegalArgumentException(1881"The input Unicode is not valid");18821883return convertPackedDecimalToInteger_(packedDecimal, 0, precision,1884checkOverflow);1885} else {1886return convertUnicodeDecimalToInteger_(unicodeDecimal, offset,1887precision, checkOverflow, unicodeType);1888}1889}18901891private static int convertUnicodeDecimalToInteger_(char[] unicodeDecimal,1892int offset, int precision, boolean checkOverflow, int unicodeType) {1893// Validate precision1894if (precision <= 0)1895throw new IllegalArgumentException("invalid precision");18961897// Validate decimalType and determine sign1898boolean positive = true;1899switch (unicodeType) {1900case UNICODE_UNSIGNED:1901break;1902case UNICODE_SIGN_SEPARATE_LEADING:1903positive = unicodeDecimal[offset++] == UNICODE_SIGN_PLUS;1904break;1905case UNICODE_SIGN_SEPARATE_TRAILING:1906positive = unicodeDecimal[offset + precision] == UNICODE_SIGN_PLUS;1907break;1908default:1909throw new IllegalArgumentException("invalid decimalType");1910}19111912int end = offset + precision;1913long val = 0;19141915// Trim leading 0s1916for (; offset < end && unicodeDecimal[offset] == UNICODE_ZERO; offset++) {1917precision--;1918}19191920// Preemptive check overflow: 10 digits in Integer.MAX_VALUE1921if (checkOverflow && precision > 10) {1922throw new ArithmeticException(1923"Decimal overflow - Unicode Decimal too large for an int");1924}19251926// Working in negatives as Integer.MIN_VALUE has a greater1927// distance from 0 than Integer.MAX_VALUE1928for ( ; offset < end; ++offset) {1929val *= 10;1930val -= unicodeDecimal[offset] & CommonData.LOWER_NIBBLE_MASK;1931}19321933// Normalize result1934val = positive ? -val : val;19351936// Check overflow1937if (checkOverflow && (val > Integer.MAX_VALUE || val < Integer.MIN_VALUE)) {1938throw new ArithmeticException(1939"Decimal overflow - Unicode Decimal too large for a int");1940}19411942return (int) val;1943}19441945/**1946* Converts a Unicode Decimal value in a char array into a binary long. The sign of the input Unicode Decimal is1947* assumed to be positive unless the sign char contains the negative sign code, in which case the sign of the1948* input Unicode Decimal is interpreted as negative.1949*1950* Overflow can happen if the Unicode Decimal value does not fit into a binary long. In this case, when1951* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or1952* invalid result is returned.1953*1954* @param unicodeDecimal1955* char array which contains the External Decimal value1956* @param offset1957* offset of the first byte of the Unicode Decimal in <code>unicodeDecimal</code>1958* @param precision1959* number of Unicode Decimal digits. Maximum valid precision is 2531960* @param checkOverflow1961* if true an <code>ArithmeticException</code> will be thrown when1962* @param unicodeType1963* constant value indicating the type of External Decimal1964*1965* @return long the resulting binary long value1966*1967* @throws NullPointerException1968* if <code>unicodeDecimal</code> is null1969* @throws ArrayIndexOutOfBoundsException1970* if an invalid array access occurs1971* @throws ArithmeticException1972* if <code>checkOverflow</code> is true and the result does not fit into a long (overflow)1973* @throws IllegalArgumentException1974* if <code>unicodeType</code> or <code>precision</code> is invalid, or the digital part of the input is1975* invalid.1976*/1977public static long convertUnicodeDecimalToLong(char[] unicodeDecimal,1978int offset, int precision, boolean checkOverflow, int unicodeType) {1979int size = unicodeType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;1980if ((offset + size > unicodeDecimal.length) || (offset < 0))1981throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +1982"convertUnicodeDecimalToLong is trying to access unicodeDecimal[" + offset + "] to unicodeDecimal[" + (offset + size - 1) + "], " +1983" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");19841985if (JITIntrinsicsEnabled()) {1986byte[] packedDecimal = new byte[precision / 2 + 1];1987convertUnicodeDecimalToPackedDecimal_(unicodeDecimal, offset,1988packedDecimal, 0, precision, unicodeType);19891990int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0, precision,true, true);1991if (cc != 0)1992throw new IllegalArgumentException("The input Unicode is not valid");19931994return convertPackedDecimalToLong_(packedDecimal, 0, precision,1995checkOverflow);1996} else {1997return convertUnicodeDecimalToLong_(unicodeDecimal, offset, precision, checkOverflow, unicodeType);1998}1999}20002001private static long convertUnicodeDecimalToLong_(char[] unicodeDecimal,2002int offset, int precision, boolean checkOverflow, int unicodeType) {2003// Validate precision2004if (precision <= 0)2005throw new IllegalArgumentException("invalid precision");20062007// Validate decimalType and determine sign2008boolean positive = true;2009switch (unicodeType) {2010case UNICODE_UNSIGNED:2011break;2012case UNICODE_SIGN_SEPARATE_LEADING:2013positive = unicodeDecimal[offset++] == UNICODE_SIGN_PLUS;2014break;2015case UNICODE_SIGN_SEPARATE_TRAILING:2016positive = unicodeDecimal[offset + precision] == UNICODE_SIGN_PLUS;2017break;2018default:2019throw new IllegalArgumentException("invalid decimalType");2020}20212022int end = offset + precision;2023long val = 0;20242025// Trim leading 0s2026for (; offset < end && unicodeDecimal[offset] == UNICODE_ZERO; offset++) {2027precision--;2028}20292030// Preemptive check overflow: 19 digits in Long.MAX_VALUE2031if (checkOverflow && precision > 19) {2032throw new ArithmeticException(2033"Decimal overflow - Unicode Decimal too large for a long");2034}20352036// Working in negatives as Long.MIN_VALUE has a greater2037// distance from 0 than Long.MAX_VALUE2038for ( ; offset < end; ++offset) {2039val *= 10;2040val -= unicodeDecimal[offset] & CommonData.LOWER_NIBBLE_MASK;2041}20422043// Normalize result2044val = positive ? -val : val;20452046// Check overflow2047if (checkOverflow) {2048if (positive && val < 0) {2049throw new ArithmeticException(2050"Decimal overflow - Unicode Decimal too large for a long");2051} else if (!positive && val > 0) {2052throw new ArithmeticException(2053"Decimal overflow - Unicode Decimal too small for a long");2054}2055}20562057return val;2058}20592060/**2061* Converts an Unicode Decimal in a char array to a Packed Decimal in a byte array. If the digital part of the input2062* Unicode Decimal is not valid then the digital part of the output will not be valid. The sign of the input Unicode2063* Decimal is assumed to be positive unless the sign byte contains the negative sign code, in which case the sign2064* of the input Unicode Decimal is interpreted as negative.2065*2066* @param unicodeDecimal2067* char array that holds the Unicode Decimal to be converted2068* @param unicodeOffset2069* offset in <code>unicodeDecimal</code> at which the Unicode Decimal is located2070* @param packedDecimal2071* byte array that will hold the Packed Decimal on a successful return2072* @param packedOffset2073* offset in <code>packedDecimal</code> where the Packed Decimal is expected to be located2074* @param precision2075* number of decimal digits2076* @param decimalType2077* constant value indicating the type of External Decimal2078*2079* @throws ArrayIndexOutOfBoundsException2080* if an invalid array access occurs2081* @throws NullPointerException2082* if <code>packedDecimal</code> or <code>unicodeDecimal</code> are null2083* @throws IllegalArgumentException2084* if <code>precision</code> or <code>decimalType</code> is invalid2085*/2086public static void convertUnicodeDecimalToPackedDecimal(2087char[] unicodeDecimal, int unicodeOffset, byte[] packedDecimal,2088int packedOffset, int precision, int decimalType) {2089int size = decimalType == DecimalData.UNICODE_UNSIGNED ? precision : precision + 1;2090if ((unicodeOffset + size > unicodeDecimal.length) || (unicodeOffset < 0))2091throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +2092"convertUnicodeDecimalToPackedDecimal is trying to access unicodeDecimal[" + unicodeOffset + "] to unicodeDecimal[" + (unicodeOffset + size - 1) + "], " +2093" but valid indices are from 0 to " + (unicodeDecimal.length - 1) + ".");2094if ((packedOffset < 0) || (packedOffset + ((precision/ 2) + 1) > packedDecimal.length))2095throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +2096"convertUnicodeDecimalToPackedDecimal is trying to access packedDecimal[" + packedOffset + "] to packedDecimal[" + (packedOffset + (precision/ 2)) + "], " +2097" but valid indices are from 0 to " + (packedDecimal.length - 1) + ".");20982099convertUnicodeDecimalToPackedDecimal_(unicodeDecimal, unicodeOffset,2100packedDecimal, packedOffset, precision, decimalType);2101}21022103private static void convertUnicodeDecimalToPackedDecimal_(2104char[] unicodeDecimal, int unicodeOffset, byte[] packedDecimal,2105int packedOffset, int precision, int decimalType) {21062107if (precision <= 0)2108throw new IllegalArgumentException("invalid precision");21092110int end = packedOffset + precision / 2;2111int signOffset = unicodeOffset;2112if (decimalType == UNICODE_SIGN_SEPARATE_LEADING) {2113unicodeOffset++;2114}2115// handle even precision2116if (precision % 2 == 0) {2117packedDecimal[packedOffset++] = (byte) (unicodeDecimal[unicodeOffset++] & CommonData.LOWER_NIBBLE_MASK);2118}21192120// compute all the intermediate digits2121for (int i = packedOffset; i < end; i++) {2122byte top = (byte) ((unicodeDecimal[unicodeOffset++] & CommonData.LOWER_NIBBLE_MASK) << 4);2123byte bottom = (byte) (unicodeDecimal[unicodeOffset++] & CommonData.LOWER_NIBBLE_MASK);2124packedDecimal[i] = (byte) (top | bottom);2125}2126packedDecimal[end] = (byte) ((unicodeDecimal[unicodeOffset++] & CommonData.LOWER_NIBBLE_MASK) << 4);21272128switch (decimalType)2129{2130case UNICODE_SIGN_SEPARATE_LEADING:2131if (unicodeDecimal[signOffset] == '-')2132packedDecimal[end] |= CommonData.PACKED_MINUS;2133else2134packedDecimal[end] |= CommonData.PACKED_PLUS;2135break;21362137case UNICODE_SIGN_SEPARATE_TRAILING:2138if (unicodeDecimal[unicodeOffset] == '-')2139packedDecimal[end] |= CommonData.PACKED_MINUS;2140else2141packedDecimal[end] |= CommonData.PACKED_PLUS;2142break;21432144case UNICODE_UNSIGNED:2145packedDecimal[end] |= CommonData.PACKED_PLUS;2146break;21472148default:2149throw new IllegalArgumentException("invalid decimalType");2150}2151}21522153/**2154* Convert a Unicode Decimal in a char array to a BigInteger. The sign of the input Unicode Decimal is assumed to2155* be positive unless the sign byte contains the negative sign code, in which case the sign of the input Unicode2156* Decimal is interpreted as negative.2157*2158* Overflow can happen if the Unicode Decimal value does not fit into a binary long. In this case, when2159* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2160* invalid result is returned.2161*2162* @param unicodeDecimal2163* char array that holds the Packed Decimal to be converted2164* @param offset2165* offset into <code>unicodeDecimal</code> where the Packed Decimal is located2166* @param precision2167* number of decimal digits. Maximum valid precision is 2532168* @param checkOverflow2169* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2170* specified precision (overflow)2171* @param decimalType2172* constant value indicating the type of External Decimal2173*2174* @return BigInteger the resulting BigInteger2175*2176* @throws ArrayIndexOutOfBoundsException2177* if an invalid array access occurs2178* @throws NullPointerException2179* if <code>unicodeDecimal</code> is null2180* @throws ArithmeticException2181* if <code>checkOverflow</code> is true and the result overflows2182* @throws IllegalArgumentException2183* if <code>decimalType</code> or <code>precision</code> is invalid, or the digital part of the input is2184* invalid.2185*/2186public static BigInteger convertUnicodeDecimalToBigInteger(2187char[] unicodeDecimal, int offset, int precision,2188boolean checkOverflow, int decimalType) {2189byte[] packedDecimal = new byte[precision / 2 + 1];2190convertUnicodeDecimalToPackedDecimal(unicodeDecimal, offset,2191packedDecimal, 0, precision, decimalType);21922193int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0, precision,true, true);2194if (cc != 0)2195throw new IllegalArgumentException("The input Unicode is not valid");21962197return convertPackedDecimalToBigDecimal(packedDecimal, 0, precision, 0,2198checkOverflow).toBigInteger();2199}22002201/**2202* Converts a Unicode Decimal in a char array to a BigDecimal. The sign of the input Unicode Decimal is assumed to2203* to be positive unless the sign byte contains the negative sign code, in which case the sign of the input Unicode2204* Decimal is interpreted as negative.2205*2206* Overflow can happen if the Unicode Decimal value does not fit into the BigDecimal. In this case, when2207* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2208* invalid result is returned.2209*2210* @param unicodeDecimal2211* char array that holds the Unicode Decimal2212* @param offset2213* offset in <code>unicodeDecimal</code> where the Unicode Decimal is located2214* @param precision2215* number of decimal digits. Maximum valid precision is 2532216* @param scale2217* scale of the returned BigDecimal2218* @param checkOverflow2219* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2220* specified precision (overflow)2221* @param decimalType2222* constant value indicating the type of External Decimal2223*2224* @return BigDecimal2225*2226* @throws NullPointerException2227* if <code>unicodeDecimal</code> is null2228* @throws ArrayIndexOutOfBoundsException2229* if an invalid array access occurs2230* @throws ArithmeticException2231* if <code>checkOverflow</code> is true and the result overflows2232* @throws IllegalArgumentException2233* if <code>checkOverflow</code> is true and the Packed Decimal is in an invalid format, or the digital2234* part of the input is invalid.2235*/2236public static BigDecimal convertUnicodeDecimalToBigDecimal(2237char[] unicodeDecimal, int offset, int precision, int scale,2238boolean checkOverflow, int decimalType) {2239byte[] packedDecimal = new byte[precision / 2 + 1];2240convertUnicodeDecimalToPackedDecimal(unicodeDecimal, offset,2241packedDecimal, 0, precision, decimalType);224222432244int cc = PackedDecimal.checkPackedDecimal(packedDecimal, 0, precision,true, true);2245if (cc != 0)2246throw new IllegalArgumentException("The input Unicode is not valid");22472248return convertPackedDecimalToBigDecimal(packedDecimal, 0, precision,2249scale, checkOverflow);2250}22512252/**2253* Converts a BigInteger value into a Packed Decimal in a byte array2254*2255* Overflow can happen if the BigInteger does not fit into the byte array. In this case, when2256* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2257* invalid result is returned.2258*2259* @param bigIntegerValue2260* BigInteger value to be converted2261* @param packedDecimal2262* byte array which will hold the Packed Decimal on a successful return2263* @param offset2264* offset into <code>packedDecimal</code> where the Packed Decimal is expected to be located2265* @param precision2266* number of decimal digits. Maximum valid precision is 253s2267* @param checkOverflow2268* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2269* specified precision (overflow)2270*2271* @throws NullPointerException2272* if <code>packedDecimal</code> is null2273* @throws ArrayIndexOutOfBoundsException2274* if an invalid array access occurs2275* @throws ArithmeticException2276* if <code>checkOverflow</code> is true and the result overflows2277*/2278public static void convertBigIntegerToPackedDecimal(2279BigInteger bigIntegerValue, byte[] packedDecimal, int offset,2280int precision, boolean checkOverflow) {2281convertBigDecimalToPackedDecimal(new BigDecimal(bigIntegerValue),2282packedDecimal, offset, precision, checkOverflow);2283}22842285/**2286* Converts a BigInteger value into an External Decimal in a byte array2287*2288* Overflow can happen if the BigInteger does not fit into the byte array. In this case, when2289* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2290* invalid result is returned.2291*2292* @param bigIntegerValue2293* BigInteger value to be converted2294* @param externalDecimal2295* byte array which will hold the External Decimal on a successful return2296* @param offset2297* offset into <code>externalDecimal</code> where the External Decimal is expected to be located2298* @param precision2299* number of decimal digits. Maximum valid precision is 2532300* @param checkOverflow2301* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2302* specified precision (overflow)2303* @param decimalType2304* constant value that indicates the type of External Decimal2305*2306* @throws NullPointerException2307* if <code>externalDecimal</code> is null2308* @throws ArrayIndexOutOfBoundsException2309* if an invalid array access occurs2310* @throws ArithmeticException2311* if <code>checkOverflow</code> is true and the result overflows2312* @throws IllegalArgumentException2313* if <code>decimalType</code> or <code>precision</code> is invalid2314*/2315public static void convertBigIntegerToExternalDecimal(2316BigInteger bigIntegerValue, byte[] externalDecimal, int offset,2317int precision, boolean checkOverflow, int decimalType) {2318byte[] packedDecimal = new byte[precision / 2 + 1];2319convertBigDecimalToPackedDecimal(new BigDecimal(bigIntegerValue),2320packedDecimal, 0, precision, checkOverflow);2321convertPackedDecimalToExternalDecimal(packedDecimal, 0,2322externalDecimal, offset, precision, decimalType);2323}23242325/**2326* Converts a BigInteger value to a Unicode Decimal in a char array2327*2328* Overflow can happen if the BigInteger does not fit into the char array. In this case, when2329* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2330* invalid result is returned.2331*2332* @param bigIntegerValue2333* BigInteger value to be converted2334* @param unicodeDecimal2335* char array that will hold the Unicode decimal on a successful return2336* @param offset2337* offset into <code>unicodeDecimal</code> where the Unicode Decimal is expected to be located2338* @param precision2339* number of decimal digits. Maximum valid precision is 2532340* @param checkOverflow2341* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2342* specified precision (overflow)2343* @param decimalType2344* constant indicating the type of External Decimal2345*2346* @throws NullPointerException2347* if <code>unicodeDecimal</code> is null2348* @throws ArrayIndexOutOfBoundsException2349* if an invalid array access occurs2350* @throws ArithmeticException2351* if <code>checkOverflow</code> is true and the result overflows2352* @throws IllegalArgumentException2353* if <code>decimalType</code> or <code>precision</code> is invalid2354*/2355public static void convertBigIntegerToUnicodeDecimal(2356BigInteger bigIntegerValue, char[] unicodeDecimal, int offset,2357int precision, boolean checkOverflow, int decimalType) {2358byte[] packedDecimal = new byte[precision / 2 + 1];2359convertBigDecimalToPackedDecimal(new BigDecimal(bigIntegerValue),2360packedDecimal, 0, precision, checkOverflow);2361convertPackedDecimalToUnicodeDecimal(packedDecimal, 0, unicodeDecimal,2362offset, precision, decimalType);2363}23642365/**2366* Converts a BigDecimal into a Packed Decimal in a byte array2367*2368* Overflow can happen if the BigDecimal does not fit into the result byte array. In this case, when2369* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2370* invalid result is returned.2371*2372* @param bigDecimalValue2373* the BigDecimal value to be converted2374* @param packedDecimal2375* byte array which will hold the Packed Decimal on a successful return2376* @param offset2377* desired offset in <code>packedDecimal</code> where the Packed Decimal is expected to be located2378* @param precision2379* number of decimal digits. Maximum valid precision is 2532380* @param checkOverflow2381* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2382* specified precision (overflow)2383*2384* @throws NullPointerException2385* if <code>packedDecimal</code> is null2386* @throws ArrayIndexOutOfBoundsException2387* if an invalid array access occurs2388* @throws ArithmeticException2389* if <code>checkOverflow</code> is true and the result overflows2390*/2391public static void convertBigDecimalToPackedDecimal(2392BigDecimal bigDecimalValue, byte[] packedDecimal, int offset,2393int precision, boolean checkOverflow) {23942395int bdprec = bigDecimalValue.precision();2396if (bdprec <=9)2397{2398convertIntegerToPackedDecimal((int) bigDecimalValue.unscaledValue().longValue(),2399packedDecimal, offset, precision, checkOverflow);2400return;2401}2402if (bdprec <= 18)2403{2404convertLongToPackedDecimal(bigDecimalValue.unscaledValue().longValue(),2405packedDecimal, offset, precision, checkOverflow);2406return;2407}24082409slowBigDecimalToSignedPacked(bigDecimalValue, packedDecimal, offset,2410precision, checkOverflow);2411}24122413/**2414* Converts a BigDecimal value to an External Decimal in a byte array2415*2416* Overflow can happen if the BigDecimal does not fit into the result byte array. In this case, when2417* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2418* invalid result is returned.2419*2420* @param bigDecimalValue2421* BigDecimal value to be converted2422* @param externalDecimal2423* byte array that will hold the External Decimal on a successful return2424* @param offset2425* offset in <code>externalDecimal</code> where the External Decimal is expected to be located2426* @param precision2427* number of decimal digits. Maximum valid precision is 2532428* @param checkOverflow2429* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2430* specified precision (overflow)2431* @param decimalType2432* constant value indicating the External Decimal type2433*2434* @throws NullPointerException2435* if <code>externalDecimal</code> is null2436* @throws ArrayIndexOutOfBoundsException2437* if an invalid array access occurs2438* @throws ArithmeticException2439* if <code>checkOverflow</code> is true and the result overflows2440* @throws IllegalArgumentException2441* if <code>precision</code> or <code>decimalType</code> is invalid2442*/2443public static void convertBigDecimalToExternalDecimal(2444BigDecimal bigDecimalValue, byte[] externalDecimal, int offset,2445int precision, boolean checkOverflow, int decimalType) {24462447int bdprec = bigDecimalValue.precision();2448if (bdprec <=9)2449{2450convertIntegerToExternalDecimal((int) bigDecimalValue.unscaledValue().longValue(),2451externalDecimal, offset, precision, checkOverflow, decimalType);2452return;2453}2454if (bdprec <= 18)2455{2456convertLongToExternalDecimal(bigDecimalValue.unscaledValue().longValue(),2457externalDecimal, offset, precision, checkOverflow, decimalType);2458return;2459}24602461byte[] packedDecimal = new byte[precision / 2 + 1];2462convertBigDecimalToPackedDecimal(bigDecimalValue, packedDecimal, 0,2463precision, checkOverflow);2464convertPackedDecimalToExternalDecimal(packedDecimal, 0,2465externalDecimal, offset, precision, decimalType);2466}24672468/**2469* Converts a BigDecimal value to a Unicode Decimal in a char array2470*2471* Overflow can happen if the BigDecimal does not fit into the result char array. In this case, when2472* <code>checkOverflow</code> is true an <code>ArithmeticException</code> is thrown, when false a truncated or2473* invalid result is returned.2474*2475* @param bigDecimalValue2476* BigDecimal value to be converted2477* @param unicodeDecimal2478* char array which will hold the Unicode Decimal on a successful return2479* @param offset2480* offset in <code>unicodeDecimal</code> where the Unicode Decimal is expected to be located2481* @param precision2482* number of decimal digits. Maximum valid precision is 2532483* @param checkOverflow2484* if true an <code>ArithmeticException</code> will be thrown if the decimal value does not fit in the2485* specified precision (overflow)2486* @param decimalType2487* constant value that indicates the type of External Decimal2488*2489* @throws NullPointerException2490* if <code>unicodeDecimal</code> is null2491* @throws ArrayIndexOutOfBoundsException2492* if an invalid array access occurs2493* @throws ArithmeticException2494* if <code>checkOverflow</code> is true and the result overflows2495* @throws IllegalArgumentException2496* if <code>decimalType</code> or <code>precision</code> is invalid2497*/2498public static void convertBigDecimalToUnicodeDecimal(2499BigDecimal bigDecimalValue, char[] unicodeDecimal, int offset,2500int precision, boolean checkOverflow, int decimalType) {2501byte[] packedDecimal = new byte[precision / 2 + 1];2502convertBigDecimalToPackedDecimal(bigDecimalValue, packedDecimal, 0,2503precision, checkOverflow);2504convertPackedDecimalToUnicodeDecimal(packedDecimal, 0, unicodeDecimal,2505offset, precision, decimalType);2506}25072508// below is code taken from BigDecimalConverters2509// these are special functions recognized by the jit2510private static boolean DFPFacilityAvailable() {2511return false;2512}25132514private static boolean DFPUseDFP() {2515return false;2516}25172518private static BigDecimal createZeroBigDecimal() {2519return new BigDecimal(0); // don't use BigDecimal.ZERO, need a new2520// object every time2521}25222523private static boolean DFPConvertPackedToDFP(BigDecimal bd, long pack,2524int scale, boolean signed) {2525return false;2526}25272528private static long DFPConvertDFPToPacked(long dfpValue, boolean signed) {2529return Long.MAX_VALUE;2530}25312532private final static int getflags() {2533return 0x3;2534}25352536private final static long getlaside(BigDecimal bd) {2537return Long.MIN_VALUE;2538}25392540private static BigDecimal slowSignedPackedToBigDecimal(byte[] byteArray,2541int offset, int precision, int scale, boolean exceptions) {254225432544int length = (precision + 2) / 2;25452546int sn = byteArray[offset + length - 1] & CommonData.LOWER_NIBBLE_MASK;25472548char[] temp = new char[length * 2];2549temp[0] = (sn == 0x0D || sn == 0x0B) ? '-' : '0';2550for (int i = 0; i < length - 1; i++) {2551temp[2 * i + 1] = (char) ('0' + (byteArray[i + offset] >>> 4 & CommonData.LOWER_NIBBLE_MASK));2552temp[2 * i + 2] = (char) ('0' + (byteArray[i + offset] & CommonData.LOWER_NIBBLE_MASK));2553}2554temp[length * 2 - 1] = (char) ('0' + (byteArray[offset + length - 1] >>> 4 & CommonData.LOWER_NIBBLE_MASK));25552556return new BigDecimal(new BigInteger(new String(temp)), scale);2557}25582559private static void slowBigDecimalToSignedPacked(BigDecimal bd,2560byte[] byteArray, int offset, int precision, boolean checkOverflow) {25612562// digits are right justified in the return byte array2563if (checkOverflow && precision < bd.precision())2564throw new ArithmeticException(2565"Decimal overflow - precision of result Packed Decimal lesser than BigDecimal precision");25662567BigInteger value = bd.unscaledValue();2568char[] buffer = value.abs().toString().toCharArray();2569int numDigitsLeft = buffer.length - 1;2570int endPosition = numDigitsLeft % 2;2571int length = (precision + 2) / 2;2572int index = length - 2;25732574// take care of the sign nibble and the right most digit2575byteArray[offset + length - 1] = (byte) ((buffer[numDigitsLeft] - '0') << 4);2576byteArray[offset + length - 1] |= ((value.signum() == -1) ? 0x0D : 0x0C);25772578// compact 2 digits into each byte2579for (int i = numDigitsLeft - 1; i >= endPosition2580&& (offset + index >= 0); i -= 2, --index) {2581byteArray[offset + index] = (byte) (buffer[i] - '0');2582byteArray[offset + index] |= (byte) ((buffer[i - 1] - '0') << 4);2583}25842585// if there's a left over digit, put it in the last byte2586if (endPosition > 0 && (offset + index >= 0)) {2587byteArray[offset + index] = (byte) (buffer[0] - '0');2588}2589}25902591/*2592* Converts the Packed Decimal to equivalent long (in hex).2593*/2594private static long convertPackedToLong(byte[] byteArray, int offset,2595int length) {2596if (length == 8) {2597return ByteArrayUnmarshaller.readLong(byteArray, offset, true);2598} else if (length == 4) {2599// We need to zero extend the int to long.2600return ((long) ByteArrayUnmarshaller.readInt(byteArray, offset,2601true)) & 0xFFFFFFFFl;2602}26032604else {2605// slow way to load value into dfp2606long value = 0;2607for (int i = 0; i < length; ++i) {2608value = value << 8;2609value += ((long) (byteArray[offset + i] & 0xFF));2610}2611return value;2612}2613}26142615private static void convertLongToPacked(long value, byte[] byteArray,2616int offset, int length) {2617if (length == 8) {2618ByteArrayMarshaller.writeLong(value, byteArray, offset, true);2619} else if (length == 4) {2620ByteArrayMarshaller.writeInt((int) value, byteArray, offset, true);2621} else {2622for (int i = length - 1; i <= 0; i--) {2623byteArray[offset + i] = (byte) ((value) & 0xFF);2624value = value >> 8;2625}2626}2627}26282629}263026312632