knovichikhin / pyiso8583

ISO8583 protocol parser that creates a regular Python dictionary describing ISO8583 data
MIT License
51 stars 15 forks source link

how to encode and decode 127 bitmap #19

Closed ondiekisteven closed 2 years ago

ondiekisteven commented 2 years ago

Hi, I ran into this package recently, but i have a problem with my specific use case. I have a document which specifies field 127 to be a bitmap, containing other fields inside it, i.e from 127.1 to 127.25, so this field needs to be encoded and decoded as containing bitmap and data.

This is a message, but encoded with java, i need to encode the same message with python

b'\x00>0800\x828\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x0202110526452202110526450211301000\x00\x00\x00\x00\x00\x00\x00\x0000'

so i tried to decode this message first but i get this error:

iso8583.decoder.DecodeError: Extra data after last field: field 127 pos 54

this image shows part of the specification image

What do i need to do to decode the field? any ideas will help. Thanks

knovichikhin commented 2 years ago

So, the reason it tells that there is extra data after field 127 is because field 127 has zero length. And there is more data after that.

import iso8583
from iso8583.specs import default as spec
import pprint

msg = b'0800\x828\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x0202110526452202110526450211301000\x00\x00\x00\x00\x00\x00\x00\x0000'
try:
    d, e = iso8583.decode(msg, spec)
except Exception as exc:
    pprint.pp(exc.__dict__)

Produces this:

{'msg': 'Extra data after last field',
 's': b'0800\x828\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x020211'
      b'0526452202110526450211301000\x00\x00\x00\x00\x00\x00\x00\x0000',
 'doc_dec': {'t': '0800',
             'p': '8238000000000000',
             '1': '0400000000000002',
             '7': '0211052645',
             '11': '220211',
             '12': '052645',
             '13': '0211',
             '70': '301',
             '127': ''},
 'doc_enc': {'t': {'len': b'', 'data': b'0800'},
             'p': {'len': b'', 'data': b'\x828\x00\x00\x00\x00\x00\x00'},
             '1': {'len': b'', 'data': b'\x04\x00\x00\x00\x00\x00\x00\x02'},
             '7': {'len': b'', 'data': b'0211052645'},
             '11': {'len': b'', 'data': b'220211'},
             '12': {'len': b'', 'data': b'052645'},
             '13': {'len': b'', 'data': b'0211'},
             '70': {'len': b'', 'data': b'301'},
             '127': {'len': b'000', 'data': b''}},
 'field': '127',
 'pos': 52}

As you can see field 127 length is 000.

Let's assume for a second that length is not 000 but 010 to indicate actual length of data that follows.


import iso8583
from iso8583.specs import default as spec
import pprint

msg = b'0800\x828\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x0202110526452202110526450211301010\x00\x00\x00\x00\x00\x00\x00\x0000'
try:
    d, e = iso8583.decode(msg, spec)
except Exception as exc:
    pprint.pp(exc.__dict__)

pprint.pp(d)
pprint.pp(e)
>>> pprint.pp(d)
{'t': '0800',
 'p': '8238000000000000',
 '1': '0400000000000002',
 '7': '0211052645',
 '11': '220211',
 '12': '052645',
 '13': '0211',
 '70': '301',
 '127': '\x00\x00\x00\x00\x00\x00\x00\x0000'}
>>> pprint.pp(e)
{'t': {'len': b'', 'data': b'0800'},
 'p': {'len': b'', 'data': b'\x828\x00\x00\x00\x00\x00\x00'},
 '1': {'len': b'', 'data': b'\x04\x00\x00\x00\x00\x00\x00\x02'},
 '7': {'len': b'', 'data': b'0211052645'},
 '11': {'len': b'', 'data': b'220211'},
 '12': {'len': b'', 'data': b'052645'},
 '13': {'len': b'', 'data': b'0211'},
 '70': {'len': b'', 'data': b'301'},
 '127': {'len': b'010', 'data': b'\x00\x00\x00\x00\x00\x00\x00\x0000'}}

Encoding the message back produces the same message.

assert msg == iso8583.encode(d, spec)[0]

And from here, you can feed d['127'] to your custom decoder to get whatever you want out of it.

So the main question is if zero length field 127 is a mistake or by design? If it's by design, I don't see how it's valid ISO8583. But you can still process it, you will have to fork the lib because right now it does not support custom decoders/encoders.

You can put your custom decoder for field 127 here: https://github.com/knovichikhin/pyiso8583/blob/b90b8b3c0e141baf81ffb658ddc782bad66dde73/iso8583/decoder.py#L126

And encoder here: https://github.com/knovichikhin/pyiso8583/blob/b90b8b3c0e141baf81ffb658ddc782bad66dde73/iso8583/encoder.py#L95

ondiekisteven commented 2 years ago

the field is empty for the message above because it's a network management message (0800) but for recharge messages, it will be available on 127.9 as transactio ID. Thanks for this. Let me see how to implement my own decoder.