Skip to content

Instantly share code, notes, and snippets.

@castaneai
Created August 6, 2015 06:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save castaneai/0ecc57033e4e49111c12 to your computer and use it in GitHub Desktop.
Save castaneai/0ecc57033e4e49111c12 to your computer and use it in GitHub Desktop.
python binary struct class
import struct
class Struct:
_fields = None # type: tuple
_size = None # type: int
@classmethod
def size(cls):
if cls._size is None:
cls._size = sum(field_cls.size() for field_cls, _ in cls._fields)
return cls._size
@classmethod
def unpack(cls, _bytes: bytes):
if cls._fields is None:
raise Exception("_serialize field required")
instance = cls()
read_pos = 0
for field_cls, field_name in cls._fields:
if issubclass(field_cls, StructField) or issubclass(field_cls, Struct):
setattr(instance, field_name, field_cls.unpack(_bytes[read_pos:read_pos + field_cls.size()]))
read_pos += field_cls.size()
else:
raise TypeError("All Struct fields must be subclass of Struct or StructField")
return instance
class StructField:
_format = None # type: str
_primitive_struct = None # type: struct.Struct
@classmethod
def size(cls) -> int:
if cls._primitive_struct is None:
cls._primitive_struct = struct.Struct(cls._format)
return cls._primitive_struct.size
@classmethod
def unpack(cls, _bytes: bytes):
if cls._primitive_struct is None:
cls._primitive_struct = struct.Struct(cls._format)
return cls._primitive_struct.unpack(_bytes)[0]
class UInt32(StructField):
_format = "<I"
class UInt16(StructField):
_format = "<H"
class IPEndPoint(Struct):
_fields = (
(UInt32, "ip_address"),
(UInt16, "port")
)
binary = b"\xFA\xBB\x1C\x09\xFF\xFF"
ep = IPEndPoint.unpack(binary)
print(ep.ip_address, ep.port)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment