Skip to content

Commit 3683d1a

Browse files
authored
Merge pull request #1 from ACRIOS-Systems/feature/support-comments-parsing
Add support for variable comment headers parsing
2 parents 880710e + d346df7 commit 3683d1a

File tree

3 files changed

+62
-9
lines changed

3 files changed

+62
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
.DS_Store
66
.tox
77
.pytest_cache
8+
build
89
**/build/*
910
**/dist/**

dissect/cstruct/cstruct.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def _read(self, stream):
8181
8282
return Instance(self, r, sizes)
8383
84-
def add_fields(self, name, type_, offset=None):
84+
def add_fields(self, name, type_, offset=None, commentAttributes={}):
8585
raise NotImplementedError("Can't add fields to a compiled structure")
8686
8787
def __repr__(self):
@@ -401,8 +401,9 @@ def _structs(self, data):
401401
self.cstruct.addtype(td, st)
402402

403403
def _parse_fields(self, s):
404+
commentAttributes = {}
404405
fields = re.finditer(
405-
r'(?P<type>[^\s]+)\s+(?P<name>[^\s\[:]+)(\s*:\s*(?P<bits>\d+))?(\[(?P<count>[^;\n]*)\])?;',
406+
r'(?P<commentBlock>\/\*(\*(?!\/)|[^*])*\*\/)?[ \t\r\n]*(?P<type>[^\s]+)\s+(?P<name>[^\s\[:]+)(\s*:\s*(?P<bits>\d+))?(\[(?P<count>[^;\n]*)\])?;',
406407
s,
407408
)
408409
r = []
@@ -411,6 +412,21 @@ def _parse_fields(self, s):
411412
if d['type'].startswith('//'):
412413
continue
413414

415+
commentAttributes={}
416+
417+
#parse the comment header
418+
if d['commentBlock'] is not None and d['commentBlock'].startswith('/*'):
419+
commentfields = re.finditer(
420+
r'@(?P<commentType>[a-zA-Z0-9_\-\/,.]+):[ \t]*(?P<commentVal>[a-zA-Z0-9_\-,.]+)',
421+
d['commentBlock'],
422+
)
423+
for cf in commentfields:
424+
cd=cf.groupdict()
425+
try:
426+
commentAttributes[cd['commentType']]=cd['commentVal']
427+
except Exception:
428+
pass
429+
414430
type_ = self.cstruct.resolve(d['type'])
415431

416432
d['name'] = d['name'].replace('(', '').replace(')', '')
@@ -433,7 +449,7 @@ def _parse_fields(self, s):
433449
d['name'] = d['name'][1:]
434450
type_ = Pointer(self.cstruct, type_)
435451

436-
field = Field(d['name'], type_, int(d['bits']) if d['bits'] else None)
452+
field = Field(d['name'], type_, int(d['bits']) if d['bits'] else None, commentAttributes=commentAttributes)
437453
r.append(field)
438454

439455
return r
@@ -747,6 +763,7 @@ def __init__(self, cstruct, name, fields=None):
747763
self.lookup = OrderedDict()
748764
self.fields = fields if fields else []
749765

766+
750767
for f in self.fields:
751768
self.lookup[f.name] = f
752769

@@ -860,15 +877,15 @@ def _write(self, stream, data):
860877

861878
return num
862879

863-
def add_field(self, name, type_, offset=None):
880+
def add_fields(self, name, type_, offset=None, commentAttributes={}):
864881
"""Add a field to this structure.
865882
866883
Args:
867884
name: The field name.
868885
type_: The field type.
869886
offset: The field offset.
870887
"""
871-
field = Field(name, type_, offset=offset)
888+
field = Field(name, type_, offset=offset, commentAttributes=commentAttributes)
872889
self.fields.append(field)
873890
self.lookup[name] = field
874891
self.size = None
@@ -969,14 +986,15 @@ def reset(self):
969986
class Field(object):
970987
"""Holds a structure field."""
971988

972-
def __init__(self, name, type_, bits=None, offset=None):
989+
def __init__(self, name, type_, bits=None, offset=None, commentAttributes={}):
973990
self.name = name
974991
self.type = type_
975992
self.bits = bits
976993
self.offset = offset
994+
self.commentAttributes = commentAttributes
977995

978996
def __repr__(self):
979-
return '<Field {} {}>'.format(self.name, self.type)
997+
return '<Field {} {} {}>'.format(self.name, self.type, self.commentAttributes)
980998

981999

9821000
class Array(BaseType):

tests/test_basic.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,9 +731,9 @@ def test_struct_sizes():
731731
""", compiled=False)
732732

733733
assert len(c.static) == 4
734-
c.static.add_field("another", c.uint32)
734+
c.static.add_fields("another", c.uint32)
735735
assert len(c.static) == 8
736-
c.static.add_field("atoffset", c.uint32, 12)
736+
c.static.add_fields("atoffset", c.uint32, 12)
737737
assert len(c.static) == 16
738738

739739
a = c.static(b'\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00')
@@ -770,3 +770,37 @@ def test_dumpstruct(capsys):
770770
captured_2 = capsys.readouterr()
771771

772772
assert captured_1.out == captured_2.out
773+
774+
775+
def test_commentfieldparse(capsys):
776+
c = cstruct.cstruct()
777+
c.load("""
778+
/*discardedCom1*/
779+
struct test{
780+
/*
781+
* @scale: 0.001
782+
* @unit: testUnit1
783+
*/
784+
int testVar1;
785+
int testVar2;
786+
/* dicardedCom2
787+
* @scale: 5
788+
* @unit: testUnit2
789+
*/
790+
int testVar3;
791+
};
792+
""", compiled=False)
793+
794+
assert c.test.name == 'test'
795+
796+
assert 'testVar1' in c.test.lookup
797+
assert 'testVar2' in c.test.lookup
798+
assert 'testVar2' in c.test.lookup
799+
800+
assert c.test.lookup['testVar1'].commentAttributes['scale'] == '0.001'
801+
assert c.test.lookup['testVar1'].commentAttributes['unit'] == 'testUnit1'
802+
803+
assert c.test.lookup['testVar2'].commentAttributes == {}
804+
805+
assert c.test.lookup['testVar3'].commentAttributes['scale'] == '5'
806+
assert c.test.lookup['testVar3'].commentAttributes['unit'] == 'testUnit2'

0 commit comments

Comments
 (0)