FFFF
Skip to content
Draft
Show file tree
Hide file tree
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
25 changes: 23 additions & 2 deletions docs/source/fields.rst
8000
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,30 @@ until the main dom is built again.
Printing
""""""""

Use the :any:`pfp.fields.Field._pfp__show()` method to return a
Use the :any:`pfp.fields.Field._pfp__show` method to return a
pretty-printed representation of the field.

Full Field Paths
""""""""""""""""

Use the :any:`pfp.fields.Field._pfp__path` method to fetch the full path
of the field. E.g. in the template below, the ``inner`` field would have
a full path of ``root.nested1.nested2.inner``, and the second element of
the ``array`` field would have a full path of ``root.nested1.nested2.array[1]``:

.. code-block:: c

struct {
struct {
struct {
char inner;
char array[4];
} nested2;
int some_int;
} nested1;
int some_int2;
} root;

Structs
^^^^^^^

Expand All @@ -40,7 +61,7 @@ Field Reference Documentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autoclass:: pfp.fields.Field
:members: _pfp__name, _pfp__parent, _pfp__build, _pfp__parse, _pfp__watchers, _pfp__watch_fields, _pfp__width, _pfp__set_value, _pfp__show
:members: _pfp__name, _pfp__parent, _pfp__build, _pfp__parse, _pfp__watchers, _pfp__watch_fields, _pfp__width, _pfp__set_value, _pfp__show, _pfp__path

.. autoclass:: pfp.fields.Array
:members: width, field_cls, raw_data
Expand Down
30 changes: 30 additions & 0 deletions pfp/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,36 @@ def __init__(self, stream=None, metadata_processor=None):
if stream is not None:
self._pfp__parse(stream, save_offset=True)

# see #51 - fields should have a method of returning the full path of its name
def _pfp__path(self):
"""Return the full pathname of this field. E.g. given
the template below, the ``a`` field would have a full
path of ``root.nested.a``

.. code-block:: c

struct {
struct {
char a;
} nested;
} root;
"""
curr = self
res = []
while curr is not None:
# don't show the meta __root name in the path
if curr._pfp__name == "__root" and curr._pfp__parent is None:
break

res.append(curr._pfp__name)

if isinstance(curr._pfp__parent, Array):
curr = curr._pfp__parent._pfp__parent
else:
curr = curr._pfp__parent

return ".".join(reversed(res))

def _pfp__snapshot(self, recurse=True):
"""Save off the current value of the field
"""
Expand Down
28 changes: 28 additions & 0 deletions tests/test_struct_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ def setUp(self):
def tearDown(self):
pass

def test_field_path(self):
dom = self._test_parse_build(
"Abbbb4141414142424242",
"""
struct {
struct {
struct {
char inner;
char array[4];
} nested2;
int some_int;
} nested1;
int some_int2;
} root;
""",
)
self.assertEqual(dom.root._pfp__path(), "root")
self.assertEqual(dom.root.some_int2._pfp__path(), "root.some_int2")
self.assertEqual(dom.root.nested1._pfp__path(), "root.nested1")
self.assertEqual(dom.root.nested1.some_int._pfp__path(), "root.nested1.some_int")
self.assertEqual(dom.root.nested1.nested2._pfp__path(), "root.nested1.nested2")
self.assertEqual(dom.root.nested1.nested2.inner._pfp__path(), "root.nested1.nested2.inner")
self.assertEqual(dom.root.nested1.nested2.array._pfp__path(), "root.nested1.nested2.array")
self.assertEqual(dom.root.nested1.nested2.array[0]._pfp__path(), "root.nested1.nested2.array[0]")
self.assertEqual(dom.root.nested1.nested2.array[1]._pfp__path(), "root.nested1.nested2.array[1]")
self.assertEqual(dom.root.nested1.nested2.array[2]._pfp__path(), "root.nested1.nested2.array[2]")
self.assertEqual(dom.root.nested1.nested2.array[3]._pfp__path(), "root.nested1.nested2.array[3]")

def test_struct(self):
dom = self._test_parse_build(
"abcddcba",
Expand Down
0