159
159
from pcapkit .protocols .schema .misc .pcapng import ZigBeeAPSKey as Schema_ZigBeeAPSKey
160
160
from pcapkit .protocols .schema .misc .pcapng import ZigBeeNWKKey as Schema_ZigBeeNWKKey
161
161
from pcapkit .utilities .compat import StrEnum
162
- from pcapkit .utilities .exceptions import EndianError , FileError , UnsupportedCall
162
+ from pcapkit .utilities .exceptions import EndianError , FileError , ProtocolError , UnsupportedCall
163
163
from pcapkit .utilities .warnings import RegistryWarning , warn
164
164
165
165
__all__ = ['PCAPNG' ]
@@ -725,7 +725,8 @@ def unpack(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_PCAPN
725
725
self .__header__ = cast ('Schema_PCAPNG' , self .__schema__ .unpack (self ._file , length , packet )) # type: ignore[call-arg,misc]
726
726
return self .read (length , ** kwargs )
727
727
728
- def read (self , length : 'Optional[int]' = None , ** kwargs : 'Any' ) -> 'Data_PCAPNG' :
728
+ def read (self , length : 'Optional[int]' = None , * , _read : 'bool' = True ,
729
+ _seek_set : 'int' = 0 , ** kwargs : 'Any' ) -> 'Data_PCAPNG' :
729
730
r"""Read PCAP-NG file blocks.
730
731
731
732
Structure of PCAP-NG file blocks:
@@ -746,12 +747,49 @@ def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_PCAPNG'
746
747
747
748
Args:
748
749
length: Length of data to be read.
750
+ \_read: If the class is called in a parsing scenario.
751
+ \_seek_set: File offset before reading.
749
752
**kwargs: Arbitrary keyword arguments.
750
753
751
754
Returns:
752
755
Parsed packet data.
753
756
754
757
"""
758
+ schema = self .__header__
759
+
760
+ if schema .block .length < 12 or schema .block .length % 4 != 0 :
761
+ raise ProtocolError (f'PCAP-NG: [Block { schema .type } ] invalid length: { schema .block .length } ' )
762
+
763
+ name = self .__block__ [schema .type ]
764
+ if isinstance (name , str ):
765
+ meth_name = f'_read_block_{ name } '
766
+ meth = cast ('BlockParser' ,
767
+ getattr (self , meth_name , self ._read_block_unknown ))
768
+ else :
769
+ meth = name [0 ]
770
+ block = meth (schema .block , header = schema )
771
+
772
+ if not _read :
773
+ # move backward to the beginning of the packet
774
+ self ._file .seek (0 , io .SEEK_SET )
775
+ else :
776
+ # NOTE: We create a copy of the block data here for parsing
777
+ # scenarios to keep the original packet data intact.
778
+ seek_cur = self ._file .tell ()
779
+
780
+ # move backward to the beginning of the block
781
+ self ._file .seek (_seek_set , io .SEEK_SET )
782
+
783
+ #: bytes: Raw block data.
784
+ self ._data = self ._read_fileng (schema .block .length )
785
+
786
+ # move backward to the beginning of next block
787
+ self ._file .seek (seek_cur , io .SEEK_SET )
788
+
789
+ #: io.BytesIO: Source packet stream.
790
+ self ._file = io .BytesIO (self ._data )
791
+
792
+ return block
755
793
756
794
def make (self ,
757
795
** kwargs : 'Any' ) -> 'Schema_PCAPNG' :
@@ -801,16 +839,19 @@ def __post_init__(self, file: 'Optional[IO[bytes] | bytes]' = None, length: 'Opt
801
839
self ._ctx = ctx
802
840
803
841
if file is None :
842
+ _read = False
804
843
#: bytes: Raw packet data.
805
844
self ._data = self .pack (** kwargs )
806
845
#: io.BytesIO: Source packet stream.
807
846
self ._file = io .BytesIO (self ._data )
808
847
else :
848
+ _read = True
809
849
#: io.BytesIO: Source packet stream.
810
850
self ._file = io .BytesIO (file ) if isinstance (file , bytes ) else file
851
+ _seek_set = self ._file .tell ()
811
852
812
853
#: pcapkit.corekit.infoclass.Info: Parsed packet data.
813
- self ._info = self .unpack (length , ** kwargs )
854
+ self ._info = self .unpack (length , _read = _read , _seek_set = _seek_set , ** kwargs )
814
855
815
856
def __length_hint__ (self ) -> 'Literal[12]' :
816
857
"""Return an estimated length for the object."""
0 commit comments