Files
2024-12-09 18:22:38 +09:00

116 lines
3.7 KiB
Python

import binascii
import typing
from pyshark.packet.common import Pickleable, SlotsPickleable
class LayerField(SlotsPickleable):
"""Holds all data about a field of a layer, both its actual value and its name and nice representation."""
# Note: We use this object with slots and not just a dict because
# it's much more memory-efficient (cuts about a third of the memory).
__slots__ = ['name', 'showname', 'raw_value', 'show', 'hide', 'pos', 'size', 'unmaskedvalue']
def __init__(self, name=None, showname=None, value=None, show=None, hide=None, pos=None, size=None, unmaskedvalue=None):
self.name = name
self.showname = showname
self.raw_value = value
self.show = show
self.pos = pos
self.size = size
self.unmaskedvalue = unmaskedvalue
if hide and hide == 'yes':
self.hide = True
else:
self.hide = False
def __repr__(self):
return f'<LayerField {self.name}: {self.get_default_value()}>'
def get_default_value(self) -> str:
"""Gets the best 'value' string this field has."""
val = self.show
if not val:
val = self.raw_value
if not val:
val = self.showname
return val
@property
def showname_value(self) -> typing.Union[str, None]:
"""The "pretty value" (as displayed by Wireshark) of the field."""
if self.showname and ': ' in self.showname:
return self.showname.split(': ', 1)[1]
return None
@property
def showname_key(self) -> typing.Union[str, None]:
"""The "pretty name" (as displayed by Wireshark) of the field."""
if self.showname and ': ' in self.showname:
return self.showname.split(': ', 1)[0]
return None
@property
def binary_value(self) -> bytes:
"""Converts this field to binary (assuming it's a binary string)"""
str_raw_value = str(self.raw_value)
if len(str_raw_value) % 2 == 1:
str_raw_value = '0' + str_raw_value
return binascii.unhexlify(str_raw_value)
@property
def int_value(self) -> int:
"""Returns the int value of this field (assuming it's represented as a decimal integer)."""
return int(self.raw_value)
@property
def hex_value(self) -> int:
"""Returns the int value of this field if it's in base 16
(either as a normal number or in a "0xFFFF"-style hex value)
"""
return int(self.raw_value, 16)
base16_value = hex_value
class LayerFieldsContainer(str, Pickleable):
"""An object which contains one or more fields (of the same name).
When accessing member, such as showname, raw_value, etc. the appropriate member of the main (first) field saved
in this container will be shown.
"""
def __new__(cls, main_field, *args, **kwargs):
if hasattr(main_field, 'get_default_value'):
obj = str.__new__(cls, main_field.get_default_value(), *args, **kwargs)
else:
obj = str.__new__(cls, main_field, *args, **kwargs)
obj.fields = [main_field]
return obj
def __dir__(self):
return dir(type(self)) + list(self.__dict__.keys()) + dir(self.main_field)
def add_field(self, field):
self.fields.append(field)
@property
def all_fields(self):
"""Returns all fields in a list, the main field followed by the alternate fields."""
return self.fields
@property
def main_field(self):
return self.fields[0]
@property
def alternate_fields(self):
"""Return the alternate values of this field containers (non-main ones)."""
return self.fields[1:]
def __getattr__(self, item):
return getattr(self.main_field, item)