Skip to content

Commit 1fac951

Browse files
authored
Merge pull request #990 from mrcook/tzx-updates
TZX updates - mostly for easier JSON parsing
2 parents c99a8e0 + d3a5b8d commit 1fac951

File tree

4 files changed

+134
-101
lines changed

4 files changed

+134
-101
lines changed

format/tap/tap.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"bufio"
77
"bytes"
88
"embed"
9+
"fmt"
910

1011
"golang.org/x/text/encoding/charmap"
1112

@@ -54,9 +55,11 @@ func decodeTapBlock(d *decode.D) {
5455
// read header, fragment, or data block
5556
switch length {
5657
case 0:
57-
// fragment with no data
58+
d.Fatalf("TAP fragments with 0 bytes are not supported")
5859
case 1:
59-
d.FieldRawLen("data", 8)
60+
d.FieldStruct("data", func(d *decode.D) {
61+
d.FieldRawLen("bytes", 8)
62+
})
6063
case 19:
6164
d.FieldStruct("header", func(d *decode.D) {
6265
decodeHeader(d)
@@ -72,15 +75,34 @@ func decodeTapBlock(d *decode.D) {
7275
func decodeHeader(d *decode.D) {
7376
blockStartPosition := d.Pos()
7477

75-
// Always 0: byte indicating a standard ROM loading header
76-
d.FieldU8("flag", scalar.UintMapSymStr{0: "standard_speed_data"})
78+
// flag indicating the type of header block, usually 0 (standard speed data)
79+
d.FieldU8("flag", scalar.UintFn(func(s scalar.Uint) (scalar.Uint, error) {
80+
if s.Actual == 0x00 {
81+
s.Sym = "standard_speed_data"
82+
} else {
83+
s.Sym = "custom_data_block"
84+
}
85+
return s, nil
86+
}))
87+
7788
// Header type
78-
dataType := d.FieldU8("data_type", scalar.UintMapSymStr{
79-
0x00: "program",
80-
0x01: "numeric",
81-
0x02: "alphanumeric",
82-
0x03: "data",
83-
})
89+
dataType := d.FieldU8("data_type", scalar.UintFn(func(s scalar.Uint) (scalar.Uint, error) {
90+
switch s.Actual {
91+
case 0x00:
92+
s.Sym = "program"
93+
case 0x01:
94+
s.Sym = "numeric"
95+
case 0x02:
96+
s.Sym = "alphanumeric"
97+
case 0x03:
98+
s.Sym = "data"
99+
default:
100+
// unofficial header types
101+
s.Sym = fmt.Sprintf("unknown%02X", s.Actual)
102+
}
103+
return s, nil
104+
}))
105+
84106
// Loading name of the program. Filled with spaces (0x20) to 10 characters.
85107
d.FieldStr("program_name", 10, charmap.ISO8859_1)
86108

@@ -120,7 +142,10 @@ func decodeHeader(d *decode.D) {
120142
// UnusedWord: 32768.
121143
d.FieldU16("unused")
122144
default:
123-
d.Fatalf("invalid TAP header type, got: %d", dataType)
145+
// Unofficial header types
146+
d.FieldU16("data_length")
147+
d.FieldU16("unknown1", scalar.UintHex)
148+
d.FieldU16("unknown2", scalar.UintHex)
124149
}
125150

126151
// Simply all bytes XORed (including flag byte).
@@ -140,7 +165,8 @@ func decodeDataBlock(d *decode.D, length uint64) {
140165
return s, nil
141166
}))
142167
// The essential data: length minus the flag/checksum bytes (may be empty)
143-
d.FieldRawLen("data", int64(length-2)*8)
168+
d.FieldRawLen("bytes", int64(length-2)*8)
169+
144170
// Simply all bytes (including flag byte) XORed
145171
d.FieldU8("checksum", d.UintValidate(calculateChecksum(d, blockStartPosition, d.Pos()-blockStartPosition)), scalar.UintHex)
146172
}

format/tap/testdata/basic_prog1.fqtest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ $ fq -d tap dv basic_prog1.tap
1515
0x10| 28 00 | (. | length: 40 0x15-0x17 (2)
1616
| | | data{}: 0x17-0x3f (40)
1717
0x10| ff | . | flag: "standard_speed_data" (255) 0x17-0x18 (1)
18-
0x10| 00 0a 14 00 20 f5 22 66| .... ."f| data: raw bits 0x18-0x3e (38)
18+
0x10| 00 0a 14 00 20 f5 22 66| .... ."f| bytes: raw bits 0x18-0x3e (38)
1919
0x20|71 20 69 73 20 74 68 65 20 62 65 73 74 21 22 0d|q is the best!".|
2020
0x30|00 14 0a 00 ec 31 30 0e 00 00 0a 00 00 0d |.....10....... |
2121
0x30| b6| | .|| checksum: 0xb6 (valid) 0x3e-0x3f (1)

format/tzx/testdata/basic_prog1.fqtest

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,77 +5,80 @@ $ fq -d tzx dv basic_prog1.tzx
55
0x00| 14 | . | minor_version: 20 0x9-0xa (1)
66
| | | blocks[0:3]: 0xa-0xcd (195)
77
| | | [0]{}: block 0xa-0x88 (126)
8-
0x00| 32 | 2 | type: "archive_info" (50) 0xa-0xb (1)
9-
0x00| 7b 00 | {. | length: 123 0xb-0xd (2)
10-
0x00| 09 | . | count: 9 0xd-0xe (1)
11-
| | | archive_info[0:9]: 0xe-0x88 (122)
12-
| | | [0]{}: entry 0xe-0x1a (12)
13-
0x00| 00 | . | id: "title" (0) 0xe-0xf (1)
14-
0x00| 0a| .| length: 10 0xf-0x10 (1)
15-
0x10|66 71 74 65 73 74 70 72 6f 67 |fqtestprog | value: "fqtestprog" 0x10-0x1a (10)
16-
| | | [1]{}: entry 0x1a-0x21 (7)
17-
0x10| 01 | . | id: "publisher" (1) 0x1a-0x1b (1)
18-
0x10| 05 | . | length: 5 0x1b-0x1c (1)
19-
0x10| 77 61 64 65| wade| value: "wader" 0x1c-0x21 (5)
8+
| | | archive_info{}: 0xa-0x88 (126)
9+
0x00| 32 | 2 | type: "archive_info" (50) 0xa-0xb (1)
10+
0x00| 7b 00 | {. | length: 123 0xb-0xd (2)
11+
0x00| 09 | . | count: 9 0xd-0xe (1)
12+
| | | entries[0:9]: 0xe-0x88 (122)
13+
| | | [0]{}: entry 0xe-0x1a (12)
14+
0x00| 00 | . | id: "title" (0) 0xe-0xf (1)
15+
0x00| 0a| .| length: 10 0xf-0x10 (1)
16+
0x10|66 71 74 65 73 74 70 72 6f 67 |fqtestprog | value: "fqtestprog" 0x10-0x1a (10)
17+
| | | [1]{}: entry 0x1a-0x21 (7)
18+
0x10| 01 | . | id: "publisher" (1) 0x1a-0x1b (1)
19+
0x10| 05 | . | length: 5 0x1b-0x1c (1)
20+
0x10| 77 61 64 65| wade| value: "wader" 0x1c-0x21 (5)
2021
0x20|72 |r |
21-
| | | [2]{}: entry 0x21-0x32 (17)
22-
0x20| 02 | . | id: "author" (2) 0x21-0x22 (1)
23-
0x20| 0f | . | length: 15 0x22-0x23 (1)
24-
0x20| 4d 69 63 68 61 65 6c 20 52 2e 20 43 6f| Michael R. Co| value: "Michael R. Cook" 0x23-0x32 (15)
22+
| | | [2]{}: entry 0x21-0x32 (17)
23+
0x20| 02 | . | id: "author" (2) 0x21-0x22 (1)
24+
0x20| 0f | . | length: 15 0x22-0x23 (1)
25+
0x20| 4d 69 63 68 61 65 6c 20 52 2e 20 43 6f| Michael R. Co| value: "Michael R. Cook" 0x23-0x32 (15)
2526
0x30|6f 6b |ok |
26-
| | | [3]{}: entry 0x32-0x38 (6)
27-
0x30| 03 | . | id: "year" (3) 0x32-0x33 (1)
28-
0x30| 04 | . | length: 4 0x33-0x34 (1)
29-
0x30| 32 30 32 34 | 2024 | value: "2024" 0x34-0x38 (4)
30-
| | | [4]{}: entry 0x38-0x41 (9)
31-
0x30| 04 | . | id: "language" (4) 0x38-0x39 (1)
32-
0x30| 07 | . | length: 7 0x39-0x3a (1)
33-
0x30| 45 6e 67 6c 69 73| Englis| value: "English" 0x3a-0x41 (7)
27+
| | | [3]{}: entry 0x32-0x38 (6)
28+
0x30| 03 | . | id: "year" (3) 0x32-0x33 (1)
29+
0x30| 04 | . | length: 4 0x33-0x34 (1)
30+
0x30| 32 30 32 34 | 2024 | value: "2024" 0x34-0x38 (4)
31+
| | | [4]{}: entry 0x38-0x41 (9)
32+
0x30| 04 | . | id: "language" (4) 0x38-0x39 (1)
33+
0x30| 07 | . | length: 7 0x39-0x3a (1)
34+
0x30| 45 6e 67 6c 69 73| Englis| value: "English" 0x3a-0x41 (7)
3435
0x40|68 |h |
35-
| | | [5]{}: entry 0x41-0x4f (14)
36-
0x40| 05 | . | id: "category" (5) 0x41-0x42 (1)
37-
0x40| 0c | . | length: 12 0x42-0x43 (1)
38-
0x40| 54 65 73 74 20 50 72 6f 67 72 61 6d | Test Program | value: "Test Program" 0x43-0x4f (12)
39-
| | | [6]{}: entry 0x4f-0x5c (13)
40-
0x40| 07| .| id: "loader" (7) 0x4f-0x50 (1)
41-
0x50|0b |. | length: 11 0x50-0x51 (1)
42-
0x50| 52 4f 4d 20 74 69 6d 69 6e 67 73 | ROM timings | value: "ROM timings" 0x51-0x5c (11)
43-
| | | [7]{}: entry 0x5c-0x6e (18)
44-
0x50| 08 | . | id: "origin" (8) 0x5c-0x5d (1)
45-
0x50| 10 | . | length: 16 0x5d-0x5e (1)
46-
0x50| 4f 72| Or| value: "Original release" 0x5e-0x6e (16)
36+
| | | [5]{}: entry 0x41-0x4f (14)
37+
0x40| 05 | . | id: "category" (5) 0x41-0x42 (1)
38+
0x40| 0c | . | length: 12 0x42-0x43 (1)
39+
0x40| 54 65 73 74 20 50 72 6f 67 72 61 6d | Test Program | value: "Test Program" 0x43-0x4f (12)
40+
| | | [6]{}: entry 0x4f-0x5c (13)
41+
0x40| 07| .| id: "loader" (7) 0x4f-0x50 (1)
42+
0x50|0b |. | length: 11 0x50-0x51 (1)
43+
0x50| 52 4f 4d 20 74 69 6d 69 6e 67 73 | ROM timings | value: "ROM timings" 0x51-0x5c (11)
44+
| | | [7]{}: entry 0x5c-0x6e (18)
45+
0x50| 08 | . | id: "origin" (8) 0x5c-0x5d (1)
46+
0x50| 10 | . | length: 16 0x5d-0x5e (1)
47+
0x50| 4f 72| Or| value: "Original release" 0x5e-0x6e (16)
4748
0x60|69 67 69 6e 61 6c 20 72 65 6c 65 61 73 65 |iginal release |
48-
| | | [8]{}: entry 0x6e-0x88 (26)
49-
0x60| ff | . | id: "comment" (255) 0x6e-0x6f (1)
50-
0x60| 18| .| length: 24 0x6f-0x70 (1)
51-
0x70|54 5a 58 65 64 20 62 79 20 4d 69 63 68 61 65 6c|TZXed by Michael| value: "TZXed by Michael R. Cook" 0x70-0x88 (24)
49+
| | | [8]{}: entry 0x6e-0x88 (26)
50+
0x60| ff | . | id: "comment" (255) 0x6e-0x6f (1)
51+
0x60| 18| .| length: 24 0x6f-0x70 (1)
52+
0x70|54 5a 58 65 64 20 62 79 20 4d 69 63 68 61 65 6c|TZXed by Michael| value: "TZXed by Michael R. Cook" 0x70-0x88 (24)
5253
0x80|20 52 2e 20 43 6f 6f 6b | R. Cook |
5354
| | | [1]{}: block 0x88-0xa0 (24)
54-
0x80| 10 | . | type: "standard_speed_data" (16) 0x88-0x89 (1)
55-
0x80| e8 03 | .. | pause: 1000 0x89-0x8b (2)
56-
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0x8b-0xa0 (21)
57-
| | | blocks[0:1]: 0x8b-0xa0 (21)
58-
| | | [0]{}: block 0x8b-0xa0 (21)
59-
0x80| 13 00 | .. | length: 19 0x8b-0x8d (2)
60-
| | | header{}: 0x8d-0xa0 (19)
61-
0x80| 00 | . | flag: "standard_speed_data" (0) 0x8d-0x8e (1)
62-
0x80| 00 | . | data_type: "program" (0) 0x8e-0x8f (1)
63-
0x80| 66| f| program_name: "fqTestProg" 0x8f-0x99 (10)
55+
| | | standard_speed_data{}: 0x88-0xa0 (24)
56+
0x80| 10 | . | type: "standard_speed_data" (16) 0x88-0x89 (1)
57+
0x80| e8 03 | .. | pause: 1000 0x89-0x8b (2)
58+
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0x8b-0xa0 (21)
59+
| | | blocks[0:1]: 0x8b-0xa0 (21)
60+
| | | [0]{}: block 0x8b-0xa0 (21)
61+
0x80| 13 00 | .. | length: 19 0x8b-0x8d (2)
62+
| | | header{}: 0x8d-0xa0 (19)
63+
0x80| 00 | . | flag: "standard_speed_data" (0) 0x8d-0x8e (1)
64+
0x80| 00 | . | data_type: "program" (0) 0x8e-0x8f (1)
65+
0x80| 66| f| program_name: "fqTestProg" 0x8f-0x99 (10)
6466
0x90|71 54 65 73 74 50 72 6f 67 |qTestProg |
65-
0x90| 26 00 | &. | data_length: 38 0x99-0x9b (2)
66-
0x90| 0a 00 | .. | auto_start_line: 10 0x9b-0x9d (2)
67-
0x90| 26 00 | &. | program_length: 38 0x9d-0x9f (2)
68-
0x90| 01| .| checksum: 0x1 (valid) 0x9f-0xa0 (1)
67+
0x90| 26 00 | &. | data_length: 38 0x99-0x9b (2)
68+
0x90| 0a 00 | .. | auto_start_line: 10 0x9b-0x9d (2)
69+
0x90| 26 00 | &. | program_length: 38 0x9d-0x9f (2)
70+
0x90| 01| .| checksum: 0x1 (valid) 0x9f-0xa0 (1)
6971
| | | [2]{}: block 0xa0-0xcd (45)
70-
0xa0|10 |. | type: "standard_speed_data" (16) 0xa0-0xa1 (1)
71-
0xa0| e8 03 | .. | pause: 1000 0xa1-0xa3 (2)
72-
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0xa3-0xcd (42)
73-
| | | blocks[0:1]: 0xa3-0xcd (42)
74-
| | | [0]{}: block 0xa3-0xcd (42)
75-
0xa0| 28 00 | (. | length: 40 0xa3-0xa5 (2)
76-
| | | data{}: 0xa5-0xcd (40)
77-
0xa0| ff | . | flag: "standard_speed_data" (255) 0xa5-0xa6 (1)
78-
0xa0| 00 0a 14 00 20 f5 22 66 71 20| .... ."fq | data: raw bits 0xa6-0xcc (38)
72+
| | | standard_speed_data{}: 0xa0-0xcd (45)
73+
0xa0|10 |. | type: "standard_speed_data" (16) 0xa0-0xa1 (1)
74+
0xa0| e8 03 | .. | pause: 1000 0xa1-0xa3 (2)
75+
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0xa3-0xcd (42)
76+
| | | blocks[0:1]: 0xa3-0xcd (42)
77+
| | | [0]{}: block 0xa3-0xcd (42)
78+
0xa0| 28 00 | (. | length: 40 0xa3-0xa5 (2)
79+
| | | data{}: 0xa5-0xcd (40)
80+
0xa0| ff | . | flag: "standard_speed_data" (255) 0xa5-0xa6 (1)
81+
0xa0| 00 0a 14 00 20 f5 22 66 71 20| .... ."fq | bytes: raw bits 0xa6-0xcc (38)
7982
0xb0|69 73 20 74 68 65 20 62 65 73 74 21 22 0d 00 14|is the best!"...|
8083
0xc0|0a 00 ec 31 30 0e 00 00 0a 00 00 0d |...10....... |
81-
0xc0| b6| | .| | checksum: 0xb6 (valid) 0xcc-0xcd (1)
84+
0xc0| b6| | .| | checksum: 0xb6 (valid) 0xcc-0xcd (1)

0 commit comments

Comments
 (0)