Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions cstruct/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,13 @@ def __new__(mcs, name, bases, dict):
__struct__ = dict.get("__struct__", None)
if __struct__ is not None:
dict['__fmt__'], dict['__fields__'], dict['__fields_types__'] = mcs.parse_struct(__struct__)
dict['__values__'] = {}
if '__byte_order__' in dict:
dict['__fmt__'] = dict['__byte_order__'] + dict['__fmt__']
# Add the missing fields to the class
for field in dict['__fields__']:
if field not in dict:
dict[field] = None
if field not in dict['__values__']:
dict['__values__'][field] = None
# Calculate the structure size
dict['__size__'] = struct.calcsize(dict['__fmt__'])
new_class = type.__new__(mcs, name, bases, dict)
Expand Down Expand Up @@ -312,8 +313,9 @@ def __init__(self, string=None, **kargs):
self.unpack(string)
except:
pass
self.__values__ = {}
for key, value in kargs.items():
setattr(self, key, value)
self.__values__[key] = value

def unpack(self, string):
"""
Expand All @@ -326,29 +328,29 @@ def unpack(self, string):
for field in self.__fields__:
(vtype, vlen) = self.__fields_types__[field]
if vtype == 'char': # string
setattr(self, field, data[i])
i = i + 1
self.__values__[field] = data[i]
i += 1
elif isinstance(vtype, CStructMeta):
num = int(vlen / vtype.size)
if num == 1: # single struct
sub_struct = vtype()
sub_struct.unpack(EMPTY_BYTES_STRING.join(data[i:i+sub_struct.size]))
setattr(self, field, sub_struct)
i = i + sub_struct.size
self.__values__[field] = sub_struct
i += sub_struct.size
else: # multiple struct
sub_structs = []
for j in range(0, num):
sub_struct = vtype()
sub_struct.unpack(EMPTY_BYTES_STRING.join(data[i:i+sub_struct.size]))
i = i + sub_struct.size
i += sub_struct.size
sub_structs.append(sub_struct)
setattr(self, field, sub_structs)
self.__values__[field] = sub_structs
elif vlen == 1:
setattr(self, field, data[i])
i = i + vlen
self.__values__[field] = data[i]
i += vlen
else:
setattr(self, field, list(data[i:i+vlen]))
i = i + vlen
self.__values__[field] = list(data[i:i+vlen])
i += vlen

def pack(self):
"""
Expand All @@ -358,17 +360,17 @@ def pack(self):
for field in self.__fields__:
(vtype, vlen) = self.__fields_types__[field]
if vtype == 'char': # string
data.append(getattr(self, field))
data.append(self.__values__.get(field))
elif isinstance(vtype, CStructMeta):
num = int(vlen / vtype.size)
if num == 1: # single struct
v = getattr(self, field, vtype())
v = self.__values__.get(field, vtype())
v = v.pack()
if sys.version_info >= (3, 0):
v = ([bytes([x]) for x in v])
data.extend(v)
else: # multiple struct
values = getattr(self, field, [])
values = self.__values__.get(field, [])
for j in range(0, num):
try:
v = values[j]
Expand All @@ -379,13 +381,26 @@ def pack(self):
v = ([bytes([x]) for x in v])
data.extend(v)
elif vlen == 1:
data.append(getattr(self, field))
data.append(self.__values__.get(field))
else:
v = getattr(self, field)
v = self.__values__.get(field)
v = v[:vlen] + [0] * (vlen - len(v))
data.extend(v)
return struct.pack(self.__fmt__, *data)

def __getattr__(self, name):
if name in self.__fields__:
try:
return self.__values__[name]
except KeyError:
raise AttributeError("'{}' object has no attribute '{}'".format(self.__name__, name))
return super(CStruct, self).__getattr__(name)

def __setattr__(self, name, value):
if name in self.__fields__:
self.__values__[name] = value
super(CStruct, self).__setattr__(name, value)

def clear(self):
self.unpack(None)

Expand Down