55from generator .sbpg .targets .common import snake_case , snake_case_keys , decode_json
66from kaitaistruct import KaitaiStream , KaitaiStruct
77import sys
8+ import base64
89import sbp .msg as msg_construct
910import sbp .table as table_construct
1011from sbp .sbp2json import iter_messages_buffered as parse_file_construct
1112from subprocess import Popen , PIPE
1213
14+ SBP_PREAMBLE = 0x55
1315SBP_HEADER_LEN = 6
1416PERL_CMD = ['perl' , 'kaitai/perl/bin/sbp2json.pl' ]
1517
@@ -31,8 +33,8 @@ def dictify(obj, round_floats=False):
3133# "original" version of sbp2json based entirely upon construct
3234def get_next_msg_construct (fileobj ):
3335 for msg_type , sender , payload_len , buf , crc_read in parse_file_construct (fileobj ):
34- msg_buf = buf [SBP_HEADER_LEN :SBP_HEADER_LEN + payload_len ]
35- msg = msg_construct .SBP (msg_type , sender , payload_len , msg_buf , crc_read )
36+ payload = buf [SBP_HEADER_LEN :SBP_HEADER_LEN + payload_len ]
37+ msg = msg_construct .SBP (msg_type , sender , payload_len , payload , crc_read )
3638
3739 if msg_type not in table_construct ._SBP_TABLE :
3840 sys .stderr .write ("Skipping unknown message type: {}\n " .format (msg_type ))
@@ -70,14 +72,40 @@ def get_next_msg_hybrid2(fileobj):
7072 sys .stderr .write ("Skipping unknown message type: {}\n " .format (msg_type ))
7173 continue
7274
73- msg_buf = buf [SBP_HEADER_LEN :SBP_HEADER_LEN + payload_len ]
74- msg = msg_construct .SBP (msg_type , sender , payload_len , msg_buf , crc_read )
75+ payload = buf [SBP_HEADER_LEN :SBP_HEADER_LEN + payload_len ]
76+ msg = msg_construct .SBP (msg_type , sender , payload_len , payload , crc_read )
7577 stream .set_buffer (msg .to_binary ())
7678 obj = table_kaitai .SbpMessage (stream )
7779
7880 yield get_flattened_msg (obj )
7981
8082
83+ # hybrid version of sbp2json which uses original parser + kaitai struct to avoid
84+ # calling table_construct.dispatch() as well as avoiding usage of io.BytesIO
85+ def get_next_msg_hybrid3 (fileobj ):
86+ stream = BufferKaitaiStream ()
87+ for msg_type , sender , payload_len , buf , crc_read in parse_file_construct (fileobj ):
88+
89+ if msg_type not in table_kaitai .TABLE :
90+ sys .stderr .write ("Skipping unknown message type: {}\n " .format (msg_type ))
91+ continue
92+
93+ # we can construct a kaitai object directly from the payload, but this
94+ # means that we need to manually fill in the preamble/sender/crc/etc
95+ payload = buf [SBP_HEADER_LEN :SBP_HEADER_LEN + payload_len ]
96+ cls = table_kaitai .TABLE [msg_type ]
97+ stream .set_buffer (bytes (payload ))
98+ obj = cls (stream )
99+ obj .preamble = SBP_PREAMBLE
100+ obj .msg_type = msg_type
101+ obj .sender = sender
102+ obj .length = payload_len
103+ obj .payload = base64 .standard_b64encode (payload ).decode ('ascii' )
104+ obj .crc = crc_read
105+
106+ yield obj
107+
108+
81109def get_next_msg_external (cmd , filename ):
82110 proc = Popen (cmd + [filename ], stdout = PIPE )
83111
@@ -106,7 +134,10 @@ def count_messages(filename, fn, cmd=None):
106134# (to avoid calling table_construct.dispatch())
107135# 4. hybrid2: use parsing code from construct version + msg_construct.SBP +
108136# kaitai struct objects (to avoid calling table_construct.dispatch())
109- # 5. perl: based completely upon the perl bindings generated by
137+ # 5. hybrid3: use parsing code from construct version + msg_construct.SBP +
138+ # kaitai_table.TABLE (to avoid calling table_construct.dispatch() and
139+ # usage of BytesIO)
140+ # 6. perl: based completely upon the perl bindings generated by
110141# kaitai-struct-compiler
111142def compare_parser_outputs (filename ):
112143 num_messages = 0
@@ -115,19 +146,22 @@ def compare_parser_outputs(filename):
115146 file2 = open (filename , 'rb' )
116147 file3 = open (filename , 'rb' )
117148 file4 = open (filename , 'rb' )
149+ file5 = open (filename , 'rb' )
118150
119- for msg_construct , msg_kaitai , msg_hybrid1 , msg_hybrid2 , msg_perl in zip (get_next_msg_construct (file1 ), get_next_msg_kaitai (file2 ), get_next_msg_hybrid1 (file3 ), get_next_msg_hybrid2 (file4 ), get_next_msg_external (PERL_CMD , filename )):
151+ for msg_construct , msg_kaitai , msg_hybrid1 , msg_hybrid2 , msg_hybrid3 , msg_perl in zip (get_next_msg_construct (file1 ), get_next_msg_kaitai (file2 ), get_next_msg_hybrid1 (file3 ), get_next_msg_hybrid2 (file4 ), get_next_msg_hybrid3 ( file5 ), get_next_msg_external (PERL_CMD , filename )):
120152 msg_construct = snake_case_keys (msg_construct )
121153 msg_perl = decode_json (msg_perl )
122154
123155 dict_construct = dictify (msg_construct )
124156 dict_kaitai = dictify (msg_kaitai )
125157 dict_hybrid1 = dictify (msg_hybrid1 )
126158 dict_hybrid2 = dictify (msg_hybrid2 )
159+ dict_hybrid3 = dictify (msg_hybrid3 )
127160
128161 assert dict_construct == dict_kaitai , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_kaitai )
129162 assert dict_construct == dict_hybrid1 , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_hybrid1 )
130163 assert dict_construct == dict_hybrid2 , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_hybrid2 )
164+ assert dict_construct == dict_hybrid3 , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_hybrid3 )
131165
132166 # need to round floats due to difference in rounding approaches used
133167 # by perl and python JSON encoders
0 commit comments