Skip to content
Open
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
48 changes: 48 additions & 0 deletions scapy/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,54 @@ class _FieldContainer(object):
"""
__slots__ = ["fld"]

def copy(self):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What this function does looks very funky to me. Couldn't we just call the copy() of the sub field?

# type: () -> Any
def _copy_attr(attr):
# type: (Any) -> Any
if hasattr(attr, "copy"):
return attr.copy()
return attr

cls = self.__class__
other = cls.__new__(cls)

if hasattr(self, "__dict__"):
other.__dict__ = {
key: _copy_attr(value)
for key, value in self.__dict__.items()
}

copied_slots = set()
for base in cls.__mro__:
slots = base.__dict__.get("__slots__", ())
if isinstance(slots, str):
slots = (slots,)
for slot in slots:
if slot in ("__dict__", "__weakref__") or slot in copied_slots:
continue
slot_descriptor = base.__dict__.get(slot)
if getattr(cls, slot, None) is not slot_descriptor:
continue
copied_slots.add(slot)
try:
value = getattr(self, slot)
except AttributeError:
continue
setattr(other, slot, _copy_attr(value))

return other

def __setattr__(self, attr, value):
# type: (str, Any) -> None
try:
object.__setattr__(self, attr, value)
except AttributeError as ex:
try:
fld = object.__getattribute__(self, "fld")
except AttributeError:
raise ex
setattr(fld, attr, value)
Comment on lines +352 to +361

def __getattr__(self, attr):
# type: (str) -> Any
return getattr(self.fld, attr)
Expand Down
28 changes: 28 additions & 0 deletions test/fields.uts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,34 @@
#Field("foo", None, fmt="I").getfield(None, b"\x12\x34\x56\x78ABCD")
#assert _ == ("ABCD",0x12345678)

= FieldContainer copy
~ core field

field_container = Emph(ByteField("foo", 0))
field_container_copy = field_container.copy()

assert type(field_container_copy) is Emph
assert type(field_container_copy.fld) is ByteField
assert field_container_copy.fld is not field_container.fld
assert field_container_copy.name == "foo"
assert field_container_copy.default == 0

class TEST_FIELD_CONTAINER_COPY_SOURCE(Packet):
fields_desc = [Emph(ByteField("foo", 0))]

class TEST_FIELD_CONTAINER_COPY_TARGET(Packet):
fields_desc = [TEST_FIELD_CONTAINER_COPY_SOURCE, ByteField("bar", 0)]
foo = 7

source_field = TEST_FIELD_CONTAINER_COPY_SOURCE.fields_desc[0]
target_field = TEST_FIELD_CONTAINER_COPY_TARGET.fields_desc[0]

assert type(target_field) is Emph
assert type(target_field.fld) is ByteField
assert target_field.fld is not source_field.fld
assert target_field.default == 7
assert source_field.default == 0


= ConditionnalField class
~ core field
Expand Down
Loading