1
1
mirror of https://github.com/wader/fq.git synced 2024-09-11 12:05:39 +03:00

tzx: change data fields to array of bytes for easier JSON parsing

This commit is contained in:
Michael R. Cook 2024-08-15 20:13:03 +02:00
parent 633160bbd0
commit fc350f3da5
2 changed files with 162 additions and 93 deletions

View File

@ -5,77 +5,116 @@ $ 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)
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)
| | | 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)
| | | bytes[0:38]: 0xa6-0xcc (38)
0xa0| 00 | . | [0]: 0 byte 0xa6-0xa7 (1)
0xa0| 0a | . | [1]: 10 byte 0xa7-0xa8 (1)
0xa0| 14 | . | [2]: 20 byte 0xa8-0xa9 (1)
0xa0| 00 | . | [3]: 0 byte 0xa9-0xaa (1)
0xa0| 20 | | [4]: 32 byte 0xaa-0xab (1)
0xa0| f5 | . | [5]: 245 byte 0xab-0xac (1)
0xa0| 22 | " | [6]: 34 byte 0xac-0xad (1)
0xa0| 66 | f | [7]: 102 byte 0xad-0xae (1)
0xa0| 71 | q | [8]: 113 byte 0xae-0xaf (1)
0xa0| 20| | [9]: 32 byte 0xaf-0xb0 (1)
0xb0|69 |i | [10]: 105 byte 0xb0-0xb1 (1)
0xb0| 73 | s | [11]: 115 byte 0xb1-0xb2 (1)
0xb0| 20 | | [12]: 32 byte 0xb2-0xb3 (1)
0xb0| 74 | t | [13]: 116 byte 0xb3-0xb4 (1)
0xb0| 68 | h | [14]: 104 byte 0xb4-0xb5 (1)
0xb0| 65 | e | [15]: 101 byte 0xb5-0xb6 (1)
0xb0| 20 | | [16]: 32 byte 0xb6-0xb7 (1)
0xb0| 62 | b | [17]: 98 byte 0xb7-0xb8 (1)
0xb0| 65 | e | [18]: 101 byte 0xb8-0xb9 (1)
0xb0| 73 | s | [19]: 115 byte 0xb9-0xba (1)
0xb0| 74 | t | [20]: 116 byte 0xba-0xbb (1)
0xb0| 21 | ! | [21]: 33 byte 0xbb-0xbc (1)
0xb0| 22 | " | [22]: 34 byte 0xbc-0xbd (1)
0xb0| 0d | . | [23]: 13 byte 0xbd-0xbe (1)
0xb0| 00 | . | [24]: 0 byte 0xbe-0xbf (1)
0xb0| 14| .| [25]: 20 byte 0xbf-0xc0 (1)
0xc0|0a |. | [26]: 10 byte 0xc0-0xc1 (1)
0xc0| 00 | . | [27]: 0 byte 0xc1-0xc2 (1)
0xc0| ec | . | [28]: 236 byte 0xc2-0xc3 (1)
0xc0| 31 | 1 | [29]: 49 byte 0xc3-0xc4 (1)
0xc0| 30 | 0 | [30]: 48 byte 0xc4-0xc5 (1)
0xc0| 0e | . | [31]: 14 byte 0xc5-0xc6 (1)
0xc0| 00 | . | [32]: 0 byte 0xc6-0xc7 (1)
0xc0| 00 | . | [33]: 0 byte 0xc7-0xc8 (1)
0xc0| 0a | . | [34]: 10 byte 0xc8-0xc9 (1)
0xc0| 00 | . | [35]: 0 byte 0xc9-0xca (1)
0xc0| 00 | . | [36]: 0 byte 0xca-0xcb (1)
0xc0| 0d | . | [37]: 13 byte 0xcb-0xcc (1)
0xc0| b6| | .| | checksum: 0xb6 (valid) 0xcc-0xcd (1)

View File

