-2

Message variable length indicator (VLI) 2 bytes precede every message sent to/from BizSwitch. The 2 bytes are referred to as a variable length indicator. Bytes 1-2 indicate the number of bytes in the message (excluding the first 2 bytes). The 2 bytes represent a 16bit unsigned integer in network byte order. Note that if a compressed message is being sent, the message will have to first be compressed, in order to determine its length, before being sent. As an example, suppose that you were to look at just the text (excluding the 2 byte header) making up an XML message from a particular example and that you then counted the characters and they happened to add up to 299 characters. If you took a scientific calculator (the one in Windows for example) and you typed in 299 with "Dec" (for decimal) selected, then you select "Hex", the value that would be shown is "12B", which means the same as 01 2B, which is exactly what one would expect to see for the first two bytes of the message if the message had been dumped to a file and then opened with a hex editor. Example java code for calculating a VLI:

public byte[] wrap(byte[] msg) throws Exception {
    int len = msg.length;
    if (len > 65535) {
        throw new IllegalArgumentException("Exceeds 65535 bytes.");
    }
    byte firstByte = (byte)(len >>> 8);
    byte secondByte = (byte)len;
    ByteArrayOutputStream baos = new ByteArrayOutputStream(len + 2);
    baos.write(firstByte);
    baos.write(secondByte);
    baos.write(msg);
    return baos.toByteArray();
}

public byte[] unWrap(InputStream inputStream) throws Exception {
    int firstByte = inputStream.read();
    if (firstByte == -1) {
        throw new IOException("End of Stream while trying to read vli byte 1");
    }
    int firstByteValue = firstByte << 8;
    int secondByteValue = inputStream.read();
    if (secondByteValue == -1) {
        throw new IOException("End of Stream reading vli byte 2." );
    }
    int len = firstByteValue + secondByteValue;
    byte[] message = new byte[len];
    int requestLen;
    int readLen;
    int currentIndex = 0;
    while(true) {
        requestLen = len - currentIndex;
        readLen = inputStream.read(message, currentIndex, requestLen);
        if (readLen == requestLen) {
            break; // Message is complete.
        }
        // Either data was not yet available, or End of Stream.
        currentIndex += readLen;
        int nextByte = inputStream.read();
        if (nextByte == -1) {
            throw new IOException("End of Stream at " + currentIndex 
    );
        }
        message[currentIndex++] = (byte)nextByte;
    }
return message;
}

and here is my python converted code

import io

def wrap(msg):
    msg_len = len(msg)
    if msg_len > 65535:
        return "Message exceeds 65535 bytes."

    first_byte = bytes(msg_len >> 8)

    second_byte = bytes(msg_len)
    # create an empty bytearray
    data_frame = bytearray()
    data_frame.extend(first_byte)
    data_frame.extend(second_byte)
    data_frame.extend(msg)
    return data_frame



def un_wrap(data_frame):
    data_frame = io.BytesIO(data_frame)

    first_byte = data_frame.read()
    try:
        first_byte == -1
    except:
        raise "End of Stream while trying to read vli byte 1"

    first_byte_value = first_byte << 8

    second_byte_value = data_frame.read(1)

    try:
        second_byte_value == -1
    except:
        raise "End of Stream reading vli byte 2."

    byt_len = first_byte_value + second_byte_value

    message = bytes(byt_len)

   request_len = 0
   read_len = 0
   current_index = 0
   while True:
        request_len = byt_len - current_index
        read_len = data_frame.read(message, current_index, request_len)
        if read_len == request_len:
            return "Message is complete."
        # Either data was not yet available, or End of Stream.
        current_index += read_len
        next_byte = data_frame
        if next_byte == -1:
            return  "End of Stream at " + current_index
        message.extend(bytes(next_byte))
    return message

This is the error am getting

    first_byte_value = first_byte << 8
    TypeError: unsupported operand type(s) for <<: 'bytes' and 'int'

This is the is what am sending as the message but I require two bytes to precede the message

<ipayMsg client="PESATRANS" term="00001" seqNum="0" time="2019-10-09 10:13:20 +0300">
   <elecMsg ver="2.44">
    <vendReq>
      <ref>749761497475</ref>
      <amt cur="KES">500</amt>
      <numTokens>1</numTokens>
      <meter>01450344831</meter>
      <payType>cash</payType>
    </vendReq>
 </elecMsg>
</ipayMsg>
10
  • 1
    and how is that error message not clear? Commented Oct 10, 2019 at 12:23
  • @Stultuske it is clear I just don't know a work arounf/888 Commented Oct 10, 2019 at 12:32
  • use valid java syntax Commented Oct 10, 2019 at 12:37
  • Possible duplicate of Reading integers from binary file in Python Commented Oct 10, 2019 at 12:54
  • Or stackoverflow.com/questions/444591/… Commented Oct 10, 2019 at 12:54

2 Answers 2

0

in this line, the code wants to do a left shift on a bytes object. You need to convert it to int first.

int_value = int.frombytes(bytes_value, byteorder="big")

Documentation: https://docs.python.org/3/library/stdtypes.html?highlight=from_bytes#int.from_bytes

Sign up to request clarification or add additional context in comments.

Comments

0

I have figured out the answer. The main issue that I had is to assume that python byte conversion is the same as java. This is where my main challenge was.

public byte[] wrap(byte[] msg) throws Exception {
    int len = msg.length;
    if (len > 65535) {
        throw new IllegalArgumentException("Exceeds 65535 bytes.");
    }
    byte firstByte = (byte)(len >>> 8);
    byte secondByte = (byte)len;
    ByteArrayOutputStream baos = new ByteArrayOutputStream(len + 2);
    baos.write(firstByte);
    baos.write(secondByte);
    baos.write(msg);
    return baos.toByteArray();
}

For this java method I was able to come up this one for python

def wrap(msg):
    msg_len = len(msg)
    if msg_len > 65535:
        return "Message exceeds 65535 bytes."
    my_list = []
    first_byte = msg_len >> 8
    second_byte = msg_len
    my_list.append(first_byte)
    my_list.append(second_byte)

    # create an empty bytearray
    data_frame = bytearray([x % 256 for x in my_list])
    data_frame.extend(msg)
    return data_frame

I was able to achieve this by first creating a list of my elements then I converted from 2s compliment to an unsigned integer and added them into the bytearray.

data_frame = bytearray([x % 256 for x in my_list])

Turns out I do not need the second method. Thanks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.