mirror of
https://github.com/wader/fq.git
synced 2024-11-23 00:57:15 +03:00
tap: handle unoffical block types and minor improvements
To make it easier to parse the JSON output the header/data blocks are now wrapped in a FieldStruct, and data fields changed to be an array of uint8 values
This commit is contained in:
parent
56beac25b0
commit
633160bbd0
@ -6,6 +6,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/charmap"
|
"golang.org/x/text/encoding/charmap"
|
||||||
|
|
||||||
@ -54,9 +55,13 @@ func decodeTapBlock(d *decode.D) {
|
|||||||
// read header, fragment, or data block
|
// read header, fragment, or data block
|
||||||
switch length {
|
switch length {
|
||||||
case 0:
|
case 0:
|
||||||
// fragment with no data
|
d.Fatalf("TAP fragments with 0 bytes are not supported")
|
||||||
case 1:
|
case 1:
|
||||||
d.FieldRawLen("data", 8)
|
d.FieldStruct("data", func(d *decode.D) {
|
||||||
|
d.FieldArray("bytes", func(d *decode.D) {
|
||||||
|
d.FieldU8("byte")
|
||||||
|
})
|
||||||
|
})
|
||||||
case 19:
|
case 19:
|
||||||
d.FieldStruct("header", func(d *decode.D) {
|
d.FieldStruct("header", func(d *decode.D) {
|
||||||
decodeHeader(d)
|
decodeHeader(d)
|
||||||
@ -72,15 +77,34 @@ func decodeTapBlock(d *decode.D) {
|
|||||||
func decodeHeader(d *decode.D) {
|
func decodeHeader(d *decode.D) {
|
||||||
blockStartPosition := d.Pos()
|
blockStartPosition := d.Pos()
|
||||||
|
|
||||||
// Always 0: byte indicating a standard ROM loading header
|
// flag indicating the type of header block, usually 0 (standard speed data)
|
||||||
d.FieldU8("flag", scalar.UintMapSymStr{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
|
// Header type
|
||||||
dataType := d.FieldU8("data_type", scalar.UintMapSymStr{
|
dataType := d.FieldU8("data_type", scalar.UintFn(func(s scalar.Uint) (scalar.Uint, error) {
|
||||||
0x00: "program",
|
switch s.Actual {
|
||||||
0x01: "numeric",
|
case 0x00:
|
||||||
0x02: "alphanumeric",
|
s.Sym = "program"
|
||||||
0x03: "data",
|
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.
|
// Loading name of the program. Filled with spaces (0x20) to 10 characters.
|
||||||
d.FieldStr("program_name", 10, charmap.ISO8859_1)
|
d.FieldStr("program_name", 10, charmap.ISO8859_1)
|
||||||
|
|
||||||
@ -120,7 +144,10 @@ func decodeHeader(d *decode.D) {
|
|||||||
// UnusedWord: 32768.
|
// UnusedWord: 32768.
|
||||||
d.FieldU16("unused")
|
d.FieldU16("unused")
|
||||||
default:
|
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).
|
// Simply all bytes XORed (including flag byte).
|
||||||
@ -140,7 +167,12 @@ func decodeDataBlock(d *decode.D, length uint64) {
|
|||||||
return s, nil
|
return s, nil
|
||||||
}))
|
}))
|
||||||
// The essential data: length minus the flag/checksum bytes (may be empty)
|
// The essential data: length minus the flag/checksum bytes (may be empty)
|
||||||
d.FieldRawLen("data", int64(length-2)*8)
|
d.FieldArray("bytes", func(d *decode.D) {
|
||||||
|
for i := uint64(0); i < length-2; i++ {
|
||||||
|
d.FieldU8("byte")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Simply all bytes (including flag byte) XORed
|
// Simply all bytes (including flag byte) XORed
|
||||||
d.FieldU8("checksum", d.UintValidate(calculateChecksum(d, blockStartPosition, d.Pos()-blockStartPosition)), scalar.UintHex)
|
d.FieldU8("checksum", d.UintValidate(calculateChecksum(d, blockStartPosition, d.Pos()-blockStartPosition)), scalar.UintHex)
|
||||||
}
|
}
|
||||||
|
42
format/tap/testdata/basic_prog1.fqtest
vendored
42
format/tap/testdata/basic_prog1.fqtest
vendored
@ -15,7 +15,43 @@ $ fq -d tap dv basic_prog1.tap
|
|||||||
0x10| 28 00 | (. | length: 40 0x15-0x17 (2)
|
0x10| 28 00 | (. | length: 40 0x15-0x17 (2)
|
||||||
| | | data{}: 0x17-0x3f (40)
|
| | | data{}: 0x17-0x3f (40)
|
||||||
0x10| ff | . | flag: "standard_speed_data" (255) 0x17-0x18 (1)
|
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)
|
| | | bytes[0:38]: 0x18-0x3e (38)
|
||||||
0x20|71 20 69 73 20 74 68 65 20 62 65 73 74 21 22 0d|q is the best!".|
|
0x10| 00 | . | [0]: 0 byte 0x18-0x19 (1)
|
||||||
0x30|00 14 0a 00 ec 31 30 0e 00 00 0a 00 00 0d |.....10....... |
|
0x10| 0a | . | [1]: 10 byte 0x19-0x1a (1)
|
||||||
|
0x10| 14 | . | [2]: 20 byte 0x1a-0x1b (1)
|
||||||
|
0x10| 00 | . | [3]: 0 byte 0x1b-0x1c (1)
|
||||||
|
0x10| 20 | | [4]: 32 byte 0x1c-0x1d (1)
|
||||||
|
0x10| f5 | . | [5]: 245 byte 0x1d-0x1e (1)
|
||||||
|
0x10| 22 | " | [6]: 34 byte 0x1e-0x1f (1)
|
||||||
|
0x10| 66| f| [7]: 102 byte 0x1f-0x20 (1)
|
||||||
|
0x20|71 |q | [8]: 113 byte 0x20-0x21 (1)
|
||||||
|
0x20| 20 | | [9]: 32 byte 0x21-0x22 (1)
|
||||||
|
0x20| 69 | i | [10]: 105 byte 0x22-0x23 (1)
|
||||||
|
0x20| 73 | s | [11]: 115 byte 0x23-0x24 (1)
|
||||||
|
0x20| 20 | | [12]: 32 byte 0x24-0x25 (1)
|
||||||
|
0x20| 74 | t | [13]: 116 byte 0x25-0x26 (1)
|
||||||
|
0x20| 68 | h | [14]: 104 byte 0x26-0x27 (1)
|
||||||
|
0x20| 65 | e | [15]: 101 byte 0x27-0x28 (1)
|
||||||
|
0x20| 20 | | [16]: 32 byte 0x28-0x29 (1)
|
||||||
|
0x20| 62 | b | [17]: 98 byte 0x29-0x2a (1)
|
||||||
|
0x20| 65 | e | [18]: 101 byte 0x2a-0x2b (1)
|
||||||
|
0x20| 73 | s | [19]: 115 byte 0x2b-0x2c (1)
|
||||||
|
0x20| 74 | t | [20]: 116 byte 0x2c-0x2d (1)
|
||||||
|
0x20| 21 | ! | [21]: 33 byte 0x2d-0x2e (1)
|
||||||
|
0x20| 22 | " | [22]: 34 byte 0x2e-0x2f (1)
|
||||||
|
0x20| 0d| .| [23]: 13 byte 0x2f-0x30 (1)
|
||||||
|
0x30|00 |. | [24]: 0 byte 0x30-0x31 (1)
|
||||||
|
0x30| 14 | . | [25]: 20 byte 0x31-0x32 (1)
|
||||||
|
0x30| 0a | . | [26]: 10 byte 0x32-0x33 (1)
|
||||||
|
0x30| 00 | . | [27]: 0 byte 0x33-0x34 (1)
|
||||||
|
0x30| ec | . | [28]: 236 byte 0x34-0x35 (1)
|
||||||
|
0x30| 31 | 1 | [29]: 49 byte 0x35-0x36 (1)
|
||||||
|
0x30| 30 | 0 | [30]: 48 byte 0x36-0x37 (1)
|
||||||
|
0x30| 0e | . | [31]: 14 byte 0x37-0x38 (1)
|
||||||
|
0x30| 00 | . | [32]: 0 byte 0x38-0x39 (1)
|
||||||
|
0x30| 00 | . | [33]: 0 byte 0x39-0x3a (1)
|
||||||
|
0x30| 0a | . | [34]: 10 byte 0x3a-0x3b (1)
|
||||||
|
0x30| 00 | . | [35]: 0 byte 0x3b-0x3c (1)
|
||||||
|
0x30| 00 | . | [36]: 0 byte 0x3c-0x3d (1)
|
||||||
|
0x30| 0d | . | [37]: 13 byte 0x3d-0x3e (1)
|
||||||
0x30| b6| | .|| checksum: 0xb6 (valid) 0x3e-0x3f (1)
|
0x30| b6| | .|| checksum: 0xb6 (valid) 0x3e-0x3f (1)
|
||||||
|
Loading…
Reference in New Issue
Block a user