Skip to content

Commit 52fab6b

Browse files
authored
Merge pull request #7 from ACRIOS-Systems/feature/necessaryTyping
Feature/necessary typing
2 parents af9fd10 + c96e7ba commit 52fab6b

File tree

2 files changed

+100
-38
lines changed

2 files changed

+100
-38
lines changed

dissect/cstruct/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,15 @@
1111
RawType,
1212
BaseType,
1313
StructureType,
14+
StructureFieldType,
1415
EnumType,
1516
ArrayType,
17+
PackedType,
18+
CharType,
19+
WcharType,
20+
UnionType,
21+
VoidType,
22+
typeAll,
1623
Error,
1724
ParserError,
1825
CompilerError,
@@ -33,8 +40,15 @@
3340
"RawType",
3441
"BaseType",
3542
"StructureType",
43+
"StructureFieldType",
3644
"EnumType",
3745
"ArrayType",
46+
"PackedType",
47+
"CharType",
48+
"WcharType",
49+
"UnionType",
50+
"VoidType",
51+
"typeAll",
3852
"Error",
3953
"ParserError",
4054
"CompilerError",

dissect/cstruct/cstruct.py

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from io import BytesIO
3434
from collections import OrderedDict
3535
import json
36+
import typing
3637

3738
try:
3839
from builtins import bytes as newbytes
@@ -88,6 +89,7 @@ def __repr__(self):
8889
return '<StructureType {name} +compiled>'
8990
"""
9091

92+
#common regex values
9193
COMMENT_MULTILINE = r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/'
9294
COMMENT_INLINE = r'//[^\n]*'
9395
COMMENT_MULTILINE_REPEATED = r'(^[ ]*('+COMMENT_INLINE+r'|'+COMMENT_MULTILINE+r'([ ]*('+COMMENT_INLINE+r'|'+COMMENT_MULTILINE+r'))*)[ \t\r]*\n?)*^[ ]*('+COMMENT_INLINE+r'|(?P<commentBlock>'+COMMENT_MULTILINE+r'))+'
@@ -97,6 +99,12 @@ def __repr__(self):
9799
#print(f"COMMENT_REGEX_START:{COMMENT_REGEX_START}")
98100
#print(f"COMMENT_REGEX_END:{COMMENT_REGEX_END}")
99101

102+
#types
103+
typeCommentAttributes=dict[str,str]
104+
typeValuesDetails =dict[str,dict[str,typing.Union[str,int,typeCommentAttributes]]]
105+
typeAll = typing.Union[str,'PackedType','CharType','WcharType','BytesInteger','VoidType','ArrayType','StructureType','EnumType']
106+
typeTypedefs = dict[str, typeAll]
107+
100108
class Error(Exception):
101109
pass
102110

@@ -139,7 +147,7 @@ def __init__(self, endian='<', pointer='uint64'):
139147

140148
self.consts = {}
141149
self.lookups = {}
142-
self.typedefs = {
150+
self.typedefs:typeTypedefs = {
143151
'byte': 'int8',
144152
'ubyte': 'uint8',
145153
'uchar': 'uint8',
@@ -186,7 +194,7 @@ def __init__(self, endian='<', pointer='uint64'):
186194

187195
self.pointer = self.resolve(pointer)
188196

189-
def addtype(self, name, t, replace=False):
197+
def addtype(self, name:str, t:typeAll, replace=False):
190198
"""Add a type or type reference.
191199
192200
Args:
@@ -197,8 +205,7 @@ def addtype(self, name, t, replace=False):
197205
Raises:
198206
ValueError: If the type already exists.
199207
"""
200-
name = name.lower()
201-
if not replace and name.lower() in self.typedefs:
208+
if not replace and name in self.typedefs:
202209
raise ValueError("Duplicate type: %s" % name)
203210

204211
self.typedefs[name] = t
@@ -223,7 +230,7 @@ def load(self, s, deftype=None, **kwargs):
223230

224231
parser.parse(s)
225232

226-
def loadfile(self, s, deftype=None, **kwargs):
233+
def loadfile(self, s:str, deftype:typing.Optional[int]=None, **kwargs:typing.Union['cstruct',bool]):
227234
"""Load structure definitions from a file.
228235
229236
The given path will be read and parsed using the .load() function.
@@ -268,25 +275,61 @@ def resolve(self, name):
268275
return t
269276

