Skip to content
This repository was archived by the owner on Mar 27, 2026. It is now read-only.

Commit c542867

Browse files
authored
Merge pull request #13 from ronfrenk/TLV_length
Implemented reading of the length of a TLV structure
2 parents 40b5b79 + a75124e commit c542867

3 files changed

Lines changed: 47 additions & 3 deletions

File tree

emv/protocol/data.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@ def read_tag(data):
5454
return tag, i
5555

5656

57+
def read_length(data):
58+
""" Read length from a list of bytes, starting at the first byte.
59+
Returns the length, plus the number of bytes read from the list.
60+
61+
EMV 4.3 Book 3 Annex B2
62+
"""
63+
i = 0
64+
length = data[i]
65+
i += 1
66+
if length & 0x80:
67+
length_bytes_count = length & 0x7F
68+
length = 0
69+
for j in range(length_bytes_count):
70+
length = (length << 8) + data[i + j]
71+
i += length_bytes_count
72+
return length, i
73+
74+
5775
@total_ordering
5876
class Tag(object):
5977
""" Represents a data tag. Provides ordering and pretty rendering."""

emv/protocol/structures.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from collections import OrderedDict
2-
from .data import ELEMENT_FORMAT, render_element, read_tag, is_constructed, Tag
2+
from .data import (
3+
ELEMENT_FORMAT,
4+
render_element,
5+
read_tag,
6+
read_length,
7+
is_constructed,
8+
Tag,
9+
)
310
from .data_elements import Parse, EPC_PRODUCT_ID
411
from ..util import decode_int, bit_set
512
import logging
@@ -45,8 +52,10 @@ def unmarshal(cls, data):
4552
if len(data) <= i:
4653
log.info("Invalid TLV - read beyond end of buffer at %s: %s", tag, data)
4754
return data
48-
length = data[i]
49-
i += 1
55+
56+
length, length_len = read_length(data[i:])
57+
i += length_len
58+
5059
value = data[i : i + length]
5160

5261
if is_constructed(tag[0]):

emv/protocol/test/test_structures.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,23 @@ def test_tlv(self):
3131
tlv = TLV.unmarshal(data)
3232
self.assertEqual(tlv[(0x9F, 0x17)][0], 3)
3333

34+
def test_length_parsing(self):
35+
data = unformat_bytes("42 01 03")
36+
tlv = TLV.unmarshal(data)
37+
self.assertEqual(tlv[0x42][0], 3)
38+
39+
data = unformat_bytes("42 81 01 07")
40+
tlv = TLV.unmarshal(data)
41+
self.assertEqual(tlv[0x42][0], 7)
42+
43+
data = unformat_bytes("42 82 00 01 07")
44+
tlv = TLV.unmarshal(data)
45+
self.assertEqual(tlv[0x42][0], 7)
46+
47+
data = unformat_bytes("42 83 00 00 01 07")
48+
tlv = TLV.unmarshal(data)
49+
self.assertEqual(tlv[0x42][0], 7)
50+
3451
def test_duplicate_tags(self):
3552
# An ADF entry with a number of records:
3653
data = unformat_bytes(

0 commit comments

Comments
 (0)