From 784928002ef2870408dfd51cd2fe6e97eb7b8b51 Mon Sep 17 00:00:00 2001 From: Jonathan Klamroth Date: Wed, 25 Jun 2025 11:20:34 +0200 Subject: [PATCH 1/2] implement parsing of the values section similar to the implementation in libpsf --- src/psf_parser/binary/parser.py | 60 +++++++++++++++++---------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/psf_parser/binary/parser.py b/src/psf_parser/binary/parser.py index 7845dd3..10f6bcd 100644 --- a/src/psf_parser/binary/parser.py +++ b/src/psf_parser/binary/parser.py @@ -1,4 +1,3 @@ -from enum import Enum import contextlib from psf_parser.parser import PsfParser @@ -7,13 +6,6 @@ from psf_parser.binary.chunk_id import ChunkId -class ValueSectionType(Enum): - NONE = 0 - SIMPLE = 512 - WINDOWED = 1024 - NON_SWEEP = 1280 - - class PsfBinParser(PsfParser): def __init__(self, path: str): @@ -28,7 +20,8 @@ def parse(self): self.validate_signature() self.reader.seek(0) - self.value_section_type = ValueSectionType(self.reader.read_uint32()) + self.has_sweep_section = False + self.reader.skip(4) self.parse_header_section() @@ -36,6 +29,7 @@ def parse(self): self.parse_type_section() if ChunkId(self.reader.peek_uint32()).matches(ChunkId.SECTION_SWEEP): + self.has_sweep_section = True self.parse_sweep_section() if ChunkId(self.reader.peek_uint32()).matches(ChunkId.SECTION_TRACE): @@ -44,6 +38,8 @@ def parse(self): if ChunkId(self.reader.peek_uint32()).matches(ChunkId.SECTION_VALUE): self.parse_value_section() + ChunkId(self.reader.read_uint32()).expect(ChunkId.SECTION_END) + self.reader.close() return self @@ -209,25 +205,9 @@ def parse_value_section(self): ChunkId(self.reader.read_uint32()).expect(ChunkId.SECTION_VALUE) endpos = self.read_container_preamble(ChunkId.CONTAINER) - match self.value_section_type: - case ValueSectionType.NONE: - pass - case ValueSectionType.NON_SWEEP: - sub_endpos = self.read_container_preamble(ChunkId.SUBCONTAINER) - while self.reader.tell() < sub_endpos: - self.read_data_declaration(Section.VALUE) - self.read_container_index(bytes_per_id=4) - - case ValueSectionType.SIMPLE: - while self.reader.tell() < endpos: - ChunkId(self.reader.read_uint32()).expect(ChunkId.DECLARATION) - decl_id = self.reader.read_uint32() - decl = self.registry.get_by_id(decl_id) - decl.data.append( - self.read_data(self.registry.get_by_id(decl.type_id)) - ) - - case ValueSectionType.WINDOWED: + if self.has_sweep_section: + windowed = "PSF window size" in self.header + if windowed: sweep_decls = self.registry.sweeps if len(sweep_decls) != 1: raise SyntaxError("Error: Expected exactly one sweep declaration for WINDOWED value section.") @@ -254,6 +234,28 @@ def parse_value_section(self): self.reader.skip((window_size - num_words) * 8) if i < len(data_decls) - 1: self.reader.skip(8) + else: + while self.reader.tell() < endpos: + chunk_id = ChunkId(self.reader.read_uint32()).expect({ChunkId.DECLARATION, ChunkId.GROUP_DECLARATION}) + decl_id = self.reader.read_uint32() + decl = self.registry.get_by_id(decl_id) + match chunk_id: + case ChunkId.DECLARATION: + decl.data.append( + self.read_data(self.registry.get_by_id(decl.type_id)) + ) + + case ChunkId.GROUP_DECLARATION: + data = None + for member_id in decl.members: + member_decl = self.registry.get_by_id(member_id) + if data is None: + data = self.read_data(self.registry.get_by_id(member_decl.type_id)) + member_decl.data.append(data) + else: + sub_endpos = self.read_container_preamble(ChunkId.SUBCONTAINER) + while self.reader.tell() < sub_endpos: + self.read_data_declaration(Section.VALUE) + self.read_container_index(bytes_per_id=4) self.check_container_end(endpos) - ChunkId(self.reader.read_uint32()).expect(ChunkId.SECTION_END) From 807a304331ebc145d59928efa81f575d2f555491 Mon Sep 17 00:00:00 2001 From: Jonathan Klamroth Date: Wed, 25 Jun 2025 14:58:27 +0200 Subject: [PATCH 2/2] add test for sweeps with group declarations in the values section (in PSFBIN files) --- tests/data/binary/spectre-lx-10signals.sweep | Bin 0 -> 5156 bytes tests/test_binary.py | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 tests/data/binary/spectre-lx-10signals.sweep diff --git a/tests/data/binary/spectre-lx-10signals.sweep b/tests/data/binary/spectre-lx-10signals.sweep new file mode 100644 index 0000000000000000000000000000000000000000..83d36ef1a20a393663634d6f0dcd05e4d31a0d64 GIT binary patch literal 5156 zcmd5=dyG_99iG?DvMiKGS1ij?F6Fs}o!uE&3bYICE<+jJSD9s?#5m5*Tz0RWof+@F zOBZcSh#F%I#-=62_&^ek(KJeYU}H>E)7sSfNJUz$Rk48bDi-Y@^+oji&N=tY>}5@s z|2)aL_k8E~ew;IRHxLL1Fy0ji)V+-Na?II7>0O6R+p)?ek^PZbiy^*)goD1WIYmJ-O4|d>zL7s->Kqi~%-jh{(D|>gQv)#LQ z_GOa;-93HD?9iUnz;J*1!JdcHL&@IZJ;|u1EyQF9M>w1X8X$pv#Yz5E0#xZmDwO=mQe;l?eEL>ckf5mcBNAX zl3j_;O&wy8>mJMo2JX0riwqc}9#ikThbyKdwgdCjK5Jw+kD6vh5`t=fzTP(~Wvk?p zdLQNr%(+$CxFt)AT{-;p+$8q5-|)!77h!YME>9?%vq7bgV&AoMdF3ScMXelbe4?0h z%eGWg?^MjZYl{d;udivc`RtxpM{ILPB4#;uoIaB$QpmX!Xi04C?AY45#Te>eZ|pM* z#(O48Mxt}QftKo2ywQT`SfkazC_guc`W$vF$6yk%ff0ePV#D8EZQX$7tJT#0{qv64Ku6$&8s#mu=T9h`olK zlQ&BRw3C3MP7B>~(S)kJ8M95~&pHIhw-1feFQAbVaUqkiF+bfEb`60 zh6%^4*ybTc3WQ2!k_0X4JYrP}QpVe-FHuB`&|&xET0i$2awG7(xHiKyZaekDJ750Z z^`ltU(o&>#edze-jXgco5Ag4%3u4Oxs2r zj;V58U$jP08y#nK+;qpvvX<;Crj2%H6+M~FSZ67NpZ%|NKjQ%rywBi^2W1xFT#5W@A;Swn04a5z(S2iyy;W;5%Vy& zYUz~WIga*~N3DE@WHJ0QkrFOJP{>bOu*xbh_18_5EScFVz1FU$L)26EJ_KuOP5sPd zFolO2o-b4McS~Ze{^$q~)0iOKVxuOnv@sVm+~2=TYLPMdV~BR&>rUA6o~gC-KjZM( zxC6>V`$jwy)8@&e&q)8a1+m76-N{O9=%?v?UH1&A>+YZP@U|(L@{Z8Q6&5h7DgFxJLrv-Ge*v5@WhNkub9yRqu4> z2zOH;_z-g%c1HRiI1~QXmo8qEOk&Xb+Go-!TL}KW2O$qOdYfZ+ML~ZQ`cRX5%n!ief(ydCw>dE1HlKPkP*jI^3k7W%t*;} zJMd;amZFgCG4Te3kgIr)I@hU*Sig#GiTkp=+PG`)Q3&Jag#9?{3+z@i$s1a8=`Px80G6 z-1Vf!-+%85Uwi9|-_aPx{_*-fXEc8H`Okm#Li+C-KbL;z7q2b)q{ctKAT~69(LQBB zMB|@^=A?e`e)ggC_vep~f#W%iU!E`ic+&Wn`^ARFXJkMc|LRil)4j)zX#7fhGdO;t z@v9hj4waCZA8ow4@`TO?flN$e)f4cqaipH-WI|2@#11bMIaG!Xln(seQ{KStm z{hV-zXG-$_@cN)A$PAIbc*V!+Ys@jjtZ3!($p>19!_)yaQx>*C^g{O5-=_&e36wufzJ;o7H~1 z&UBT&py_`B_u#o58ox#H!HZS=sr%5;f7AE|R&xBmpMT!t9K6GDmx=%R;cgRuFX9ds T-wdG5+t^#o*_Pwvc+dS80epO+ literal 0 HcmV?d00001 diff --git a/tests/test_binary.py b/tests/test_binary.py index ec42953..3ed9f9e 100644 --- a/tests/test_binary.py +++ b/tests/test_binary.py @@ -66,3 +66,9 @@ def test_binary_info_oppoint(psf_test_files): file = psf_test_files / "binary/myinfo_Oppoint.info" parser = PsfBinParser(file).parse() expect(parser, 13, 0, 0, 3) + + +def test_binary_spectre_lx_10signals(psf_test_files): + file = psf_test_files / "binary/spectre-lx-10signals.sweep" + parser = PsfBinParser(file).parse() + expect(parser, 15, 1, 10, 0)