@@ -170,11 +170,165 @@ static void _output_sar_data(uint32_t tick, struct sar_data data) {
170
170
}
171
171
}
172
172
173
+ #define SAR_MSG_INIT_B "&^!$"
174
+ #define SAR_MSG_INIT_O "&^!%"
175
+ #define SAR_MSG_CONT_B "&^?$"
176
+ #define SAR_MSG_CONT_O "&^?%"
177
+
178
+ static char g_partial [8192 ];
179
+ static int g_expected_len = 0 ;
180
+
181
+ ///// START BASE92 /////
182
+
183
+ // This isn't really base92. Instead, we encode 4-byte input chunks into 5 base92 characters. If the
184
+ // final chunk is not 4 bytes, each byte of it is sent as 2 base92 characters; the receiver infers
185
+ // this from the buffer length and decodes accordingly. This system is almost as space-efficient as
186
+ // is possible.
187
+
188
+ static char base92_chars [93 ] = // 93 because null terminator
189
+ "abcdefghijklmnopqrstuvwxyz"
190
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
191
+ "0123456789"
192
+ "!$%^&*-_=+()[]{}<>'@#~;:/?,.|\\" ;
193
+
194
+ // doing this at runtime is a little silly but shh
195
+ static const char * base92_reverse () {
196
+ static char map [256 ];
197
+ static int initd = 0 ;
198
+ if (initd == 0 ) {
199
+ initd = 1 ;
200
+ for (int i = 0 ; i < 92 ; ++ i ) {
201
+ char c = base92_chars [i ];
202
+ map [(int )c ] = i ;
203
+ }
204
+ }
205
+ return map ;
206
+ }
207
+
208
+ static char * base92_decode (const char * encoded , int len ) {
209
+ const char * base92_rev = base92_reverse ();
210
+
211
+ static char out [512 ]; // leave some overhead lol
212
+ static int outLen ;
213
+ memset (out , 0 , sizeof (out ));
214
+ outLen = 0 ;
215
+ #define push (val ) \
216
+ out[outLen++] = val;
217
+ while (len > 6 || len == 5 ) {
218
+ unsigned val = base92_rev [(unsigned )encoded [4 ]];
219
+ val = (val * 92 ) + base92_rev [(unsigned )encoded [3 ]];
220
+ val = (val * 92 ) + base92_rev [(unsigned )encoded [2 ]];
221
+ val = (val * 92 ) + base92_rev [(unsigned )encoded [1 ]];
222
+ val = (val * 92 ) + base92_rev [(unsigned )encoded [0 ]];
223
+
224
+ char * raw = (char * )& val ;
225
+ push (raw [0 ]);
226
+ push (raw [1 ]);
227
+ push (raw [2 ]);
228
+ push (raw [3 ]);
229
+
230
+ encoded += 5 ;
231
+ len -= 5 ;
232
+ }
233
+ while (len > 0 ) {
234
+ unsigned val = base92_rev [(unsigned )encoded [1 ]];
235
+ val = (val * 92 ) + base92_rev [(unsigned )encoded [0 ]];
236
+
237
+ char * raw = (char * )& val ;
238
+ push (raw [0 ]);
239
+ encoded += 2 ;
240
+ len -= 2 ;
241
+ }
242
+ return out ;
243
+ }
244
+
245
+ ///// END BASE92 /////
246
+
247
+ static bool handleMessage (struct demo_msg * msg ) {
248
+ if (strncmp (msg -> con_cmd , "say \"" , 5 )) return false;
249
+ if (strlen (msg -> con_cmd ) < 10 ) return false;
250
+ bool has_prefix = true;
251
+ char * prefix = msg -> con_cmd + 5 ;
252
+ bool cont , orange ;
253
+ if (!strncmp (prefix , SAR_MSG_INIT_B , 4 )) {
254
+ cont = false;
255
+ orange = false;
256
+ } else if (!strncmp (prefix , SAR_MSG_INIT_O , 4 )) {
257
+ cont = false;
258
+ orange = true;
259
+ } else if (!strncmp (prefix , SAR_MSG_CONT_B , 4 )) {
260
+ cont = true;
261
+ orange = false;
262
+ } else if (!strncmp (prefix , SAR_MSG_CONT_O , 4 )) {
263
+ cont = true;
264
+ orange = true;
265
+ } else {
266
+ has_prefix = false;
267
+ }
268
+
269
+ if (!has_prefix ) return false;
270
+
271
+ if (cont ) {
272
+ if (!g_expected_len ) {
273
+ fprintf (g_errfile , "\t\t[%5u] Unmatched NetMessage continuation %s\n" , msg -> tick , msg -> con_cmd );
274
+ return false;
275
+ }
276
+ strcat (g_partial , msg -> con_cmd + 9 );
277
+ } else {
278
+ char * raw = base92_decode (msg -> con_cmd + 9 , 5 );
279
+ g_expected_len = (int )* raw ;
280
+ strcat (g_partial , msg -> con_cmd + 14 );
281
+ }
282
+
283
+ if (strlen (g_partial ) < g_expected_len ) {
284
+ fprintf (g_outfile , "\t\t[%5u] NetMessage continuation %d != %d\n" , msg -> tick , g_expected_len , (int )strlen (g_partial ));
285
+ return true;
286
+ } else if (strlen (g_partial ) > g_expected_len ) {
287
+ fprintf (g_errfile , "\t\t[%5u] NetMessage length mismatch %d != %d\n" , msg -> tick , g_expected_len , (int )strlen (g_partial ));
288
+ return false;
289
+ } else {
290
+ char * decoded = base92_decode (g_partial , g_expected_len );
291
+ char * type = decoded ;
292
+ char * data = decoded + strlen (type ) + 1 ;
293
+
294
+ fprintf (g_outfile , "\t\t[%5u] NetMessage (%s): %s" , msg -> tick , orange ? "o" : "b" , type );
295
+
296
+ // print data
297
+ int datalen = strlen (data );
298
+ bool printdata = true;
299
+ if (!strcmp (type , "srtimer" )) {
300
+ datalen = 4 ;
301
+ printdata = false;
302
+ }
303
+ if (!strcmp (type , "cmboard" )) {
304
+ datalen = 0 ;
305
+ }
306
+
307
+ if (datalen > 0 ) {
308
+ if (printdata ) fprintf (g_outfile , " = %s (" , data );
309
+ else fprintf (g_outfile , " (" );
310
+
311
+ for (int i = 0 ; i < datalen ; ++ i ) {
312
+ fprintf (g_outfile , "%02X" , (unsigned char )data [i ]);
313
+ if (i < datalen - 1 ) fprintf (g_outfile , " " );
314
+ }
315
+ if (datalen > 0 ) fprintf (g_outfile , ")" );
316
+ }
317
+
318
+ fprintf (g_outfile , "\n" );
319
+ }
320
+ g_expected_len = 0 ;
321
+ g_partial [0 ] = 0 ;
322
+ return true;
323
+ }
324
+
173
325
static void _output_msg (struct demo_msg * msg ) {
174
326
switch (msg -> type ) {
175
327
case DEMO_MSG_CONSOLE_CMD :
176
328
if (!config_check_cmd_whitelist (g_cmd_whitelist , msg -> con_cmd )) {
177
- fprintf (g_outfile , "\t\t[%5u] %s\n" , msg -> tick , msg -> con_cmd );
329
+ if (!handleMessage (msg )) {
330
+ fprintf (g_outfile , "\t\t[%5u] %s\n" , msg -> tick , msg -> con_cmd );
331
+ }
178
332
}
179
333
break ;
180
334
case DEMO_MSG_SAR_DATA :
0 commit comments