How to unpack COMP-3 digits using Java?

Shekhar picture Shekhar · Dec 3, 2013 · Viewed 13.2k times · Source

I have huge mainframe file and there are some packed digits in that file. I would like to know how to unpack following digit using java?

packed digit : ?

I read tutorials for unpacking digits and found the following rule to count the number of bytes required to unpack digits :

total_number_of_bytes = (no. of digits + 1) / 2

I wrote the following code to unpack digits :

public String unpackData(String packedData, int decimalPointLocation) {
        String unpackedData = "";
        char[] characters = packedData.toCharArray();
        final int impliedPositive = 15;
        final int positiveNumber = 12;
        final int negativeNumber = 13;
        for (int currentCharIndex = 0; currentCharIndex < characters.length; currentCharIndex++) {
            byte[] unpackedDigits = unpackByte((byte) characters[currentCharIndex]);
            if(currentCharIndex == (characters.length - 1)) {
                if(unpackedDigits[1] == impliedPositive || unpackedDigits[1] == positiveNumber) {
                    unpackedData += String.valueOf(unpackedDigits[0]);
                } else if(unpackedDigits[1] == negativeNumber) {
                    unpackedData = "-" + unpackedData;
                }
            } else {
                unpackedData += String.valueOf(unpackedDigits[0]) + String.valueOf(unpackedDigits[1]);
            }
        }
        if(decimalPointLocation > 0) {
            unpackedData = unpackedData.substring(0, (decimalPointLocation - 1)) + 
                            "." + 
                            unpackedData.substring(decimalPointLocation);
        }
        return unpackedData;
    }

    private byte[] unpackByte(byte packedData) {
        byte firstDigit = (byte) (packedData >>> 4);
        firstDigit = setBitsToZero(firstDigit, 4, 8);

        //System.out.println(" firstDigit = "+ firstDigit + ", and its bit string after unpacking = " + getBitString(firstDigit, 7));

        byte secondDigit = setBitsToZero(packedData, 4, 8);
        //System.out.println("second digit = " + secondDigit + ", and its bit string of second digit after unpcking = " + getBitString(secondDigit, 7));

        byte[] unpackedData = new byte[2];
        unpackedData[0] = firstDigit;
        unpackedData[1] = secondDigit;
        return unpackedData;
    }

    private byte setBitsToZero(byte number, int startBitPosition, int endBitPosition) {
        for (int i = startBitPosition; i < endBitPosition; i++) {
            number =  (byte) (number & ~(1 << i));
        }
        return number;
    }

This program works correctly for integer type values but it's not working for floating point type values.

Can anyone please tell if my program is correct?

Answer

Ross Patterson picture Ross Patterson · Dec 3, 2013

COMP-3 (or "packed decimal") data looks like this: 0x12345s, where "s" is C for positive, D for negative, or F for unsigned. Thus 0x12345c -> "12345", x012345d -> "-12345", and 0x12345f -> "12345".

You've got one obvious error: You're ignoring the nybble in the byte that contains the sign nybble (e.g., "5" above) if the sign is negative. In addition, you're working too hard at manipulating the nybbles, it's a simple bitwise-and or a 4-bit shift to isolate a nybble.

Try something like this (untested):

public String unpackData(String packedData, int decimalPointLocation) {
    String unpackedData = "";
    char[] characters = packedData.toCharArray();
    final int negativeSign = 13;
    for (int currentCharIndex = 0; currentCharIndex < characters.length; currentCharIndex++) {
        byte firstDigit = ((byte) characters[currentCharIndex]) >>> 4);
        byte secondDigit = ((byte) characters[currentCharIndex]) & 0x0F;
        unpackedData += String.valueOf(firstDigit);
        if (currentCharIndex == (characters.length - 1)) {
            if (secondDigit == negativeSign) {
                unpackedData = "-" + unpackedData;
            }
        } else {
            unpackedData += String.valueOf(secondDigit);
        }
    }
    if (decimalPointLocation > 0) {
        unpackedData = unpackedData.substring(0, (decimalPointLocation - 1)) + 
                        "." + 
                        unpackedData.substring(decimalPointLocation);
    }
    return unpackedData;
}