From 980ecdba8209faf901388d1255f6e76c729055f1 Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Fri, 10 Mar 2023 01:14:53 +0100 Subject: [PATCH] decode: Add float 80 reader Rename *d.Bits to UintBits as it return a uint Add *d.Bits that return []byte --- format/asn1/asn1_ber.go | 2 +- format/bencode/bencode.go | 4 +- format/bitcoin/bitcoin_block.go | 2 +- format/bitcoin/bitcoin_script.go | 2 +- format/bitcoin/bitcoin_transaction.go | 2 +- format/bzip2/bzip2.go | 2 +- format/cbor/cbor.go | 8 +- format/dns/dns.go | 2 +- format/gif/gif.go | 6 +- format/id3/id3v1.go | 2 +- format/id3/id3v2.go | 4 +- format/jpeg/jpeg.go | 2 +- format/matroska/matroska.go | 2 +- format/mp4/boxes.go | 6 +- format/mpeg/avc_pps.go | 2 +- format/mpeg/mpeg_pes.go | 2 +- format/mpeg/mpeg_pes_packet.go | 4 +- format/mpeg/mpeg_spu.go | 2 +- format/riff/aiff.go | 5 +- format/rtmp/amf0.go | 6 +- format/rtmp/rtmp.go | 2 +- format/tls/tls.go | 2 +- pkg/decode/decode.go | 45 ++++++--- pkg/decode/decode_gen.go | 138 ++++++++++++++++++++++++++ pkg/decode/read.go | 23 +++-- pkg/decode/types.json | 21 ++++ 26 files changed, 239 insertions(+), 59 deletions(-) diff --git a/format/asn1/asn1_ber.go b/format/asn1/asn1_ber.go index ef9810fb4..c63f5e8f2 100644 --- a/format/asn1/asn1_ber.go +++ b/format/asn1/asn1_ber.go @@ -202,7 +202,7 @@ func decodeASN1BERValue(d *decode.D, bib *bitio.Buffer, sb *strings.Builder, par case form == formConstructed || tag == universalTypeSequence || tag == universalTypeSet: d.FieldArray("constructed", func(d *decode.D) { for !d.End() { - if length == lengthIndefinite && d.PeekBits(16) == lengthEndMarker { + if length == lengthIndefinite && d.PeekUintBits(16) == lengthEndMarker { break } diff --git a/format/bencode/bencode.go b/format/bencode/bencode.go index 9ad7e9454..4827131cd 100644 --- a/format/bencode/bencode.go +++ b/format/bencode/bencode.go @@ -71,14 +71,14 @@ func decodeBencodeValue(d *decode.D) { d.FieldUTF8("end", 1, d.StrAssert("e")) case "l": d.FieldArray("values", func(d *decode.D) { - for d.PeekBits(8) != 'e' { + for d.PeekUintBits(8) != 'e' { d.FieldStruct("value", decodeBencodeValue) } }) d.FieldUTF8("end", 1, d.StrAssert("e")) case "d": d.FieldArray("pairs", func(d *decode.D) { - for d.PeekBits(8) != 'e' { + for d.PeekUintBits(8) != 'e' { d.FieldStruct("pair", func(d *decode.D) { d.FieldStruct("key", decodeBencodeValue) d.FieldStruct("value", decodeBencodeValue) diff --git a/format/bitcoin/bitcoin_block.go b/format/bitcoin/bitcoin_block.go index 94203ec9c..4312ede9a 100644 --- a/format/bitcoin/bitcoin_block.go +++ b/format/bitcoin/bitcoin_block.go @@ -42,7 +42,7 @@ func decodeBitcoinBlock(d *decode.D) any { size := d.BitsLeft() if bbi.HasHeader { - magic := d.PeekBits(32) + magic := d.PeekUintBits(32) switch magic { case 0xf9beb4d9, 0x0b110907, diff --git a/format/bitcoin/bitcoin_script.go b/format/bitcoin/bitcoin_script.go index 7d1e48889..bef77c879 100644 --- a/format/bitcoin/bitcoin_script.go +++ b/format/bitcoin/bitcoin_script.go @@ -171,7 +171,7 @@ func decodeBitcoinScript(d *decode.D) any { } for !d.End() { - opcode := byte(d.PeekBits(8)) + opcode := byte(d.PeekUintBits(8)) ope, ok := opcodeEntries.lookup(opcode) if !ok { d.Fatalf("unknown opcode %x", opcode) diff --git a/format/bitcoin/bitcoin_transaction.go b/format/bitcoin/bitcoin_transaction.go index 310874d4a..cad5864d2 100644 --- a/format/bitcoin/bitcoin_transaction.go +++ b/format/bitcoin/bitcoin_transaction.go @@ -49,7 +49,7 @@ func decodeBitcoinTranscation(d *decode.D) any { d.FieldU32("version") witness := false - if d.PeekBits(8) == 0 { + if d.PeekUintBits(8) == 0 { witness = true d.FieldU8("marker") d.FieldU8("flag") diff --git a/format/bzip2/bzip2.go b/format/bzip2/bzip2.go index 793d44f30..1c790a56e 100644 --- a/format/bzip2/bzip2.go +++ b/format/bzip2/bzip2.go @@ -127,7 +127,7 @@ func bzip2Decode(d *decode.D) any { compressedSize := (readCompressedSize - compressedStart) - footerByteSize*8 for i := 0; i < 8; i++ { d.SeekAbs(compressedStart + compressedSize) - if d.PeekBits(48) == footerMagic { + if d.PeekUintBits(48) == footerMagic { break } compressedSize-- diff --git a/format/cbor/cbor.go b/format/cbor/cbor.go index 6e0db70b7..afe5a9221 100644 --- a/format/cbor/cbor.go +++ b/format/cbor/cbor.go @@ -124,7 +124,7 @@ func decodeCBORValue(d *decode.D) any { if shortCount == shortCountIndefinite { bb := &bytes.Buffer{} d.FieldArray("items", func(d *decode.D) { - for d.PeekBits(8) != breakMarker { + for d.PeekUintBits(8) != breakMarker { d.FieldStruct("item", func(d *decode.D) { v := decodeCBORValue(d) switch v := v.(type) { @@ -149,7 +149,7 @@ func decodeCBORValue(d *decode.D) any { if shortCount == shortCountIndefinite { sb := &strings.Builder{} d.FieldArray("items", func(d *decode.D) { - for d.PeekBits(8) != breakMarker { + for d.PeekUintBits(8) != breakMarker { d.FieldStruct("item", func(d *decode.D) { v := decodeCBORValue(d) switch v := v.(type) { @@ -171,7 +171,7 @@ func decodeCBORValue(d *decode.D) any { majorTypeArray: {s: scalar.Uint{Sym: "array"}, d: func(d *decode.D, shortCount uint64, count uint64) any { d.FieldArray("elements", func(d *decode.D) { for i := uint64(0); true; i++ { - if shortCount == shortCountIndefinite && d.PeekBits(8) == breakMarker { + if shortCount == shortCountIndefinite && d.PeekUintBits(8) == breakMarker { break } else if i >= count { break @@ -187,7 +187,7 @@ func decodeCBORValue(d *decode.D) any { majorTypeMap: {s: scalar.Uint{Sym: "map"}, d: func(d *decode.D, shortCount uint64, count uint64) any { d.FieldArray("pairs", func(d *decode.D) { for i := uint64(0); true; i++ { - if shortCount == shortCountIndefinite && d.PeekBits(8) == breakMarker { + if shortCount == shortCountIndefinite && d.PeekUintBits(8) == breakMarker { break } else if i >= count { break diff --git a/format/dns/dns.go b/format/dns/dns.go index c78cf8768..3570f2326 100644 --- a/format/dns/dns.go +++ b/format/dns/dns.go @@ -141,7 +141,7 @@ func fieldDecodeLabel(d *decode.D, pointerOffset int64, name string) { seenTermintor := false for !seenTermintor { d.FieldStruct("label", func(d *decode.D) { - if d.PeekBits(2) == 0b11 { + if d.PeekUintBits(2) == 0b11 { d.FieldU2("is_pointer") pointer := d.FieldU14("pointer") if endPos == 0 { diff --git a/format/gif/gif.go b/format/gif/gif.go index 6d1f50aed..7260fe38b 100644 --- a/format/gif/gif.go +++ b/format/gif/gif.go @@ -72,7 +72,7 @@ func gifDecode(d *decode.D) any { d.FieldArray("blocks", func(d *decode.D) { blocks: for { - switch d.PeekBits(8) { + switch d.PeekUintBits(8) { case ';': break blocks case '!': /* "!" */ @@ -89,7 +89,7 @@ func gifDecode(d *decode.D) any { d.FieldStruct("func_data_byte", func(d *decode.D) { byteCount := d.FieldU8("byte_count") b := d.FieldRawLen("data", int64(byteCount*8)) - if d.PeekBits(8) == 0 { + if d.PeekUintBits(8) == 0 { d.FieldU8("terminator") seenTerminator = true } @@ -135,7 +135,7 @@ func gifDecode(d *decode.D) any { d.FieldStruct("func_data_byte", func(d *decode.D) { byteCount := d.FieldU8("byte_count") d.FieldRawLen("data", int64(byteCount*8)) - if d.PeekBits(8) == 0 { + if d.PeekUintBits(8) == 0 { d.FieldU8("terminator") seenTerminator = true } diff --git a/format/id3/id3v1.go b/format/id3/id3v1.go index 72dd19dfe..1bae6b604 100644 --- a/format/id3/id3v1.go +++ b/format/id3/id3v1.go @@ -21,7 +21,7 @@ func init() { func id3v1Decode(d *decode.D) any { d.AssertAtLeastBitsLeft(128 * 8) d.FieldUTF8("magic", 3, d.StrAssert("TAG")) - if d.PeekBits(8) == uint64('+') { + if d.PeekUintBits(8) == uint64('+') { d.Errorf("looks like id3v11") } d.FieldUTF8NullFixedLen("song_name", 30) diff --git a/format/id3/id3v2.go b/format/id3/id3v2.go index 286a68c84..33af79848 100644 --- a/format/id3/id3v2.go +++ b/format/id3/id3v2.go @@ -315,7 +315,7 @@ func textNullLenFn(encoding int, notFoundFixedBytes int) func(d *decode.D) strin d.SeekRel(nullLen * 8) // seems sometimes utf16 etc has one exta null byte - if nullLen > 1 && d.PeekBits(8) == 0 { + if nullLen > 1 && d.PeekUintBits(8) == 0 { d.SeekRel(8) } @@ -592,7 +592,7 @@ func decodeFrame(d *decode.D, version int) uint64 { func decodeFrames(d *decode.D, version int, size uint64) { d.FieldArray("frames", func(d *decode.D) { for size > 0 { - if d.PeekBits(8) == 0 { + if d.PeekUintBits(8) == 0 { return } diff --git a/format/jpeg/jpeg.go b/format/jpeg/jpeg.go index c7bfad667..a49eb8f45 100644 --- a/format/jpeg/jpeg.go +++ b/format/jpeg/jpeg.go @@ -180,7 +180,7 @@ func jpegDecode(d *decode.D) any { if inECD { ecdLen := int64(0) for { - if d.PeekBits(8) == 0xff && d.PeekBits(16) != 0xff00 { + if d.PeekUintBits(8) == 0xff && d.PeekUintBits(16) != 0xff00 { break } d.SeekRel(8) diff --git a/format/matroska/matroska.go b/format/matroska/matroska.go index c05cfb701..28a528fa3 100644 --- a/format/matroska/matroska.go +++ b/format/matroska/matroska.go @@ -445,7 +445,7 @@ func matroskaDecode(d *decode.D) any { d.ArgAs(&mi) ebmlHeaderID := uint64(0x1a45dfa3) - if d.PeekBits(32) != ebmlHeaderID { + if d.PeekUintBits(32) != ebmlHeaderID { d.Errorf("no EBML header found") } dc := &decodeContext{tracks: []*track{}} diff --git a/format/mp4/boxes.go b/format/mp4/boxes.go index ef4c84fc8..2544a50b6 100644 --- a/format/mp4/boxes.go +++ b/format/mp4/boxes.go @@ -295,7 +295,7 @@ func decodeBoxesWithParentData(ctx *decodeContext, d *decode.D, parentData any, if d.BitsLeft() > 0 { // "Some sample descriptions terminate with four zero bytes that are not otherwise indicated." - if d.BitsLeft() >= 32 && d.PeekBits(32) == 0 { + if d.BitsLeft() >= 32 && d.PeekUintBits(32) == 0 { d.FieldU32("zero_terminator") } if d.BitsLeft() > 0 { @@ -904,7 +904,7 @@ func decodeBox(ctx *decodeContext, d *decode.D, typ string) { decodeBoxes(ctx, d) case "meta": // TODO: meta box sometimes has a 4 byte unknown field? (flag/version?) - maybeFlags := d.PeekBits(32) + maybeFlags := d.PeekUintBits(32) if maybeFlags == 0 { // TODO: rename? d.FieldU32("maybe_flags") @@ -1687,7 +1687,7 @@ func decodeBox(ctx *decodeContext, d *decode.D, typ string) { // TODO: better probe? ffmpeg uses box name heuristics? // if 16 length field seems to match assume box with length, language and value // otherwise decode as box with value rest of box - probeLength := d.PeekBits(16) + probeLength := d.PeekUintBits(16) // +2 for length field, +2 for language field if (probeLength+2+2)*8 == uint64(d.BitsLeft()) { length := d.FieldU16("length") diff --git a/format/mpeg/avc_pps.go b/format/mpeg/avc_pps.go index c0466a9fc..f1a96ff2e 100644 --- a/format/mpeg/avc_pps.go +++ b/format/mpeg/avc_pps.go @@ -17,7 +17,7 @@ func init() { func moreRBSPData(d *decode.D) bool { l := d.BitsLeft() - return l >= 8 && d.PeekBits(8) != 0b1000_0000 + return l >= 8 && d.PeekUintBits(8) != 0b1000_0000 } func avcPPSDecode(d *decode.D) any { diff --git a/format/mpeg/mpeg_pes.go b/format/mpeg/mpeg_pes.go index a1280aa64..5c0882927 100644 --- a/format/mpeg/mpeg_pes.go +++ b/format/mpeg/mpeg_pes.go @@ -36,7 +36,7 @@ type subStream struct { func pesDecode(d *decode.D) any { substreams := map[int]*subStream{} - prefix := d.PeekBits(24) + prefix := d.PeekUintBits(24) if prefix != 0b0000_0000_0000_0000_0000_0001 { d.Errorf("no pes prefix found") } diff --git a/format/mpeg/mpeg_pes_packet.go b/format/mpeg/mpeg_pes_packet.go index e5f1e8d12..54a56f6e2 100644 --- a/format/mpeg/mpeg_pes_packet.go +++ b/format/mpeg/mpeg_pes_packet.go @@ -97,7 +97,7 @@ func pesPacketDecode(d *decode.D) any { } case startCode == packHeader: - isMPEG2 := d.PeekBits(2) == 0b01 + isMPEG2 := d.PeekUintBits(2) == 0b01 if isMPEG2 { d.FieldU2("marker_bits0", mpegVersion) } else { @@ -140,7 +140,7 @@ func pesPacketDecode(d *decode.D) any { d.FieldU1("packet_rate_restriction_flag") d.FieldU7("reserved") d.FieldArray("stream_bound_entries", func(d *decode.D) { - for d.PeekBits(1) == 1 { + for d.PeekUintBits(1) == 1 { d.FieldStruct("stream_bound_entry", func(d *decode.D) { d.FieldU8("stream_id") d.FieldU2("skip0") diff --git a/format/mpeg/mpeg_spu.go b/format/mpeg/mpeg_spu.go index 162315151..13ed8d3cd 100644 --- a/format/mpeg/mpeg_spu.go +++ b/format/mpeg/mpeg_spu.go @@ -48,7 +48,7 @@ var commandNames = scalar.UintMapSymStr{ } func rleValue(d *decode.D) (uint64, uint64, int) { - p := uint(d.PeekBits(8)) + p := uint(d.PeekUintBits(8)) // match zero prefix switch { diff --git a/format/riff/aiff.go b/format/riff/aiff.go index e44306693..72bdcf8be 100644 --- a/format/riff/aiff.go +++ b/format/riff/aiff.go @@ -4,7 +4,6 @@ package riff import ( "github.com/wader/fq/format" - "github.com/wader/fq/internal/mathex" "github.com/wader/fq/pkg/decode" "github.com/wader/fq/pkg/interp" "github.com/wader/fq/pkg/scalar" @@ -81,9 +80,7 @@ func aiffDecode(d *decode.D) any { d.FieldU32("num_sample_frames") d.FieldU16("sample_size") // TODO: support big float? - d.FieldFltFn("sample_rate", func(d *decode.D) float64 { - return mathex.NewFloat80FromBytes(d.BytesLen(10)).Float64() - }) + d.FieldF80("sample_rate") return false, nil case "SSND": d.FieldU32("offset") diff --git a/format/rtmp/amf0.go b/format/rtmp/amf0.go index 3394868af..d3dd4c57a 100644 --- a/format/rtmp/amf0.go +++ b/format/rtmp/amf0.go @@ -77,7 +77,7 @@ func amf0DecodeValue(d *decode.D) { l := d.FieldU16("length") d.FieldUTF8("value", int(l)) }) - typ = d.PeekBits(8) + typ = d.PeekUintBits(8) d.FieldStruct("value", amf0DecodeValue) }) } @@ -98,7 +98,7 @@ func amf0DecodeValue(d *decode.D) { l := d.FieldU16("length") d.FieldUTF8("value", int(l)) }) - typ = d.PeekBits(8) + typ = d.PeekUintBits(8) d.FieldStruct("value", amf0DecodeValue) }) } @@ -134,7 +134,7 @@ func amf0DecodeValue(d *decode.D) { l := d.FieldU16("length") d.FieldUTF8("value", int(l)) }) - typ = d.PeekBits(8) + typ = d.PeekUintBits(8) d.FieldStruct("value", amf0DecodeValue) }) } diff --git a/format/rtmp/rtmp.go b/format/rtmp/rtmp.go index 61cea7bf3..99bbc5dbc 100644 --- a/format/rtmp/rtmp.go +++ b/format/rtmp/rtmp.go @@ -368,7 +368,7 @@ func rtmpDecode(d *decode.D) any { var chunkSteamID uint64 fmt := d.FieldU2("fmt") - switch d.PeekBits(6) { + switch d.PeekUintBits(6) { case 0: // 64-319: 2 byte d.FieldU6("chunk_stream_id_prefix") diff --git a/format/tls/tls.go b/format/tls/tls.go index 9477719fc..32793a0f2 100644 --- a/format/tls/tls.go +++ b/format/tls/tls.go @@ -695,7 +695,7 @@ func decodeTLS(d *decode.D) any { tc.server.currentCipherSuit = ciphersuites.TLS_NULL_WITH_NULL_NULL tc.server.nextCipherSuit = ciphersuites.TLS_NULL_WITH_NULL_NULL - firstByte := d.PeekBits(8) + firstByte := d.PeekUintBits(8) if firstByte&0x80 != 0 { d.FieldStruct("ssl_v2", func(d *decode.D) { decodeV2ClientHello(d, tc) diff --git a/pkg/decode/decode.go b/pkg/decode/decode.go index 4e710ba9b..110359be1 100644 --- a/pkg/decode/decode.go +++ b/pkg/decode/decode.go @@ -306,7 +306,7 @@ func (d *D) SharedReadBuf(n int) []byte { if len(*d.readBuf) < n { *d.readBuf = make([]byte, n) } - return *d.readBuf + return (*d.readBuf)[:n] } func (d *D) FillGaps(r ranges.Range, namePrefix string) { @@ -370,14 +370,35 @@ func (d *D) IOPanic(err error, op string) { panic(IOError{Err: err, Pos: d.Pos(), Op: op}) } +// TryBits reads nBits bits from buffer +func (d *D) TryBits(nBits int) ([]byte, error) { + if nBits < 0 { + return nil, fmt.Errorf("nBits must be >= 0 (%d)", nBits) + } + buf := d.SharedReadBuf(int(bitio.BitsByteCount(int64(nBits)))) + _, err := bitio.ReadFull(d.bitBuf, buf, int64(nBits)) + if err != nil { + return nil, err + } + + return buf[:], nil +} + // Bits reads nBits bits from buffer -func (d *D) TryBits(nBits int) (uint64, error) { +func (d *D) Bits(nBits int) []byte { + b, err := d.TryBits(nBits) + if err != nil { + panic(IOError{Err: err, Op: "Bits", ReadSize: int64(nBits), Pos: d.Pos()}) + } + return b +} + +// TryUintBits reads nBits bits as a uint64 from buffer +func (d *D) TryUintBits(nBits int) (uint64, error) { if nBits < 0 || nBits > 64 { return 0, fmt.Errorf("nBits must be 0-64 (%d)", nBits) } - // 64 bits max, 9 byte worse case if not byte aligned - buf := d.SharedReadBuf(9) - _, err := bitio.ReadFull(d.bitBuf, buf, int64(nBits)) // TODO: int64? + buf, err := d.TryBits(nBits) if err != nil { return 0, err } @@ -385,19 +406,19 @@ func (d *D) TryBits(nBits int) (uint64, error) { return bitio.Read64(buf[:], 0, int64(nBits)), nil // TODO: int64 } -// Bits reads nBits bits from buffer -func (d *D) Bits(nBits int) uint64 { - n, err := d.TryBits(nBits) +// UintBits reads nBits bits as uint64 from buffer +func (d *D) UintBits(nBits int) uint64 { + n, err := d.TryUintBits(nBits) if err != nil { - panic(IOError{Err: err, Op: "Bits", ReadSize: int64(nBits), Pos: d.Pos()}) + panic(IOError{Err: err, Op: "UintBits", ReadSize: int64(nBits), Pos: d.Pos()}) } return n } -func (d *D) PeekBits(nBits int) uint64 { +func (d *D) PeekUintBits(nBits int) uint64 { n, err := d.TryPeekBits(nBits) if err != nil { - panic(IOError{Err: err, Op: "PeekBits", ReadSize: int64(nBits), Pos: d.Pos()}) + panic(IOError{Err: err, Op: "PeekUintBits", ReadSize: int64(nBits), Pos: d.Pos()}) } return n } @@ -450,7 +471,7 @@ func (d *D) TryPeekBits(nBits int) (uint64, error) { if err != nil { return 0, err } - n, err := d.TryBits(nBits) + n, err := d.TryUintBits(nBits) if _, err := d.bitBuf.SeekBits(start, io.SeekStart); err != nil { return 0, err } diff --git a/pkg/decode/decode_gen.go b/pkg/decode/decode_gen.go index 0fc8fd88d..a20e433e2 100644 --- a/pkg/decode/decode_gen.go +++ b/pkg/decode/decode_gen.go @@ -18260,6 +18260,52 @@ func (d *D) FieldF64(name string, sms ...scalar.FltMapper) float64 { return d.FieldScalarF64(name, sms...).Actual } +// Reader F80 + +// TryF80 tries to read 80 bit IEEE 754 float in current endian +func (d *D) TryF80() (float64, error) { return d.tryFEndian(80, d.Endian) } + +// F80 reads 80 bit IEEE 754 float in current endian +func (d *D) F80() float64 { + v, err := d.tryFEndian(80, d.Endian) + if err != nil { + panic(IOError{Err: err, Op: "F80", Pos: d.Pos()}) + } + return v +} + +// TryFieldScalarF80 tries to add a field and read 80 bit IEEE 754 float in current endian +func (d *D) TryFieldScalarF80(name string, sms ...scalar.FltMapper) (*scalar.Flt, error) { + s, err := d.TryFieldScalarFltFn(name, func(d *D) (scalar.Flt, error) { + v, err := d.tryFEndian(80, d.Endian) + return scalar.Flt{Actual: v}, err + }, sms...) + if err != nil { + return nil, err + } + return s, err +} + +// FieldScalarF80 adds a field and reads 80 bit IEEE 754 float in current endian +func (d *D) FieldScalarF80(name string, sms ...scalar.FltMapper) *scalar.Flt { + s, err := d.TryFieldScalarF80(name, sms...) + if err != nil { + panic(IOError{Err: err, Name: name, Op: "F80", Pos: d.Pos()}) + } + return s +} + +// TryFieldF80 tries to add a field and read 80 bit IEEE 754 float in current endian +func (d *D) TryFieldF80(name string, sms ...scalar.FltMapper) (float64, error) { + s, err := d.TryFieldScalarF80(name, sms...) + return s.Actual, err +} + +// FieldF80 adds a field and reads 80 bit IEEE 754 float in current endian +func (d *D) FieldF80(name string, sms ...scalar.FltMapper) float64 { + return d.FieldScalarF80(name, sms...).Actual +} + // Reader F16LE // TryF16LE tries to read 16 bit IEEE 754 float in little-endian @@ -18398,6 +18444,52 @@ func (d *D) FieldF64LE(name string, sms ...scalar.FltMapper) float64 { return d.FieldScalarF64LE(name, sms...).Actual } +// Reader F80LE + +// TryF80LE tries to read 80 bit IEEE 754 float in little-endian +func (d *D) TryF80LE() (float64, error) { return d.tryFEndian(80, LittleEndian) } + +// F80LE reads 80 bit IEEE 754 float in little-endian +func (d *D) F80LE() float64 { + v, err := d.tryFEndian(80, LittleEndian) + if err != nil { + panic(IOError{Err: err, Op: "F80LE", Pos: d.Pos()}) + } + return v +} + +// TryFieldScalarF80LE tries to add a field and read 80 bit IEEE 754 float in little-endian +func (d *D) TryFieldScalarF80LE(name string, sms ...scalar.FltMapper) (*scalar.Flt, error) { + s, err := d.TryFieldScalarFltFn(name, func(d *D) (scalar.Flt, error) { + v, err := d.tryFEndian(80, LittleEndian) + return scalar.Flt{Actual: v}, err + }, sms...) + if err != nil { + return nil, err + } + return s, err +} + +// FieldScalarF80LE adds a field and reads 80 bit IEEE 754 float in little-endian +func (d *D) FieldScalarF80LE(name string, sms ...scalar.FltMapper) *scalar.Flt { + s, err := d.TryFieldScalarF80LE(name, sms...) + if err != nil { + panic(IOError{Err: err, Name: name, Op: "F80LE", Pos: d.Pos()}) + } + return s +} + +// TryFieldF80LE tries to add a field and read 80 bit IEEE 754 float in little-endian +func (d *D) TryFieldF80LE(name string, sms ...scalar.FltMapper) (float64, error) { + s, err := d.TryFieldScalarF80LE(name, sms...) + return s.Actual, err +} + +// FieldF80LE adds a field and reads 80 bit IEEE 754 float in little-endian +func (d *D) FieldF80LE(name string, sms ...scalar.FltMapper) float64 { + return d.FieldScalarF80LE(name, sms...).Actual +} + // Reader F16BE // TryF16BE tries to read 16 bit IEEE 754 float in big-endian @@ -18536,6 +18628,52 @@ func (d *D) FieldF64BE(name string, sms ...scalar.FltMapper) float64 { return d.FieldScalarF64BE(name, sms...).Actual } +// Reader F80BE + +// TryF80BE tries to read 80 bit IEEE 754 float in big-endian +func (d *D) TryF80BE() (float64, error) { return d.tryFEndian(80, BigEndian) } + +// F80BE reads 80 bit IEEE 754 float in big-endian +func (d *D) F80BE() float64 { + v, err := d.tryFEndian(80, BigEndian) + if err != nil { + panic(IOError{Err: err, Op: "F80BE", Pos: d.Pos()}) + } + return v +} + +// TryFieldScalarF80BE tries to add a field and read 80 bit IEEE 754 float in big-endian +func (d *D) TryFieldScalarF80BE(name string, sms ...scalar.FltMapper) (*scalar.Flt, error) { + s, err := d.TryFieldScalarFltFn(name, func(d *D) (scalar.Flt, error) { + v, err := d.tryFEndian(80, BigEndian) + return scalar.Flt{Actual: v}, err + }, sms...) + if err != nil { + return nil, err + } + return s, err +} + +// FieldScalarF80BE adds a field and reads 80 bit IEEE 754 float in big-endian +func (d *D) FieldScalarF80BE(name string, sms ...scalar.FltMapper) *scalar.Flt { + s, err := d.TryFieldScalarF80BE(name, sms...) + if err != nil { + panic(IOError{Err: err, Name: name, Op: "F80BE", Pos: d.Pos()}) + } + return s +} + +// TryFieldF80BE tries to add a field and read 80 bit IEEE 754 float in big-endian +func (d *D) TryFieldF80BE(name string, sms ...scalar.FltMapper) (float64, error) { + s, err := d.TryFieldScalarF80BE(name, sms...) + return s.Actual, err +} + +// FieldF80BE adds a field and reads 80 bit IEEE 754 float in big-endian +func (d *D) FieldF80BE(name string, sms ...scalar.FltMapper) float64 { + return d.FieldScalarF80BE(name, sms...).Actual +} + // Reader FP // TryFP tries to read nBits fixed-point number in current endian diff --git a/pkg/decode/read.go b/pkg/decode/read.go index 13fb5804f..72144467e 100644 --- a/pkg/decode/read.go +++ b/pkg/decode/read.go @@ -2,6 +2,7 @@ package decode import ( "bytes" + "encoding/binary" "fmt" "math" "math/big" @@ -20,7 +21,7 @@ func (d *D) tryUEndian(nBits int, endian Endian) (uint64, error) { if nBits < 0 { return 0, fmt.Errorf("tryUEndian nBits must be >= 0 (%d)", nBits) } - n, err := d.TryBits(nBits) + n, err := d.TryUintBits(nBits) if err != nil { return 0, err } @@ -88,20 +89,22 @@ func (d *D) tryFEndian(nBits int, endian Endian) (float64, error) { if nBits < 0 { return 0, fmt.Errorf("tryFEndian nBits must be >= 0 (%d)", nBits) } - n, err := d.TryBits(nBits) + b, err := d.TryBits(nBits) if err != nil { return 0, err } if endian == LittleEndian { - n = bitio.ReverseBytes64(nBits, n) + ReverseBytes(b) } switch nBits { case 16: - return float64(mathex.Float16(uint16(n)).Float32()), nil + return float64(mathex.Float16(binary.BigEndian.Uint16(b)).Float32()), nil case 32: - return float64(math.Float32frombits(uint32(n))), nil + return float64(math.Float32frombits(binary.BigEndian.Uint32(b))), nil case 64: - return math.Float64frombits(n), nil + return math.Float64frombits(binary.BigEndian.Uint64(b)), nil + case 80: + return mathex.NewFloat80FromBytes(b).Float64(), nil default: return 0, fmt.Errorf("unsupported float size %d", nBits) } @@ -111,7 +114,7 @@ func (d *D) tryFPEndian(nBits int, fBits int, endian Endian) (float64, error) { if nBits < 0 { return 0, fmt.Errorf("tryFPEndian nBits must be >= 0 (%d)", nBits) } - n, err := d.TryBits(nBits) + n, err := d.TryUintBits(nBits) if err != nil { return 0, err } @@ -160,7 +163,7 @@ func (d *D) tryTextLenPrefixed(lenBits int, fixedBytes int, e encoding.Encoding) } p := d.Pos() - l, err := d.TryBits(lenBits) + l, err := d.TryUintBits(lenBits) if err != nil { return "", err } @@ -228,7 +231,7 @@ func (d *D) tryUnary(ov uint64) (uint64, error) { p := d.Pos() var n uint64 for { - b, err := d.TryBits(1) + b, err := d.TryUintBits(1) if err != nil { d.SeekAbs(p) return 0, err @@ -242,7 +245,7 @@ func (d *D) tryUnary(ov uint64) (uint64, error) { } func (d *D) tryBool() (bool, error) { - n, err := d.TryBits(1) + n, err := d.TryUintBits(1) if err != nil { return false, err } diff --git a/pkg/decode/types.json b/pkg/decode/types.json index 8f29f4dc1..ddea96d64 100644 --- a/pkg/decode/types.json +++ b/pkg/decode/types.json @@ -290,6 +290,13 @@ "call" : "d.tryFEndian(64, d.Endian)" , "doc" : "64 bit IEEE 754 float in current endian" }, + { + "name" : "80" , + "args" : "" , + "params": "" , + "call" : "d.tryFEndian(80, d.Endian)" , + "doc" : "80 bit IEEE 754 float in current endian" + }, { "name" : "16LE" , "args" : "" , @@ -311,6 +318,13 @@ "call" : "d.tryFEndian(64, LittleEndian)" , "doc" : "64 bit IEEE 754 float in little-endian" }, + { + "name" : "80LE" , + "args" : "" , + "params": "" , + "call" : "d.tryFEndian(80, LittleEndian)" , + "doc" : "80 bit IEEE 754 float in little-endian" + }, { "name" : "16BE" , "args" : "" , @@ -331,6 +345,13 @@ "params": "" , "call" : "d.tryFEndian(64, BigEndian)" , "doc" : "64 bit IEEE 754 float in big-endian" + }, + { + "name" : "80BE" , + "args" : "" , + "params": "" , + "call" : "d.tryFEndian(80, BigEndian)" , + "doc" : "80 bit IEEE 754 float in big-endian" } ] },