@ -97,7 +97,11 @@ func decodeBlock(d *decode.D) {
length := d.FieldU24("length") // Length of data that follows
// Data as in .TAP files
d.FieldRawLen("data", int64(length*8))
d.FieldArray("data", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 12h (18d) | Pure Tone
@ -131,7 +135,11 @@ func decodeBlock(d *decode.D) {
length := d.FieldU24("length") // Length of data that follows
// Data as in .TAP files
d.FieldRawLen("data", int64(length*8))
d.FieldArray("data", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 15h (21d) | Direct Recording
@ -143,11 +151,17 @@ func decodeBlock(d *decode.D) {
// The preferred sampling frequencies are 22050 or 44100 Hz
// (158 or 79 T-states/sample).
0x15: func(d *decode.D) {
d.FieldU16("t_states") // Number of T-states per sample (bit of data)
d.FieldU16("pause") // Pause after this block in milliseconds (ms.)
d.FieldU8("used_bits") // Used bits (samples) in last byte of data (1-8)
length := d.FieldU24("length") // Length of data that follows
d.FieldRawLen("data", int64(length*8)) // Samples data. Each bit represents a state on the EAR port
d.FieldU16("t_states") // Number of T-states per sample (bit of data)
d.FieldU16("pause") // Pause after this block in milliseconds (ms.)
d.FieldU8("used_bits") // Used bits (samples) in last byte of data (1-8)
length := d.FieldU24("length") // Length of data that follows
// Samples data. Each bit represents a state on the EAR port
d.FieldArray("data", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 18h (24d) | CSW Recording
@ -165,12 +179,16 @@ func decodeBlock(d *decode.D) {
// Sampling rate
d.FieldU24("sample_rate")
// Compression type
d.FieldU8("compression_type", scalar.UintMapSymStr{0x01: "rle", 0x02: "zrle"})
d.FieldU8("compression_type", scalar.UintMapSymStr{0x00: "unknown", 0x01: "rle", 0x02: "zrle"})
// Number of stored pulses (after decompression)
d.FieldU32("stored_pulse_count")
// CSW data, encoded according to the CSW specification
d.FieldRawLen("data", int64(length*8))
d.FieldArray("data", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 19h (25d) | Generalized Data
@ -194,7 +212,11 @@ func decodeBlock(d *decode.D) {
// PilotStreams []PilotRLE // 0x12+ (2*NPP+1)*ASP - PRLE[TOTP] Pilot and sync data stream
// DataSymbols []Symbol // 0x12+ (TOTP>0)*((2*NPP+1)*ASP)+TOTP*3 - SYMDEF[ASD] Data symbols definition table
// DataStreams []uint8 // 0x12+ (TOTP>0)*((2*NPP+1)*ASP)+ TOTP*3+(2*NPD+1)*ASD - BYTE[DS] Data stream
d.FieldRawLen("data", int64(length*8))
d.FieldArray("data", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 20h (32d) | Pause Tape Command
@ -340,7 +362,7 @@ func decodeBlock(d *decode.D) {
count := d.FieldU8("count") // Number of entries in the archive info
// the archive strings
d.FieldArray("archive_info", func(d *decode.D) {
d.FieldArray("entries", func(d *decode.D) {
for i := uint64(0); i < count; i++ {
d.FieldStruct("entry", func(d *decode.D) {
d.FieldU8("id", scalar.UintMapSymStr{
@ -372,11 +394,11 @@ func decodeBlock(d *decode.D) {
for i := uint64(0); i < count; i++ {
d.FieldStruct("info", func(d *decode.D) {
// Hardware Type ID (computers, printers, mice, etc.)
typeId := d.FieldU8("type", hwInfoTypeMapper)
// Hardware ID (ZX81, Kempston Joystick, etc.)
d.FieldU8("id", hwInfoTypeIdMapper[typeId])
typeId := d.FieldU8("type_id", hwInfoTypes)
// Hardware Device ID (ZX81, Kempston Joystick, etc.)
d.FieldU8("device_id", hwInfoDevices[typeId])
// Hardware compatibility information
d.FieldU8("info_id", hwInfoIdMapper)
d.FieldU8("info_id", hwInfoCompatibilityInfo)
})
}
})
@ -389,7 +411,11 @@ func decodeBlock(d *decode.D) {
0x35: func(d *decode.D) {
d.FieldStr("identification", 10, charmap.ISO8859_1)
length := d.FieldU32("length")
d.FieldRawLen("info", int64(length*8))
d.FieldArray("info", func(d *decode.D) {
for i := uint64(0); i < length; i++ {
d.FieldU8("byte")
}
})
},
// ID: 5Ah (90d) | Glue Block
@ -404,22 +430,26 @@ func decodeBlock(d *decode.D) {
0x5A: func(d *decode.D) {
// Value: { "XTape!",0x1A,MajR,MinR }
// Just skip these 9 bytes and you will end up on the next ID.
d.FieldRawLen("value", int64(9*8))
d.FieldRawLen("value", 9*8)
},
}
blockType := d.FieldU8("type", blockTypeMapper)
blockType := d.PeekUintBits(8)
// Deprecated block types: C64RomType, C64TurboData, EmulationInfo, Snapshot
if blockType == 0x16 || blockType == 0x17 || blockType == 0x34 || blockType == 0x40 {
d.Fatalf("deprecated block type encountered: %02x", blockType)
}
if fn, ok := blocks[blockType]; ok {
fn(d)
} else {
d.Fatalf("block type not valid, got: %02x", blockType)
}
blockLabel := blockTypeMapper[blockType]
d.FieldStruct(blockLabel, func(d *decode.D) {
d.FieldU8("type", blockTypeMapper)
if fn, ok := blocks[blockType]; ok {
fn(d)
} else {
d.Fatalf("block type not valid, got: %02x", blockType)
}
})
}
var blockTypeMapper = scalar.UintMapSymStr{
@ -454,7 +484,7 @@ var blockTypeMapper = scalar.UintMapSymStr{
0x5A: "glue_block",
}
var hwInfoTypeMapper = scalar.UintMapDescription{
var hwInfoTypes = scalar.UintMapDescription{
0x00: "Computers",
0x01: "External storage",
0x02: "ROM/RAM type add-ons",
@ -474,7 +504,7 @@ var hwInfoTypeMapper = scalar.UintMapDescription{
0x10: "Graphics",
}
var hwInfoTypeIdMapper = map[uint64]scalar.UintMapDescription{
var hwInfoDevices = map[uint64]scalar.UintMapDescription{
0x00: { // Computers
0x00: "ZX Spectrum 16k",
0x01: "ZX Spectrum 48k, Plus",
@ -647,7 +677,7 @@ var hwInfoTypeIdMapper = map[uint64]scalar.UintMapDescription{
},
}
var hwInfoIdMapper = scalar.UintMapDescription{
var hwInfoCompatibilityInfo = scalar.UintMapDescription{
00: "RUNS on this machine or with this hardware, but may or may not use the hardware or special features of the machine.",
01: "USES the hardware or special features of the machine, such as extra memory or a sound chip.",
02: "RUNS but it DOESN'T use the hardware or special features of the machine.",