270277
for i in xrange(10):
271-
if t.lower() not in self.typedefs:
278+
if t not in self.typedefs:
272279
raise ResolveError("Unknown type %s" % name)
273280

274-
t = self.typedefs[t.lower()]
281+
t = self[t]
275282

276283
if not isinstance(t, str):
277284
return t
278285

279286
raise ResolveError("Recursion limit exceeded while resolving type %s" % name)
280287

281288
def __getattr__(self, attr):
282-
if attr.lower() in self.typedefs:
283-
return self.typedefs[attr.lower()]
289+
if attr in self.typedefs:
290+
return self.typedefs[attr]
284291

285292
if attr in self.consts:
286293
return self.consts[attr]
287294

295+
for enum in self.getEnumTypes():
296+
for enumMember in enum.values.items():
297+
if enumMember[0] == attr:
298+
return enumMember[1]
299+
300+
288301
raise AttributeError("Invalid Attribute: %s" % attr)
289302

303+
def __getitem__(self, item):
304+
return self.__getattr__(item)
305+
306+
def keys(self):
307+
return self.typedefs.keys()
308+
309+
def values(self):
310+
return self.typedefs.values()
311+
312+
def items(self):
313+
return self.typedefs.items()
314+
315+
def getEnumTypes(self):
316+
retVal: list[EnumType] = []
317+
allTypes = self.typedefs
318+
for currentType in allTypes.values():
319+
if isinstance(currentType, EnumType):
320+
retVal.append(currentType)
321+
322+
return retVal
323+
324+
def getStructTypes(self):
325+
retVal: list[StructureType] = []
326+
allTypes = self.typedefs
327+
for currentType in allTypes.values():
328+
if isinstance(currentType, StructureType):
329+
retVal.append(currentType)
330+
331+
return retVal
332+
290333

