5
5
from generator .sbpg .targets .common import snake_case , snake_case_keys , decode_json
6
6
from kaitaistruct import KaitaiStream , KaitaiStruct
7
7
import sys
8
+ import base64
8
9
import sbp .msg as msg_construct
9
10
import sbp .table as table_construct
10
11
from sbp .sbp2json import iter_messages_buffered as parse_file_construct
11
12
from subprocess import Popen , PIPE
12
13
14
+ SBP_PREAMBLE = 0x55
13
15
SBP_HEADER_LEN = 6
14
16
PERL_CMD = ['perl' , 'kaitai/perl/bin/sbp2json.pl' ]
15
17
@@ -31,8 +33,8 @@ def dictify(obj, round_floats=False):
31
33
# "original" version of sbp2json based entirely upon construct
32
34
def get_next_msg_construct (fileobj ):
33
35
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 )
36
38
37
39
if msg_type not in table_construct ._SBP_TABLE :
38
40
sys .stderr .write ("Skipping unknown message type: {}\n " .format (msg_type ))
@@ -70,14 +72,40 @@ def get_next_msg_hybrid2(fileobj):
70
72
sys .stderr .write ("Skipping unknown message type: {}\n " .format (msg_type ))
71
73
continue
72
74
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 )
75
77
stream .set_buffer (msg .to_binary ())
76
78
obj = table_kaitai .SbpMessage (stream )
77
79
78
80
yield get_flattened_msg (obj )
79
81
80
82
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
+
81
109
def get_next_msg_external (cmd , filename ):
82
110
proc = Popen (cmd + [filename ], stdout = PIPE )
83
111
@@ -106,7 +134,10 @@ def count_messages(filename, fn, cmd=None):
106
134
# (to avoid calling table_construct.dispatch())
107
135
# 4. hybrid2: use parsing code from construct version + msg_construct.SBP +
108
136
# 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
110
141
# kaitai-struct-compiler
111
142
def compare_parser_outputs (filename ):
112
143
num_messages = 0
@@ -115,19 +146,22 @@ def compare_parser_outputs(filename):
115
146
file2 = open (filename , 'rb' )
116
147
file3 = open (filename , 'rb' )
117
148
file4 = open (filename , 'rb' )
149
+ file5 = open (filename , 'rb' )
118
150
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 )):
120
152
msg_construct = snake_case_keys (msg_construct )
121
153
msg_perl = decode_json (msg_perl )
122
154
123
155
dict_construct = dictify (msg_construct )
124
156
dict_kaitai = dictify (msg_kaitai )
125
157
dict_hybrid1 = dictify (msg_hybrid1 )
126
158
dict_hybrid2 = dictify (msg_hybrid2 )
159
+ dict_hybrid3 = dictify (msg_hybrid3 )
127
160
128
161
assert dict_construct == dict_kaitai , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_kaitai )
129
162
assert dict_construct == dict_hybrid1 , "Mismatch:\n {}\n vs\n {}" .format (dict_construct , dict_hybrid1 )
130
163
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 )
131
165
132
166
# need to round floats due to difference in rounding approaches used
133
167
# by perl and python JSON encoders
0 commit comments