0

I referred a code on the internet to unpack comp 3 to numeric in java. I tried to pass a sample comp3 file to the code but I didn't get the proper unpacked data. I got some weird numbers. I am new to this concept(comp 3) so can you guys help me on this. Thanks in advance

Below is my code


import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Converts between integer and an array of bytes in IBM mainframe packed
 * decimal format. The number of bytes required to store an integer is (digits +
 * 1) / 2. For example, a 7 digit number can be stored in 4 bytes. Each pair of
 * digits is packed into the two nibbles of one byte. The last nibble contains
 * the sign, 0F for positive and 0C for negative. For example 7654321 becomes
 * 0x76 0x54 0x32 0x1F.
 * 
 * This class is immutable. Once constructed you can extract the value as an
 * int, an array of bytes but you cannot change the value. Someone should
 * implement equals() and hashcode() to make this thing truly useful.
 */

public class PackedDecimalToComp {

    public static void main(String[] args) {

        try {
            // test.unpackData(" 0x12345s");
            Path path = Paths.get("C:\\Users\\AV00499269\\Desktop\\Comp3 data file\\Comp3Test.txt");
            byte[] data = Files.readAllBytes(path);
            PackedDecimalToComp test = new PackedDecimalToComp();
            test.unpackData(data);
        } catch (Exception ex) {
            System.out.println("Exception is :" + ex.getMessage());
        }    
    }

    private static String unpackData(byte[] packedData) {
        String unpackedData = "";

        final int negativeSign = 13;
        for (int currentCharIndex = 0; currentCharIndex < packedData.length; currentCharIndex++) {
            byte firstDigit = (byte) ((packedData[currentCharIndex] >>> 4) & 0x0F);
            byte secondDigit = (byte) (packedData[currentCharIndex] & 0x0F);
            unpackedData += String.valueOf(firstDigit);
            if (currentCharIndex == (packedData.length - 1)) {
                if (secondDigit == negativeSign) {
                    unpackedData = "-" + unpackedData;
                }
            } else {
                unpackedData += String.valueOf(secondDigit);
            }
        }
        System.out.println("Unpackeddata is :" + unpackedData);

        return unpackedData;
    }    
}

Comp3 file I passed has values x019F

When converted I got the unpacked data as 783031394

