0

I have a problem while unpacking the comp3 digits in a file which is extracted from the legacy system(main frame). I tried the code which was given by a fellow stack overflow member @Jose Ventura but it didnt work. I tried to print the unpacked data but nothing got printed. I am totally new to this concept(comp 3). So can you guys help me to achieve this task

Below is my code


    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import org.apache.commons.io.FileUtils;

    public class TestComp3 {
        private static String unpackData(byte[] packedData) {

            int decimals = 2;
            String unpackedData = "";
            final int negativeSign = 13;
            int lengthPack = packedData.length;
            int numDigits = lengthPack * 2 - 1;

            int raw = (packedData[lengthPack - 1] & 0xFF);
            int firstDigit = (raw >> 4);
            int secondDigit = (packedData[lengthPack - 1] & 0x0F);
            boolean negative = (secondDigit == negativeSign);
            int lastDigit = firstDigit;
            for (int i = 0; i < lengthPack - 1; i++) {
                raw = (packedData[i] & 0xFF);
                firstDigit = (raw >> 4);
                secondDigit = (packedData[i] & 0x0F);
                unpackedData += String.valueOf(firstDigit);
                unpackedData += String.valueOf(secondDigit);

            }
            unpackedData += String.valueOf(lastDigit);
            if (decimals > 0) {
                unpackedData = unpackedData.substring(0, numDigits - decimals) + "."
                        + unpackedData.substring(numDigits - decimals);
            }
            if (negative) {
                // System.out.println("unpacked data :-"+unpackedData);
                System.out.println("-" + unpackedData);
                return '-' + unpackedData;

            }
            System.out.println(unpackedData);
            return unpackedData;
        }
    public static void main(String[] args) {

            Path path = Paths.get("C:\\Users\\AV00499269\\Desktop\\Comp3 data file\\KYC.txt");

            try {
                byte[] data = Files.readAllBytes(path);
                TestComp3.unpackData(data);
            } catch (IOException e1) {
                // TODO Auto-generated catch block

                e1.printStackTrace();
            }

        }

    }
  • Looking at the picture, I am unsure where the packed decimal data is. At offset x'25' are the characters x'2C' which look like the end of a packed-decimal number. If so, then that number is positive 2. Before it you would have any number of x'00' characters which in packed decimal are 00. – James Nov 28 '18 at 06:15
  • 1
    You are treating the whole `record` as one big comp-3 number. its **not** one big comp-3 number. Do you have a **file description** - ideally Cobol. Either way try Record – Bruce Martin Nov 28 '18 at 07:05
  • 1
    @Ashwinivijaykumar So it looks like you've been given an entire record, but only some of it is packed decimal. The @ characters at the end are x'40', which in EBCDIC is a space. At the start you have some codes which might be two full word integers, but that's a guess. Starting at x'10' (the second line) I can see some "zoned decimal" numbers, x'F1F9F0F0' which are '1900'. But really we're guessing as to what the numbers are. As Bruce Martin says, you need to get the description of the record. – James Nov 28 '18 at 07:15
  • Okay @James can we convert the file(image which i added above) to a readable format(csv or text file)? – Ashwini vijaykumar Nov 28 '18 at 07:21
  • 2
    Get your comp-3 data converted to DISPLAY format BEFORE it is sent to you. If the data contains decimals then ensure that the data you receive includes the decimal point. EBCDIC to non-EBCDIC translation can make a mess of comp-3 values unles transferred as BIN in which case the non-comp3 values do not get translated. from EBCDIC. If you are actually working in EBCDIC an it is only the comp-3 values that are the problem then get that data converted. – NicC Nov 28 '18 at 09:37
  • IBM Record Generator for Java might be useful. It takes these structures and gives you a Java helper class. You give the class a byte array and can then access your variables appropriately based on what they are (String, int, float et cetera). https://developer.ibm.com/mainframe/products/record-generator-for-java/ – James Nov 29 '18 at 13:58
  • @James can you tell me the comp value of decimal value 19? – Ashwini vijaykumar Dec 03 '18 at 06:16
  • @Ashwinivijaykumar So That would be two bytes. x'019F' for unsigned, x'019C' for positive and x'019D' for negative. The last half byte is the sign field. – James Dec 03 '18 at 08:26
  • @James comp and comp 3 values for decimal value 19 differ or not? Could you help? Since I also need the comp 3 value of 19. – Ashwini vijaykumar Dec 03 '18 at 12:35
  • @Ashwinivijaykumar Ah yes, so I gave you the PACKED-DECIMAL or COMP3 value x'019F. For COMP (which is basically binary), that would be x'0013' if it was a short or PIC S9(4) COMP. – James Dec 03 '18 at 12:57
  • Thanks @James for the response . Can you tell me how to calculate the comp and comp 3 value of any numeric? – Ashwini vijaykumar Dec 04 '18 at 05:56
  • @Ashwinivijaykumar sure, (but don't forget to upvote if I've been helpful). COMP values are just binary. You can use the calculator tool in Windows to do that and that's pretty straightforward. You just need to switch to programmer mode. F5 will give you hexadecimal, F6 will give you decimal. So 12345 in decimal is x'3039' in COMP/binary. For COMP3, packed-decimal, it is one half-byte per digit, plus a sign. So 12345 would be x'12345F' for unsigned, x'12345C' for positive, x'12345D' for negative. Add zeroes at the front to pad. – James Dec 04 '18 at 08:37
  • Thanks @James. I want to decode this "õõ"_ ua?". Can you help. I dont know what kind of data this is. This is extracted from mainframe which is a comp 3 field – Ashwini vijaykumar Dec 04 '18 at 11:03
  • @Ashwinivijaykumar so for that you really want access to a hexadecmal editor. "a?" would be x'816F' if you look at it in EBCDIC, which is 816 unsigned. But characters like that get confused. If you have access to the outputted data on the mainframe, you can view it in hexadecimal mode. – James Dec 04 '18 at 11:16
  • õõ"_ SOHua? @James Can you tell me in which format this is? Is it encoded? – Ashwini vijaykumar Dec 04 '18 at 12:32
  • I can't tell. It is either binary or packed-decimal. As I said earlier "a?" suggests that it MIGHT be packed decimal, as that would be 816 unsigned. But you really need to access the data in hexadecimal mode. The mainframe system has interactive editors that will let you do that. – James Dec 04 '18 at 14:58
  • @James can you explain me the logic to unpack comp 3 values with sm example, it will be very useful for me. Thanks – Ashwini vijaykumar Dec 05 '18 at 09:50
  • @Ashwinivijaykumar I have, several times (above) but the comments haven't been marked as useful. (but don't forget to upvote if I've been helpful). For COMP3, packed-decimal, it is one half-byte per digit, plus a sign. So 12345 would be x'12345F' for unsigned, x'12345C' for positive, x'12345D' for negative. Add zeroes at the front to pad. – James Dec 05 '18 at 09:55
  • Thanks @James Can you explain with a java program because I couldnt understand the logic to unpack comp 3 field values available in net. I find them a bit complex. Thanks and definitely I will upvote your comments – Ashwini vijaykumar Dec 05 '18 at 10:06
  • @Ashwinivijaykumar it's the small triangle to the left of the comment. I've upvoted yours as an example. I've not got a Java program to explain the logic to hand unfortunately. But the structure is something like this. A Packed-Decimal (COMP-3) number is X bytes long. There are (X * 2) - 1 digits in the number, and one sign. Each digit (and the sign) are 4 bits. Each digit will be from zero to nine, so will be b'0000' to b'1001'. The sign can only be x'C', x'D' or x'F' and is the last four bits of the number. That will be b'1100' for C, b'1101' for D or b'1111' for F. – James Dec 05 '18 at 10:14
  • @Ashwinivijaykumar Fair enough. I'm in a web browser so I get the "upvote" and the "flag". The flag is for "serious problems and moderator attention", if I was being rude for example. The other icon is for "This comment adds something useful to the post". THIS comment doesn't add anything useful to the post for example. – James Dec 05 '18 at 10:30
  • @James I am also using stackoverflow through google chrome(web browser) – Ashwini vijaykumar Dec 05 '18 at 12:46
  • @Ashwinivijaykumar so in my Google Chrome, the upvote icon is to the left of the first line of every comment, just above the flag. It's not that important to be fair. – James Dec 05 '18 at 13:05
  • @James I have a doubt. I have a mainframe file which is in ebcdic format. To Convert that to numeric should I have to convert the ebcdic file to binary. Because I dont understand the file. Its totally greek and latin for me – Ashwini vijaykumar Dec 19 '18 at 05:39
  • @Ashwinivijaykumar if it is in EBCDIC then you need to leave it as binary (not convert it). If you FTP it from the mainframe to your PC, select "binary" and it will NOT convert it. This will leave all the bytes as they are. I find it helpful to look for @ characters. For some reason, @ in EBCDIC is space in ASCII, and space in EBCDIC is @ in ASCII. So if you see a lot of @@@@@@@ symbols, you're probably looking at it in the wrong codepage. – James Dec 19 '18 at 07:36
  • @James the file looks something like this " Áöðöóóðððùõøùõõ" " , how do I convert this to numeric. I don't have the mainframe file in binary format. Hope you understand – Ashwini vijaykumar Dec 19 '18 at 07:51
  • @Ashwinivijaykumar You'll need access to a hexadecimal editor which should let you see what the actual byte codes are. You'll also need to know how the mainframe file is laid out, as there can be strings, floats, integers and packed decimal numbers there too. – James Dec 19 '18 at 14:22

1 Answers1

0

Your problem is that you are trying to take the string value of the unpacked nibbles, and those will be non-printable control characters.

Treat your packed number as a byte array, for each byte:

int endValue = 0;

for (int I = 0, I< packed.length; I++) {
  byte high = packed[I] & 0xF0;
  byte low  = packed[I] & 0x0F;
  endValue = (endValue * 10) + (high * 10) + low;
}

System.out.println("The int value is: " + endValue)

Depending on the source system, you will need to special case the sign nibble, and multiply by -1 if it is negative, but I'll leave that as a special exercise for the reader.

Joe Zitzelberger
  • 4,238
  • 2
  • 28
  • 42