Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TZX updates - mostly for easier JSON parsing #990

Merged
merged 4 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions format/tap/tap.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"bufio"
"bytes"
"embed"
"fmt"

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

Expand Down Expand Up @@ -54,9 +55,11 @@ func decodeTapBlock(d *decode.D) {
// read header, fragment, or data block
switch length {
case 0:
// fragment with no data
d.Fatalf("TAP fragments with 0 bytes are not supported")
case 1:
d.FieldRawLen("data", 8)
d.FieldStruct("data", func(d *decode.D) {
d.FieldRawLen("bytes", 8)
})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be d.FieldRawLen again?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, mis-read. Is the struct around it needed?

Copy link
Contributor Author

@mrcook mrcook Aug 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to wrap each type of block to be able to distinguish between header and data blocks.

As a 1-byte data block there is no flag or checksum byte so this can not be passed to the decodeDataBlock() without that handling the length. So the struct is still useful to know the block type, and aid in JSON parsing.

I suppose another block type could be introduced, but that seems overkill for what is actually a rare occurrence.

Edited to add: I know of no useful purpose for such a 1-byte block

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha i see, makes sense

case 19:
d.FieldStruct("header", func(d *decode.D) {
decodeHeader(d)
Expand All @@ -72,15 +75,34 @@ func decodeTapBlock(d *decode.D) {
func decodeHeader(d *decode.D) {
blockStartPosition := d.Pos()

// Always 0: byte indicating a standard ROM loading header
d.FieldU8("flag", scalar.UintMapSymStr{0: "standard_speed_data"})
// flag indicating the type of header block, usually 0 (standard speed data)
d.FieldU8("flag", scalar.UintFn(func(s scalar.Uint) (scalar.Uint, error) {
if s.Actual == 0x00 {
s.Sym = "standard_speed_data"
} else {
s.Sym = "custom_data_block"
}
return s, nil
}))

// Header type
dataType := d.FieldU8("data_type", scalar.UintMapSymStr{
0x00: "program",
0x01: "numeric",
0x02: "alphanumeric",
0x03: "data",
})
dataType := d.FieldU8("data_type", scalar.UintFn(func(s scalar.Uint) (scalar.Uint, error) {
switch s.Actual {
case 0x00:
s.Sym = "program"
case 0x01:
s.Sym = "numeric"
case 0x02:
s.Sym = "alphanumeric"
case 0x03:
s.Sym = "data"
default:
// unofficial header types
s.Sym = fmt.Sprintf("unknown%02X", s.Actual)
}
return s, nil
}))

// Loading name of the program. Filled with spaces (0x20) to 10 characters.
d.FieldStr("program_name", 10, charmap.ISO8859_1)

Expand Down Expand Up @@ -120,7 +142,10 @@ func decodeHeader(d *decode.D) {
// UnusedWord: 32768.
d.FieldU16("unused")
default:
d.Fatalf("invalid TAP header type, got: %d", dataType)
// Unofficial header types
d.FieldU16("data_length")
d.FieldU16("unknown1", scalar.UintHex)
d.FieldU16("unknown2", scalar.UintHex)
}

// Simply all bytes XORed (including flag byte).
Expand All @@ -140,7 +165,8 @@ func decodeDataBlock(d *decode.D, length uint64) {
return s, nil
}))
// The essential data: length minus the flag/checksum bytes (may be empty)
d.FieldRawLen("data", int64(length-2)*8)
d.FieldRawLen("bytes", int64(length-2)*8)

// Simply all bytes (including flag byte) XORed
d.FieldU8("checksum", d.UintValidate(calculateChecksum(d, blockStartPosition, d.Pos()-blockStartPosition)), scalar.UintHex)
}
Expand Down
2 changes: 1 addition & 1 deletion format/tap/testdata/basic_prog1.fqtest
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $ fq -d tap dv basic_prog1.tap
0x10| 28 00 | (. | length: 40 0x15-0x17 (2)
| | | data{}: 0x17-0x3f (40)
0x10| ff | . | flag: "standard_speed_data" (255) 0x17-0x18 (1)
0x10| 00 0a 14 00 20 f5 22 66| .... ."f| data: raw bits 0x18-0x3e (38)
0x10| 00 0a 14 00 20 f5 22 66| .... ."f| bytes: raw bits 0x18-0x3e (38)
0x20|71 20 69 73 20 74 68 65 20 62 65 73 74 21 22 0d|q is the best!".|
0x30|00 14 0a 00 ec 31 30 0e 00 00 0a 00 00 0d |.....10....... |
0x30| b6| | .|| checksum: 0xb6 (valid) 0x3e-0x3f (1)
131 changes: 67 additions & 64 deletions format/tzx/testdata/basic_prog1.fqtest
Original file line number Diff line number Diff line change
Expand Up @@ -5,77 +5,80 @@ $ fq -d tzx dv basic_prog1.tzx
0x00| 14 | . | minor_version: 20 0x9-0xa (1)
| | | blocks[0:3]: 0xa-0xcd (195)
| | | [0]{}: block 0xa-0x88 (126)
0x00| 32 | 2 | type: "archive_info" (50) 0xa-0xb (1)
0x00| 7b 00 | {. | length: 123 0xb-0xd (2)
0x00| 09 | . | count: 9 0xd-0xe (1)
| | | archive_info[0:9]: 0xe-0x88 (122)
| | | [0]{}: entry 0xe-0x1a (12)
0x00| 00 | . | id: "title" (0) 0xe-0xf (1)
0x00| 0a| .| length: 10 0xf-0x10 (1)
0x10|66 71 74 65 73 74 70 72 6f 67 |fqtestprog | value: "fqtestprog" 0x10-0x1a (10)
| | | [1]{}: entry 0x1a-0x21 (7)
0x10| 01 | . | id: "publisher" (1) 0x1a-0x1b (1)
0x10| 05 | . | length: 5 0x1b-0x1c (1)
0x10| 77 61 64 65| wade| value: "wader" 0x1c-0x21 (5)
| | | archive_info{}: 0xa-0x88 (126)
0x00| 32 | 2 | type: "archive_info" (50) 0xa-0xb (1)
0x00| 7b 00 | {. | length: 123 0xb-0xd (2)
0x00| 09 | . | count: 9 0xd-0xe (1)
| | | entries[0:9]: 0xe-0x88 (122)
| | | [0]{}: entry 0xe-0x1a (12)
0x00| 00 | . | id: "title" (0) 0xe-0xf (1)
0x00| 0a| .| length: 10 0xf-0x10 (1)
0x10|66 71 74 65 73 74 70 72 6f 67 |fqtestprog | value: "fqtestprog" 0x10-0x1a (10)
| | | [1]{}: entry 0x1a-0x21 (7)
0x10| 01 | . | id: "publisher" (1) 0x1a-0x1b (1)
0x10| 05 | . | length: 5 0x1b-0x1c (1)
0x10| 77 61 64 65| wade| value: "wader" 0x1c-0x21 (5)
0x20|72 |r |
| | | [2]{}: entry 0x21-0x32 (17)
0x20| 02 | . | id: "author" (2) 0x21-0x22 (1)
0x20| 0f | . | length: 15 0x22-0x23 (1)
0x20| 4d 69 63 68 61 65 6c 20 52 2e 20 43 6f| Michael R. Co| value: "Michael R. Cook" 0x23-0x32 (15)
| | | [2]{}: entry 0x21-0x32 (17)
0x20| 02 | . | id: "author" (2) 0x21-0x22 (1)
0x20| 0f | . | length: 15 0x22-0x23 (1)
0x20| 4d 69 63 68 61 65 6c 20 52 2e 20 43 6f| Michael R. Co| value: "Michael R. Cook" 0x23-0x32 (15)
0x30|6f 6b |ok |
| | | [3]{}: entry 0x32-0x38 (6)
0x30| 03 | . | id: "year" (3) 0x32-0x33 (1)
0x30| 04 | . | length: 4 0x33-0x34 (1)
0x30| 32 30 32 34 | 2024 | value: "2024" 0x34-0x38 (4)
| | | [4]{}: entry 0x38-0x41 (9)
0x30| 04 | . | id: "language" (4) 0x38-0x39 (1)
0x30| 07 | . | length: 7 0x39-0x3a (1)
0x30| 45 6e 67 6c 69 73| Englis| value: "English" 0x3a-0x41 (7)
| | | [3]{}: entry 0x32-0x38 (6)
0x30| 03 | . | id: "year" (3) 0x32-0x33 (1)
0x30| 04 | . | length: 4 0x33-0x34 (1)
0x30| 32 30 32 34 | 2024 | value: "2024" 0x34-0x38 (4)
| | | [4]{}: entry 0x38-0x41 (9)
0x30| 04 | . | id: "language" (4) 0x38-0x39 (1)
0x30| 07 | . | length: 7 0x39-0x3a (1)
0x30| 45 6e 67 6c 69 73| Englis| value: "English" 0x3a-0x41 (7)
0x40|68 |h |
| | | [5]{}: entry 0x41-0x4f (14)
0x40| 05 | . | id: "category" (5) 0x41-0x42 (1)
0x40| 0c | . | length: 12 0x42-0x43 (1)
0x40| 54 65 73 74 20 50 72 6f 67 72 61 6d | Test Program | value: "Test Program" 0x43-0x4f (12)
| | | [6]{}: entry 0x4f-0x5c (13)
0x40| 07| .| id: "loader" (7) 0x4f-0x50 (1)
0x50|0b |. | length: 11 0x50-0x51 (1)
0x50| 52 4f 4d 20 74 69 6d 69 6e 67 73 | ROM timings | value: "ROM timings" 0x51-0x5c (11)
| | | [7]{}: entry 0x5c-0x6e (18)
0x50| 08 | . | id: "origin" (8) 0x5c-0x5d (1)
0x50| 10 | . | length: 16 0x5d-0x5e (1)
0x50| 4f 72| Or| value: "Original release" 0x5e-0x6e (16)
| | | [5]{}: entry 0x41-0x4f (14)
0x40| 05 | . | id: "category" (5) 0x41-0x42 (1)
0x40| 0c | . | length: 12 0x42-0x43 (1)
0x40| 54 65 73 74 20 50 72 6f 67 72 61 6d | Test Program | value: "Test Program" 0x43-0x4f (12)
| | | [6]{}: entry 0x4f-0x5c (13)
0x40| 07| .| id: "loader" (7) 0x4f-0x50 (1)
0x50|0b |. | length: 11 0x50-0x51 (1)
0x50| 52 4f 4d 20 74 69 6d 69 6e 67 73 | ROM timings | value: "ROM timings" 0x51-0x5c (11)
| | | [7]{}: entry 0x5c-0x6e (18)
0x50| 08 | . | id: "origin" (8) 0x5c-0x5d (1)
0x50| 10 | . | length: 16 0x5d-0x5e (1)
0x50| 4f 72| Or| value: "Original release" 0x5e-0x6e (16)
0x60|69 67 69 6e 61 6c 20 72 65 6c 65 61 73 65 |iginal release |
| | | [8]{}: entry 0x6e-0x88 (26)
0x60| ff | . | id: "comment" (255) 0x6e-0x6f (1)
0x60| 18| .| length: 24 0x6f-0x70 (1)
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)
| | | [8]{}: entry 0x6e-0x88 (26)
0x60| ff | . | id: "comment" (255) 0x6e-0x6f (1)
0x60| 18| .| length: 24 0x6f-0x70 (1)
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)
0x80|20 52 2e 20 43 6f 6f 6b | R. Cook |
| | | [1]{}: block 0x88-0xa0 (24)
0x80| 10 | . | type: "standard_speed_data" (16) 0x88-0x89 (1)
0x80| e8 03 | .. | pause: 1000 0x89-0x8b (2)
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0x8b-0xa0 (21)
| | | blocks[0:1]: 0x8b-0xa0 (21)
| | | [0]{}: block 0x8b-0xa0 (21)
0x80| 13 00 | .. | length: 19 0x8b-0x8d (2)
| | | header{}: 0x8d-0xa0 (19)
0x80| 00 | . | flag: "standard_speed_data" (0) 0x8d-0x8e (1)
0x80| 00 | . | data_type: "program" (0) 0x8e-0x8f (1)
0x80| 66| f| program_name: "fqTestProg" 0x8f-0x99 (10)
| | | standard_speed_data{}: 0x88-0xa0 (24)
0x80| 10 | . | type: "standard_speed_data" (16) 0x88-0x89 (1)
0x80| e8 03 | .. | pause: 1000 0x89-0x8b (2)
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0x8b-0xa0 (21)
| | | blocks[0:1]: 0x8b-0xa0 (21)
| | | [0]{}: block 0x8b-0xa0 (21)
0x80| 13 00 | .. | length: 19 0x8b-0x8d (2)
| | | header{}: 0x8d-0xa0 (19)
0x80| 00 | . | flag: "standard_speed_data" (0) 0x8d-0x8e (1)
0x80| 00 | . | data_type: "program" (0) 0x8e-0x8f (1)
0x80| 66| f| program_name: "fqTestProg" 0x8f-0x99 (10)
0x90|71 54 65 73 74 50 72 6f 67 |qTestProg |
0x90| 26 00 | &. | data_length: 38 0x99-0x9b (2)
0x90| 0a 00 | .. | auto_start_line: 10 0x9b-0x9d (2)
0x90| 26 00 | &. | program_length: 38 0x9d-0x9f (2)
0x90| 01| .| checksum: 0x1 (valid) 0x9f-0xa0 (1)
0x90| 26 00 | &. | data_length: 38 0x99-0x9b (2)
0x90| 0a 00 | .. | auto_start_line: 10 0x9b-0x9d (2)
0x90| 26 00 | &. | program_length: 38 0x9d-0x9f (2)
0x90| 01| .| checksum: 0x1 (valid) 0x9f-0xa0 (1)
| | | [2]{}: block 0xa0-0xcd (45)
0xa0|10 |. | type: "standard_speed_data" (16) 0xa0-0xa1 (1)
0xa0| e8 03 | .. | pause: 1000 0xa1-0xa3 (2)
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0xa3-0xcd (42)
| | | blocks[0:1]: 0xa3-0xcd (42)
| | | [0]{}: block 0xa3-0xcd (42)
0xa0| 28 00 | (. | length: 40 0xa3-0xa5 (2)
| | | data{}: 0xa5-0xcd (40)
0xa0| ff | . | flag: "standard_speed_data" (255) 0xa5-0xa6 (1)
0xa0| 00 0a 14 00 20 f5 22 66 71 20| .... ."fq | data: raw bits 0xa6-0xcc (38)
| | | standard_speed_data{}: 0xa0-0xcd (45)
0xa0|10 |. | type: "standard_speed_data" (16) 0xa0-0xa1 (1)
0xa0| e8 03 | .. | pause: 1000 0xa1-0xa3 (2)
|00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f|0123456789abcdef| tap{}: (tap) 0xa3-0xcd (42)
| | | blocks[0:1]: 0xa3-0xcd (42)
| | | [0]{}: block 0xa3-0xcd (42)
0xa0| 28 00 | (. | length: 40 0xa3-0xa5 (2)
| | | data{}: 0xa5-0xcd (40)
0xa0| ff | . | flag: "standard_speed_data" (255) 0xa5-0xa6 (1)
0xa0| 00 0a 14 00 20 f5 22 66 71 20| .... ."fq | bytes: raw bits 0xa6-0xcc (38)
0xb0|69 73 20 74 68 65 20 62 65 73 74 21 22 0d 00 14|is the best!"...|
0xc0|0a 00 ec 31 30 0e 00 00 0a 00 00 0d |...10....... |
0xc0| b6| | .| | checksum: 0xb6 (valid) 0xcc-0xcd (1)
0xc0| b6| | .| | checksum: 0xb6 (valid) 0xcc-0xcd (1)
Loading
Loading