SaggingRufus
  • 1,814
  • 16
  • 32
  • The method `unpackData` looks to be working; your problem is elsewhere. Check the file in the **RecordEditor** (https://sourceforge.net/projects/record-editor/) to make sure that is correct – Bruce Martin Dec 06 '18 at 06:00
  • @BruceMartin when i unpack the comp 3 field value x019F I should get the unpacked data as 19 right? Since I am new to comp3 I have this doubt and can you explain me the logic used here in the above code. I don't have much clarity on that – Ashwini vijaykumar Dec 06 '18 at 06:16
  • @BruceMartin is there any alternate editor available for RecordEditor because my organisation doesn't allow to install RecordEditor – Ashwini vijaykumar Dec 06 '18 at 07:38
  • Use a hex editor then – Bruce Martin Dec 06 '18 at 10:17
  • 1
    The problem is you have the **ascii string` x019F = x'7830313946'** hex in your file. You need to put **binary 019F** in the file. The easiest way is to write it with a java program – Bruce Martin Dec 06 '18 at 10:30
  • @BruceMartin I put 019F in the file but the output i got was "3058324" – Ashwini vijaykumar Dec 06 '18 at 10:38
  • Yes you put the **character string** 019F in the file you need to put the **hex** string x'019F' in the file. Either use a **hex editor** or write a java program that writes 2 bytes 0x01 and 0x9F to a FileOutputStream. **Do not** use a text editor to create the file. Comp-3 is a **binary** type – Bruce Martin Dec 06 '18 at 10:51
  • Thanks @BruceMartin, could you tell me what is the comp 3 value of decimal number 19? I just want to know how the value will be. – Ashwini vijaykumar Dec 06 '18 at 11:23
  • The first byte will be 0x01, the second byte will be one of 0x9F - *unsigned comp-3* or 0x9C *signed comp-3* – Bruce Martin Dec 06 '18 at 12:17
  • @BruceMartin Do you have any java code which can convert comp 3 value (0x01 0x9F) to numeric (19) because I don't understand the code which i have mentioned above – Ashwini vijaykumar Dec 06 '18 at 12:46
  • 1
    Note that a packed decimal negative sign code can be X’B’ (11), or X‘D‘ (13). Both values are accepted as input to packed decimal instructions. Similarly, X‘A‘, X‘C‘, X‘E‘, and X‘F‘ all represent valus positive sign codes. – phunsoft Dec 06 '18 at 14:47
  • 1
    I was playing around with the code and it seems to be working as you'd expect ... can you give an example of the file and a hexdump of what isn't working ? – Hogstrom Dec 07 '18 at 02:01
  • Hi @Hogstrom I need to write a basic java class which converts a comp 3 field value to numeric value . Ex: I need to convert 0x01 0x9F(comp3) to 19(numeric). If you have any sample code, can you share me. I dont understand the code which is available in the internet(mentioned above) and i am new to COBOL – Ashwini vijaykumar Dec 07 '18 at 04:11
  • @phunsoft I have a doubt if we unpack the comp-3 value say(0x01 0x9F), what will be the unpacked value, I mean in which format the value will be. Based on the code I mentioned can you say in which format the result unpacked data would be. Thanks in advance – Ashwini vijaykumar Dec 07 '18 at 10:39
  • @phunsoft from what I can see your code is working. it reads the data and calculates how you'd expect ... if you have an example of the file your trying to convert that would be helpful – Hogstrom Dec 07 '18 at 21:07
  • @Hogstrom I have a doubt can you tell me if I unpack a comp 3 value say 0x01 0x9F will I get the numeric value 19 or some other value in different format, because I tried that with the code mentioned above but I got some random number, can you help on that – Ashwini vijaykumar Dec 08 '18 at 14:03
  • @Hogstrom I have a mainframe file which is in ascii, in that there are comp 3 digits in certain field positions. How can i convert that ascii to comp3 and then unpack those comp3 field values. Can you help on this? – Ashwini vijaykumar Dec 10 '18 at 04:22
  • Comp-3 is really a binary format. In COBOL you can have multiple data types include COMP, COMP-3, CHAR, ... it sounds like you have a file that has a mix of data types. CHAR could be converted to ASCII / UTF-8, etc. The Comp-3 is binary so you'd need to know the offset and length of those data elements. I'm not sure I understand if you have a file that has multiple data types or not. @BruceMartin's answer below is probably your best bet if your dealing with complex copybooks. – Hogstrom Dec 10 '18 at 20:12
  • Yeah okay @Hogstrom – Ashwini vijaykumar Dec 11 '18 at 10:21
  • @BruceMartin 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:36
  • @Hogstrom 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 06:09

2 Answers2

2

You can use the IBM Record Generator for Java, a free tool.

This allows you to generate a Java class that represents a COBOL or PL/I DSECT which you can then use in your own code to read/write values to most COBOL and PL/I data types. If you aren't working with a structure then you can see through the code how the underlying JZOS classes are used to interact with the datatype.

Although the tool is free it is supported by IBM, so if you hit an issue you can raise a problem with IBM and they will fix it.

Ben Cox
  • 1,393
  • 10
  • 28
Will Yates
  • 131
  • 3
0

Handling Mainframe binary file

You have 2 options:

  • Convert the file to a Text file on the mainframe and then transfer the file
  • Do a binary transfer and keep the file as EBCDIC then use something like JRecord to read the file. You can also use RecordEditor to edit the file

I have also seen files converted to Unix EBCDIC Text files on the mainframe and a binary Transfer (keep as EBCDIC). This is done for non-English EBCDIC where you have special language specific characters. Java editors (e.g. JEdit) have no trouble editing Unix Ebcdic files

File Transfer (Mainframe)

To transfer a Binary file (has comp, comp-3 etc) from the Mainframe to Windows / *nix box you must do a Binary Transfer for a very simple reason: the Ebcdic --> Ascii program can not distinguish between binary fields and Text fields.

Comp-3 value   hex     hex after Ascii conversion

 400          x'400c'       x'200c'       x'40' is the ebcdic space character
                                          it gets converted to the ascii
                                          space character x'20'

You need to do a Binary transfer from the Mainframe. This will keep the file as EBCDIC and any binary fields will be untouched. You then read the file using Ebcdic.

You will need to check the RECFM on the Mainframe. If the RECFM is

  • FB - no problems just transfer
  • VB - either convert to FB on the mainframe of include the RDW (Record Descriptor Word) option in the file transfer.
  • Other - Convert to FB/VB on the mainframe

RecordEditor

  • Make sure you have Java installed
  • You can get the RecordEditor from here. You can either download an installer or the USB version. The USB version is a zipped Directory which you can install in any normal directory.

Using The Record Editor

You need to define the Record Layout (or file schema). The easiest way is to import a Cobol Copybook.

For a 2 byte comp-3 field, create a cobol copybook with

        01  Tst-Record.
            03  comp3-field              pic s9(3) comp-3.

To import the cobol copybook Select Record Layouts >>> Load Cobol Copybook

Cobol import

Then enter the Cobol copybook file name and press the load Cobol button at the bottom of the screen

enter image description here

Next go the file open screen and enter the file name and select the copybook you have just imported:

enter image description here

Hit enter and you should be able update the file:

enter image description here

Generating Code

The RecordEditor can also generate code for the JRecord Library. See How do you generate java~jrecord code for a Cobol copybook for hot to generate Java~JRecord Code using a Cobol Copybook.

You can also generate Code that does not use a Cobol Copybook wile editting the file:

Select Generate >>> Generate Code from the File option. Thene select a template and enter a package Id

enter image description here

Bruce Martin
  • 10,358
  • 1
  • 27
  • 38