Ben I has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/41913?usp=email )


Change subject: Decode GSM 7-bit packed EF.PNN data
......................................................................

Decode GSM 7-bit packed EF.PNN data

Change-Id: I4558fd011592aeeae2389fe8a1f62f3d7e21d219
---
M pySim/ts_51_011.py
M pySim/utils.py
2 files changed, 88 insertions(+), 7 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/13/41913/1

diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 70c38b1..a71e2c2 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -40,7 +40,7 @@
 from osmocom.construct import *

 from pySim.utils import dec_iccid, enc_iccid, dec_imsi, enc_imsi, dec_plmn, 
enc_plmn, dec_xplmn_w_act
-from pySim.utils import bytes_for_nibbles
+from pySim.utils import bytes_for_nibbles, gsm7_unpack, gsm7_pack
 from pySim.profile import CardProfile, CardProfileAddon
 from pySim.filesystem import *
 from pySim.ts_31_102_telecom import DF_PHONEBOOK, DF_MULTIMEDIA, DF_MCS, DF_V2X
@@ -884,19 +884,56 @@
                                  'cap_conf_id'/Int8ub,
                                  ext_name/Int8ub)

+
+class NetworkNameAdapter(Adapter):
+    """Adapter for Network Name IE per TS 24.008 Section 10.5.3.5a."""
+
+    def _decode(self, obj, context, path):
+        if len(obj) < 1:
+            return ''
+        header = obj[0]
+        coding_scheme = (header >> 6) & 0x01  # bit 7: 0=GSM7, 1=UCS2
+        spare_bits = header & 0x07            # bits 3-1
+        data = obj[1:]
+        if not data:
+            return ''
+        if coding_scheme == 0:
+            # GSM 7-bit packed
+            unpacked = gsm7_unpack(data, spare_bits)
+            return unpacked.decode('gsm03.38')
+        else:
+            # UCS-2 (UTF-16 BE)
+            return data.decode('utf_16_be')
+
+    def _encode(self, obj, context, path):
+        if not obj:
+            return b'\x80'  # Empty with GSM7 coding
+        # Try GSM 7-bit first
+        try:
+            unpacked = obj.encode('gsm03.38')
+            packed, spare_bits = gsm7_pack(unpacked)
+            header = 0x80 | spare_bits  # ext=1, coding=0, ci=0
+            return bytes([header]) + packed
+        except UnicodeEncodeError:
+            # Fall back to UCS-2
+            encoded = obj.encode('utf_16_be')
+            header = 0x80 | 0x40  # ext=1, coding=1
+            return bytes([header]) + encoded
+
+
 # TS 51.011 Section 4.2.58
 class EF_PNN(LinFixedEF):
-    # TODO: 430a82d432bbbc7eb75de432450a82d432bbbc7eb75de432ffffffff
-    # TODO: 430a82c596b34cbfbfe5eb39ffffffffffffffffffffffffffffffffffff
+    _test_de_encode = [
+        ('430584c330bc0c', [{'full_name_for_network': 'Cape'}]),
+    ]
+
     class FullNameForNetwork(BER_TLV_IE, tag=0x43):
         # TS 24.008 10.5.3.5a
-        # TODO: proper decode
-        _construct = GreedyBytes
+        _construct = NetworkNameAdapter(GreedyBytes)

     class ShortNameForNetwork(BER_TLV_IE, tag=0x45):
         # TS 24.008 10.5.3.5a
-        # TODO: proper decode
-        _construct = GreedyBytes
+        _construct = NetworkNameAdapter(GreedyBytes)

     class NetworkNameCollection(TLV_IE_Collection, nested=[FullNameForNetwork, 
ShortNameForNetwork]):
         pass
diff --git a/pySim/utils.py b/pySim/utils.py
index 7d8e3fa..2ec5bd0 100644
--- a/pySim/utils.py
+++ b/pySim/utils.py
@@ -78,6 +78,50 @@
     return imsi


+def gsm7_unpack(packed_data: bytes, num_spare_bits: int = 0) -> bytes:
+    """Unpack GSM 7-bit packed data to unpacked bytes (one septet per byte).
+
+    Args:
+        packed_data: The packed 7-bit data bytes
+        num_spare_bits: Number of spare bits in the last octet (0-6)
+
+    Returns:
+        Unpacked bytes where each byte contains one 7-bit character value
+    """
+    if not packed_data:
+        return b''
+    packed_int = int.from_bytes(packed_data, byteorder='little')
+    num_bits = len(packed_data) * 8 - num_spare_bits
+    num_septets = num_bits // 7
+    unpacked = bytearray()
+    for i in range(num_septets):
+        septet = (packed_int >> (i * 7)) & 0x7f
+        unpacked.append(septet)
+    return bytes(unpacked)
+
+
+def gsm7_pack(unpacked_data: bytes) -> Tuple[bytes, int]:
+    """Pack unpacked GSM 7-bit data into packed format.
+
+    Args:
+        unpacked_data: Unpacked bytes (one septet per byte, high bit ignored)
+
+    Returns:
+        Tuple of (packed_data, num_spare_bits)
+    """
+    if not unpacked_data:
+        return b'', 0
+    num_septets = len(unpacked_data)
+    num_bits = num_septets * 7
+    num_bytes = (num_bits + 7) // 8
+    num_spare_bits = num_bytes * 8 - num_bits
+    packed_int = 0
+    for i, septet in enumerate(unpacked_data):
+        packed_int |= (septet & 0x7f) << (i * 7)
+    packed = packed_int.to_bytes(num_bytes, byteorder='little')
+    return packed, num_spare_bits
+
+
 def dec_iccid(ef: Hexstr) -> str:
     return swap_nibbles(ef).strip('f')


--
To view, visit https://gerrit.osmocom.org/c/pysim/+/41913?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I4558fd011592aeeae2389fe8a1f62f3d7e21d219
Gerrit-Change-Number: 41913
Gerrit-PatchSet: 1
Gerrit-Owner: Ben I <[email protected]>

Reply via email to