-
Notifications
You must be signed in to change notification settings - Fork 240
TZX updates - mostly for easier JSON parsing #990
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
Changes from 2 commits
633160b
fc350f3
d384930
d3a5b8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import ( | |
| "bufio" | ||
| "bytes" | ||
| "embed" | ||
| "fmt" | ||
|
|
||
| "golang.org/x/text/encoding/charmap" | ||
|
|
||
|
|
@@ -54,9 +55,13 @@ 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.FieldArray("bytes", func(d *decode.D) { | ||
| d.FieldU8("byte") | ||
| }) | ||
| }) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, mis-read. Is the struct around it needed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 As a 1-byte data block there is no 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
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
|
|
@@ -72,15 +77,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) | ||
|
|
||
|
|
@@ -120,7 +144,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). | ||
|
|
@@ -140,7 +167,12 @@ 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.FieldArray("bytes", func(d *decode.D) { | ||
| for i := uint64(0); i < length-2; i++ { | ||
| d.FieldU8("byte") | ||
| } | ||
| }) | ||
|
|
||
| // Simply all bytes (including flag byte) XORed | ||
| d.FieldU8("checksum", d.UintValidate(calculateChecksum(d, blockStartPosition, d.Pos()-blockStartPosition)), scalar.UintHex) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if an alternative to this is some improvements of how raw fields can be turned into JSON? maybe easiest to show a demo how it works at the moment. Here i use
[1,2,3] | tobytesto get a raw field aka a "binary"The alternative could be to add a
-o bits_format=arrayetc that turns binary into a byte array? so it would be something like this:but maybe
arrayis not good name, maybe "bytes_array"? 🤔There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did see that
tobytes, but it seems to only be useful when you want to pull out just one field. For my tests I would just runfq -d tzx -V d file.tzxbut that messes up the JSON.Is there a way to use that
tobyteswhen generating the whole thing as a JSON?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap the
bits_formatoption controls how binary values (note they store bits not bytes, but are usually zero bit padded to be byte aligned) should be represented as JSON. I made quick hack to add a bytes_array options here https://github.com/wader/fq/tree/bits-format-bytes-arrayThe
tobytesfunction can used to convert things into a binary, strings, array of numbers etc. But one can use theexplodefunction on a binary to gets bytes... there is even atobitsSorry that all this is a bit undocumented, is still a bit work in progress but i haven't worked on it much lately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem Mattias, and thanks for the info. I'll check it out later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would be best, it's a bit sad that JSON has no binary safe type :( so it's a bit of a tradeoff how to represent it, always a byte array would probably be inconvenient with other formats.
But it's probably a good idea to document your uses cases as examples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Mattias, is this something I should leave to you, or do you want me to add it to my PR?
Regarding the naming:
bytes_arrayseems reasonable.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great 👍 will review tomorrow and you can leave it to me do a proper
bytes_arrayPR tomorrow with docs and tests and also