@@ -26,12 +26,42 @@ use color_eyre::eyre::eyre;
26
26
use nom:: { number:: Endianness , IResult } ;
27
27
use std:: {
28
28
ffi:: CString ,
29
- fmt:: { self , Debug , Display , Formatter } ,
29
+ fmt:: { self , Debug , Display , Formatter , Write } ,
30
30
} ;
31
31
32
32
const RCX_TAG : & str = "RCXI" ;
33
33
const MAX_SECTIONS : usize = 10 ;
34
34
const INDENT : & str = " " ;
35
+ const HEXDUMP_WRAP_BYTES : usize = 16 ;
36
+
37
+ fn print_hex_with_marker_at ( bin : & [ u8 ] , pos : usize ) -> String {
38
+ let mut out = String :: new ( ) ;
39
+
40
+ // header
41
+ write ! ( & mut out, " " ) . unwrap ( ) ;
42
+ for n in 0 ..16 {
43
+ write ! ( & mut out, " {n:2x}" ) . unwrap ( ) ;
44
+ }
45
+ writeln ! ( & mut out) . unwrap ( ) ;
46
+
47
+ // hexdump
48
+ for ( idx, chunk) in bin. chunks ( HEXDUMP_WRAP_BYTES ) . enumerate ( ) {
49
+ write ! ( & mut out, "0x{:02x}:" , idx * HEXDUMP_WRAP_BYTES , ) . unwrap ( ) ;
50
+ for byte in chunk {
51
+ write ! ( & mut out, " {byte:02x}" ) . unwrap ( ) ;
52
+ }
53
+ writeln ! ( & mut out) . unwrap ( ) ;
54
+ if ( idx * HEXDUMP_WRAP_BYTES ..( idx + 1 ) * HEXDUMP_WRAP_BYTES )
55
+ . contains ( & pos)
56
+ {
57
+ // indent the marker appropriately
58
+ out += " " ; // indent past the offset display
59
+ out. extend ( std:: iter:: repeat ( " " ) . take ( pos % HEXDUMP_WRAP_BYTES ) ) ;
60
+ writeln ! ( & mut out, "^<<" ) . unwrap ( ) ;
61
+ }
62
+ }
63
+ out
64
+ }
35
65
36
66
#[ derive( Clone , Debug , PartialEq , Eq ) ]
37
67
pub struct RcxBin {
@@ -47,14 +77,28 @@ pub struct RcxBin {
47
77
48
78
impl RcxBin {
49
79
pub fn parse ( bin : & [ u8 ] ) -> Result < Self > {
50
- let ( _i, bin) = parse ( bin) . map_err ( |e| eyre ! ( "Parse error: {e}" ) ) ?;
80
+ let ( _i, bin) = parse ( bin) . map_err ( |err| {
81
+ let input = match & err {
82
+ nom:: Err :: Error ( err) => err. input ,
83
+ nom:: Err :: Failure ( err) => err. input ,
84
+ nom:: Err :: Incomplete ( needed) => {
85
+ return eyre ! ( "Incomplete input, needed {needed:?}" ) ;
86
+ }
87
+ } ;
88
+ let pos = bin. len ( ) - input. len ( ) ;
89
+ println ! ( "{}" , print_hex_with_marker_at( bin, pos) ) ;
90
+ eyre ! ( "Parse error: {err}" )
91
+ } ) ?;
51
92
bin. verify ( ) ?;
52
93
Ok ( bin)
53
94
}
54
95
55
96
pub fn verify ( & self ) -> Result < ( ) > {
56
97
fn repeated_idx ( sections : & [ Section ] ) -> bool {
57
- let mut c = sections. iter ( ) . map ( |c| c. number ) . collect :: < Vec < _ > > ( ) ;
98
+ let mut c = sections
99
+ . iter ( )
100
+ . map ( |c| ( c. ty as u8 , c. number ) )
101
+ . collect :: < Vec < _ > > ( ) ;
58
102
c. sort_unstable ( ) ;
59
103
c. dedup ( ) ;
60
104
c. len ( ) != sections. len ( )
@@ -98,6 +142,40 @@ impl Display for RcxBin {
98
142
Ok ( ( ) )
99
143
}
100
144
}
145
+
146
+ fn parse ( bin : & [ u8 ] ) -> IResult < & [ u8 ] , RcxBin > {
147
+ println ! ( "Input len: {}" , bin. len( ) ) ;
148
+ let read_u16 = nom:: number:: complete:: u16 ( Endianness :: Little ) ;
149
+ let read_u8 = nom:: number:: complete:: u8;
150
+
151
+ let ( i, signature) = nom:: bytes:: complete:: tag ( RCX_TAG ) ( bin) ?;
152
+ let ( i, version) = read_u16 ( i) ?;
153
+ let ( i, section_count) = read_u16 ( i) ?;
154
+ let ( i, symbol_count) = read_u16 ( i) ?;
155
+ let ( i, target_type) = read_u8 ( i) ?;
156
+ let ( i, reserved) = read_u8 ( i) ?;
157
+
158
+ println ! ( "Parse {section_count} sections" ) ;
159
+ let ( i, sections) =
160
+ nom:: multi:: count ( parse_section, section_count. into ( ) ) ( i) ?;
161
+ println ! ( "Parse {symbol_count} symbols" ) ;
162
+ let ( i, symbols) = nom:: multi:: count ( parse_symbol, symbol_count. into ( ) ) ( i) ?;
163
+
164
+ IResult :: Ok ( (
165
+ i,
166
+ RcxBin {
167
+ signature : signature. try_into ( ) . unwrap_or ( [ 0 ; 4 ] ) ,
168
+ version,
169
+ section_count,
170
+ symbol_count,
171
+ target_type,
172
+ reserved,
173
+ sections,
174
+ symbols,
175
+ } ,
176
+ ) )
177
+ }
178
+
101
179
#[ derive( Clone , Debug , PartialEq , Eq ) ]
102
180
pub struct Section {
103
181
pub ty : SectionType ,
@@ -106,14 +184,24 @@ pub struct Section {
106
184
pub data : Vec < u8 > ,
107
185
}
108
186
109
- fn parse_chunk ( i : & [ u8 ] ) -> IResult < & [ u8 ] , Section > {
187
+ fn parse_section ( i : & [ u8 ] ) -> IResult < & [ u8 ] , Section > {
188
+ let neg_offset = i. len ( ) ;
110
189
let read_u16 = nom:: number:: complete:: u16 ( Endianness :: Little ) ;
111
190
let read_u8 = nom:: number:: complete:: u8;
112
191
113
192
let ( i, ty) = SectionType :: parse ( i) ?;
193
+ println ! ( "- section type {ty} - offset from back: {neg_offset}" ) ;
114
194
let ( i, number) = read_u8 ( i) ?;
195
+ println ! ( " number {number}" ) ;
196
+ println ! ( " length raw: {:02x}{:02x}" , i[ 1 ] , i[ 0 ] ) ;
115
197
let ( i, length) = read_u16 ( i) ?;
198
+ println ! ( " length {length}" ) ;
116
199
let ( i, data) = nom:: bytes:: complete:: take ( length) ( i) ?;
200
+ println ! ( " data len {}" , data. len( ) ) ;
201
+ println ! ( " data: {data:02x?}" ) ;
202
+
203
+ // read padding bytes
204
+ let ( i, _pad) = nom:: bytes:: complete:: take ( ( 4 - ( length % 4 ) ) & 3 ) ( i) ?;
117
205
118
206
Ok ( (
119
207
i,
@@ -138,7 +226,7 @@ impl Display for Section {
138
226
#[ repr( u8 ) ]
139
227
pub enum SectionType {
140
228
Task = 0 ,
141
- SubChunk ,
229
+ Subroutine ,
142
230
Sound ,
143
231
Animation ,
144
232
Count ,
@@ -149,7 +237,7 @@ impl SectionType {
149
237
let ( i, ty) = nom:: number:: complete:: u8 ( i) ?;
150
238
let ty = match ty {
151
239
0 => Self :: Task ,
152
- 1 => Self :: SubChunk ,
240
+ 1 => Self :: Subroutine ,
153
241
2 => Self :: Sound ,
154
242
3 => Self :: Animation ,
155
243
4 => Self :: Count ,
@@ -183,6 +271,7 @@ fn parse_symbol(i: &[u8]) -> IResult<&[u8], Symbol> {
183
271
let read_u8 = nom:: number:: complete:: u8;
184
272
185
273
let ( i, ty) = read_u8 ( i) ?;
274
+ println ! ( "Symbol type {ty}" ) ;
186
275
let ( i, index) = read_u8 ( i) ?;
187
276
let ( i, length) = read_u16 ( i) ?;
188
277
let ( i, name) = nom:: bytes:: complete:: take ( length) ( i) ?;
@@ -214,36 +303,6 @@ impl Display for Symbol {
214
303
Ok ( ( ) )
215
304
}
216
305
}
217
-
218
- fn parse ( bin : & [ u8 ] ) -> IResult < & [ u8 ] , RcxBin > {
219
- let read_u16 = nom:: number:: complete:: u16 ( Endianness :: Little ) ;
220
- let read_u8 = nom:: number:: complete:: u8;
221
-
222
- let ( i, signature) = nom:: bytes:: complete:: tag ( RCX_TAG ) ( bin) ?;
223
- let ( i, version) = read_u16 ( i) ?;
224
- let ( i, chunk_count) = read_u16 ( i) ?;
225
- let ( i, symbol_count) = read_u16 ( i) ?;
226
- let ( i, target_type) = read_u8 ( i) ?;
227
- let ( i, reserved) = read_u8 ( i) ?;
228
-
229
- let ( i, chunks) = nom:: multi:: count ( parse_chunk, chunk_count. into ( ) ) ( i) ?;
230
- let ( i, symbols) = nom:: multi:: count ( parse_symbol, symbol_count. into ( ) ) ( i) ?;
231
-
232
- IResult :: Ok ( (
233
- i,
234
- RcxBin {
235
- signature : signature. try_into ( ) . unwrap_or ( [ 0 ; 4 ] ) ,
236
- version,
237
- section_count : chunk_count,
238
- symbol_count,
239
- target_type,
240
- reserved,
241
- sections : chunks,
242
- symbols,
243
- } ,
244
- ) )
245
- }
246
-
247
306
#[ cfg( test) ]
248
307
mod test {
249
308
use super :: * ;
@@ -255,6 +314,50 @@ mod test {
255
314
430264002141000005006d61696e00"
256
315
) ;
257
316
317
+ const COMPLEX : & [ u8 ] = & hex ! (
318
+ "52435849020103000500000001000400e181218100000e0013070207e187
319
+ 130102321700710100000001330014000232001401020500130100002400
320
+ 00010085420059000008140102feff270d8502000b000006140102020043
321
+ 02640027a800010008007365745f66776400000005006d61696e0000010a
322
+ 006c6f6f705f7461736b0002000600706f776572000201060064656c7461
323
+ 00"
324
+ ) ;
325
+
326
+ #[ test]
327
+ fn err_msg ( ) {
328
+ let out = print_hex_with_marker_at ( COMPLEX , 5 ) ;
329
+ let expected = " 0 1 2 3 4 5 6 7 8 9 a b c d e f
330
+ 0x00: 52 43 58 49 02 01 03 00 05 00 00 00 01 00 04 00
331
+ ^<<
332
+ 0x10: e1 81 21 81 00 00 0e 00 13 07 02 07 e1 87 13 01
333
+ 0x20: 02 32 17 00 71 01 00 00 00 01 33 00 14 00 02 32
334
+ 0x30: 00 14 01 02 05 00 13 01 00 00 24 00 00 01 00 85
335
+ 0x40: 42 00 59 00 00 08 14 01 02 fe ff 27 0d 85 02 00
336
+ 0x50: 0b 00 00 06 14 01 02 02 00 43 02 64 00 27 a8 00
337
+ 0x60: 01 00 08 00 73 65 74 5f 66 77 64 00 00 00 05 00
338
+ 0x70: 6d 61 69 6e 00 00 01 0a 00 6c 6f 6f 70 5f 74 61
339
+ 0x80: 73 6b 00 02 00 06 00 70 6f 77 65 72 00 02 01 06
340
+ 0x90: 00 64 65 6c 74 61 00
341
+ " ;
342
+ assert_eq ! ( out, expected) ;
343
+
344
+ let out = print_hex_with_marker_at ( COMPLEX , 35 ) ;
345
+ let expected = " 0 1 2 3 4 5 6 7 8 9 a b c d e f
346
+ 0x00: 52 43 58 49 02 01 03 00 05 00 00 00 01 00 04 00
347
+ 0x10: e1 81 21 81 00 00 0e 00 13 07 02 07 e1 87 13 01
348
+ 0x20: 02 32 17 00 71 01 00 00 00 01 33 00 14 00 02 32
349
+ ^<<
350
+ 0x30: 00 14 01 02 05 00 13 01 00 00 24 00 00 01 00 85
351
+ 0x40: 42 00 59 00 00 08 14 01 02 fe ff 27 0d 85 02 00
352
+ 0x50: 0b 00 00 06 14 01 02 02 00 43 02 64 00 27 a8 00
353
+ 0x60: 01 00 08 00 73 65 74 5f 66 77 64 00 00 00 05 00
354
+ 0x70: 6d 61 69 6e 00 00 01 0a 00 6c 6f 6f 70 5f 74 61
355
+ 0x80: 73 6b 00 02 00 06 00 70 6f 77 65 72 00 02 01 06
356
+ 0x90: 00 64 65 6c 74 61 00
357
+ " ;
358
+ assert_eq ! ( out, expected) ;
359
+ }
360
+
258
361
#[ test]
259
362
fn parse_sample ( ) {
260
363
let bin = RcxBin :: parse ( SAMPLE ) . unwrap ( ) ;
@@ -286,4 +389,79 @@ mod test {
286
389
}
287
390
) ;
288
391
}
392
+
393
+ #[ test]
394
+ fn parse_complex ( ) {
395
+ let bin = RcxBin :: parse ( COMPLEX ) . unwrap ( ) ;
396
+ assert_eq ! (
397
+ bin,
398
+ RcxBin {
399
+ signature: * b"RCXI" ,
400
+ version: 0x0102 ,
401
+ section_count: 3 ,
402
+ symbol_count: 5 ,
403
+ target_type: 0 ,
404
+ reserved: 0 ,
405
+ sections: vec![
406
+ Section {
407
+ ty: SectionType :: Subroutine ,
408
+ number: 0 ,
409
+ length: 4 ,
410
+ data: vec![ 225 , 129 , 33 , 129 ]
411
+ } ,
412
+ Section {
413
+ ty: SectionType :: Task ,
414
+ number: 0 ,
415
+ length: 14 ,
416
+ data: vec![
417
+ 19 , 7 , 2 , 7 , 225 , 135 , 19 , 1 , 2 , 50 , 23 , 0 , 113 , 1
418
+ ]
419
+ } ,
420
+ Section {
421
+ ty: SectionType :: Task ,
422
+ number: 1 ,
423
+ length: 51 ,
424
+ data: vec![
425
+ 20 , 0 , 2 , 50 , 0 , 20 , 1 , 2 , 5 , 0 , 19 , 1 , 0 , 0 , 36 ,
426
+ 0 , 0 , 1 , 0 , 133 , 66 , 0 , 89 , 0 , 0 , 8 , 20 , 1 , 2 , 254 ,
427
+ 255 , 39 , 13 , 133 , 2 , 0 , 11 , 0 , 0 , 6 , 20 , 1 , 2 , 2 ,
428
+ 0 , 67 , 2 , 100 , 0 , 39 , 168
429
+ ]
430
+ } ,
431
+ ] ,
432
+ symbols: vec![
433
+ Symbol {
434
+ ty: 1 ,
435
+ index: 0 ,
436
+ length: 8 ,
437
+ name: CString :: new( "set_fwd" ) . unwrap( )
438
+ } ,
439
+ Symbol {
440
+ ty: 0 ,
441
+ index: 0 ,
442
+ length: 5 ,
443
+ name: CString :: new( "main" ) . unwrap( )
444
+ } ,
445
+ Symbol {
446
+ ty: 0 ,
447
+ index: 1 ,
448
+ length: 10 ,
449
+ name: CString :: new( "loop_task" ) . unwrap( )
450
+ } ,
451
+ Symbol {
452
+ ty: 2 ,
453
+ index: 0 ,
454
+ length: 6 ,
455
+ name: CString :: new( "power" ) . unwrap( )
456
+ } ,
457
+ Symbol {
458
+ ty: 2 ,
459
+ index: 1 ,
460
+ length: 6 ,
461
+ name: CString :: new( "delta" ) . unwrap( )
462
+ }
463
+ ] ,
464
+ }
465
+ ) ;
466
+ }
289
467
}
0 commit comments