291334
class Parser(object):
292335
"""Base class for definition parsers.
@@ -428,7 +471,7 @@ def _parse_fields_struct(self, s):
428471
COMMENT_REGEX_START+r'(?P<type>[^\s]+)\s+(?P<name>[^\s\[:]+)(\s*:\s*(?P<bits>\d+))?(\[(?P<count>[^;\n]*)\])?;'+COMMENT_REGEX_END,
429472
s, re.MULTILINE
430473
)
431-
r = []
474+
r:list[StructureFieldType] = []
432475
for f in fields:
433476
d = f.groupdict()
434477
if d['type'].startswith('//'):
@@ -458,13 +501,13 @@ def _parse_fields_struct(self, s):
458501
d['name'] = d['name'][1:]
459502
type_ = Pointer(self.cstruct, type_)
460503

461-
field = StructureField(d['name'], type_, int(d['bits']) if d['bits'] else None, commentAttributes=commentAttributes)
504+
field = StructureFieldType(d['name'], type_, int(d['bits']) if d['bits'] else None, commentAttributes=commentAttributes)
462505
r.append(field)
463506

464507
return r
465508

466509
def parse_comment_block(self,s):
467-
commentAttributes={}
510+
commentAttributes:typeCommentAttributes={}
468511

469512
#parse the comment header
470513
if s is not None and s.startswith('/*'):
@@ -622,7 +665,7 @@ class Expression(object):
622665
('<<', lambda a, b: a << b),
623666
]
624667

625-
def __init__(self, cstruct, expr):
668+
def __init__(self, cstruct:cstruct, expr):
626669
self.cstruct = cstruct
627670
self.expr = expr
628671

@@ -667,6 +710,11 @@ def evaluate_part(self, e, v):
667710
if e in self.cstruct.consts:
668711
return self.cstruct.consts[e]
669712

713+
for enum in self.cstruct.getEnumTypes():
714+
for enumMember in enum.values.items():
715+
if enumMember[0] == e:
716+
return enumMember[1]
717+
670718
return int(e)
671719

672720
def __repr__(self):
@@ -778,9 +826,9 @@ def __call__(self, *args, **kwargs):
778826
class RawType(BaseType):
779827
"""Base class for raw types that have a name and size."""
780828

781-
def __init__(self, cstruct, name=None, size=0):
782-
self.name = name
783-
self.size = size
829+
def __init__(self, cstruct, name:typing.Union[str,None]=None, size:int=0):
830+
self.name:typing.Union[str,None] = name
831+
self.size:int = size
784832
super(RawType, self).__init__(cstruct)
785833

786834
def __len__(self):
@@ -796,12 +844,12 @@ def __repr__(self):
796844
class StructureType(BaseType):
797845
"""Type class for structures."""
798846

799-
def __init__(self, cstruct, name, fields=None, commentAttributes={}):
800-
self.name = name
801-
self.size = None
847+
def __init__(self, cstruct, name:str, fields:list['StructureFieldType']=[], commentAttributes:typeCommentAttributes={}):
848+
self.name:str = name
849+
self.size:typing.Union[int,None] = None
802850
self.lookup = OrderedDict()
803-
self.fields = fields if fields else []
804-
self.commentAttributes = commentAttributes
851+
self.fields:list[StructureFieldType] = fields
852+
self.commentAttributes:typeCommentAttributes = commentAttributes
805853

806854

807855
for f in self.fields:
@@ -917,15 +965,15 @@ def _write(self, stream, data):
917965

918966
return num
919967

920-
def add_fields(self, name, type_, offset=None, commentAttributes={}):
968+
def add_fields(self, name, type_, offset=None, commentAttributes:typeCommentAttributes={}):
921969
"""Add a field to this structure.
922970
923971
Args:
924972
name: The field name.
925973
type_: The field type.
926974
offset: The field offset.
927975
"""
928-
field = StructureField(name, type_, offset=offset, commentAttributes=commentAttributes)
976+
field = StructureFieldType(name, type_, offset=offset, commentAttributes=commentAttributes)
929977
self.fields.append(field)
930978
self.lookup[name] = field
931979
self.size = None
@@ -1023,15 +1071,15 @@ def reset(self):
10231071
self._remaining = 0
10241072

10251073

1026-
class StructureField(object):
1074+
class StructureFieldType(object):
10271075
"""Holds a structure field."""
10281076

1029-
def __init__(self, name, type_, bits=None, offset=None, commentAttributes={}):
1030-
self.name = name
1031-
self.type = type_
1077+
def __init__(self, name:str, type_:typeAll, bits=None, offset:typing.Union[int,None]=None, commentAttributes:typeCommentAttributes={}):
1078+
self.name:str = name
1079+
self.type:typeAll = type_
10321080
self.bits = bits
1033-
self.offset = offset
1034-
self.commentAttributes = commentAttributes
1081+
self.offset:typing.Union[int,None] = offset
1082+
self.commentAttributes:typeCommentAttributes = commentAttributes
10351083

10361084
def __repr__(self):
10371085
return '<Field {} {} {}>'.format(self.name, self.type, self.commentAttributes)
@@ -1048,8 +1096,8 @@ class ArrayType(BaseType):
10481096
x[expr] -> expr -> dynamic length.
10491097
"""
10501098

1051-
def __init__(self, cstruct, type_, count):
1052-
self.type = type_
1099+
def __init__(self, cstruct, type_:typeAll, count):
1100+
self.type:typeAll = type_
10531101
self.count = count
10541102
self.dynamic = isinstance(self.count, Expression) or self.count is None
10551103

@@ -1352,11 +1400,11 @@ class EnumType(RawType):
13521400
};
13531401
"""
13541402

1355-
def __init__(self, cstruct, name, type_, values, valuesDetails, commentAttributes={}):
1356-
self.type = type_
1357-
self.values = values
1358-
self.valuesDetails = valuesDetails
1359-
self.commentAttributes = commentAttributes
1403+
def __init__(self, cstruct, name:str, type_:typeAll, values:dict[str,int], valuesDetails:typeValuesDetails, commentAttributes:typeCommentAttributes={}):
1404+
self.type:typeAll = type_
1405+
self.values:dict[str,int] = values
1406+
self.valuesDetails:typeValuesDetails = valuesDetails
1407+
self.commentAttributes:typeCommentAttributes = commentAttributes
13601408
self.reverse = {}
13611409

13621410
for k, v in values.items():
@@ -1449,10 +1497,10 @@ def __call__(self):
14491497
return self.value
14501498

14511499

1452-
class Union(RawType):
1500+
class UnionType(RawType):
14531501
def __init__(self, cstruct):
14541502
self.cstruct = cstruct
1455-
super(Union, self).__init__(cstruct)
1503+
super(UnionType, self).__init__(cstruct)
14561504

14571505
def _read(self, stream):
14581506
raise NotImplementedError()

0 commit comments

Comments
 (0)